diff --git a/DEPS b/DEPS
index 8fe41af4..2fb65e90 100644
--- a/DEPS
+++ b/DEPS
@@ -236,7 +236,7 @@
   #
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-amd64-generic-chrome-skylab
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-arm-generic-chrome-skylab
-  'lacros_sdk_version': '16022.0.0-1062744',
+  'lacros_sdk_version': '16023.0.0-1062828',
 
   # Generate location tag metadata to include in tests result data uploaded
   # to ResultDB. This isn't needed on some configs and the tool that generates
@@ -248,7 +248,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:1d383421736c86faeb7dea6d2039d8ea2ef6d648',
+  'luci_go': 'git_revision:1aca70b6bf116c1bd8fbf0526c9a89e9be308718',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -300,23 +300,23 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': '2161c6c29e26dbbdcb8ed215a548e202b89f5cd7',
+  'src_internal_revision': '619a026e7cb0711040338bb724d00e8420611336',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '1fa3a29e66bd220f33202be998ae0a883c749bd2',
+  'skia_revision': '7c2ab74e6d1b9c3017114a8d13a200a888fc5b10',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6c7cf27a322aa220c36e60faa79370cfbdcbcf5d',
+  'v8_revision': '9927247d821b1fefa9d225acee0d67f2cbdbfd0f',
   # 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': '67b3149f2cf0fe38cbdd7bf1c7b2ab8e7d95ebea',
+  'angle_revision': '53476d6ff2740267db0c0573644378621c4e7d78',
   # 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': '5561c71fa64e5f7f726f74f23a8aac5cc308d18a',
+  'swiftshader_revision': '8dd40811c5715061393f1b36999139ef0813c291',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -324,7 +324,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '01e1ae3687e391a076fe470471f096db1f6d6bb4',
+  'boringssl_revision': 'f10c1dc37174843c504a80e94c252e35b7b1eb61',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -352,7 +352,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '3008032062e2ce8549c26b42ae55c6e02439f27c',
+  'freetype_revision': '83af801b552111e37d9466a887e1783a0fb5f196',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -376,7 +376,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
-  'chromium_variations_revision': '7fd4b8625471752cff2ed65f7676900a15a3a2fe',
+  'chromium_variations_revision': '5117ddadfa9e6ef29d5eb03ab93e90fd506c0828',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -396,7 +396,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': '7e0f06a7936e95c3410f27cfaccbd94c7b5ff26c',
+  'devtools_frontend_revision': 'a058cb54ecbbb8630ccc3b959b209b20d7ad2fa8',
   # 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.
@@ -420,7 +420,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': '7d3a30e786c1c9bd61d24b21d7fdec5218ab280c',
+  'dawn_revision': '73d7f7ee1b320591b78dfbc35ceec83e6baea621',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -500,10 +500,10 @@
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
-  'libcxx_revision':       '7ef1f0a187aa3320426084c19e42833568f779a9',
+  'libcxx_revision':       '9be1056e883d3fe5cd6666ac69702a6c5e9a39df',
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:f792b9756418af8ab8a91a4c15b582431cb86ff9',
+  'gn_version': 'git_revision:20806f79c6b4ba295274e3a589d85db41a02fdaa',
 
   # ninja CIPD package.
   'ninja_package': 'infra/3pp/tools/ninja/',
@@ -1103,7 +1103,7 @@
   },
 
   'src/chrome/installer/mac/third_party/xz/xz': {
-      'url': Var('chromium_git') + '/chromium/deps/xz.git' + '@' + 'eecaf55632ca72e90eb2641376bce7cdbc7284f7',
+      'url': Var('chromium_git') + '/chromium/deps/xz.git' + '@' + '10d236393a338a55830db628356f022a91978b61',
       'condition': 'checkout_mac',
   },
 
@@ -1287,7 +1287,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '4720ec1e1fe6d7a9f35ea36cf45c1b9b19da4a2b',
+    'e5ba0da2a173ac40347c806053698ca2624857ea',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1742,7 +1742,7 @@
     Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + 'ca678952a9a8eaa6de112d154e8e104b22f9ab3f',
 
   'src/third_party/crc32c/src':
-    Var('chromium_git') + '/external/github.com/google/crc32c.git' + '@' + 'fa5ade41ee480003d9c5af6f43567ba22e4e17e6',
+    Var('chromium_git') + '/external/github.com/google/crc32c.git' + '@' + 'd3d60ac6e0f16780bcfcc825385e1d338801a558',
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
@@ -1760,13 +1760,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ae3745656b1111c995e41ec70eaa4397eaea7951',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '653e86a6f020e89e7f9249d40a22b25a8d6ba02a',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'b6c4c78e370aab6bd45dd39584cb49962687e8ac',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '7ae8cb30b21435841a28f345b03624cc31029418',
     'condition': 'checkout_src_internal',
   },
 
@@ -1967,7 +1967,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/jdk',
-              'version': 'sewpT0JmZAgFX_ZzmWhbYPmcPGeDa9os_4Q74ZFbo5sC',
+              'version': 'BXZwbslDFpYhPRuG8hBh2z7ApP36ZG-ZfkBWrkpnPl4C',
           },
       ],
       # Needed on Linux for use on chromium_presubmit (for checkstyle).
@@ -2252,7 +2252,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '6a4a99c3a7a42d98ea93990af32e4a69cfb39552',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'bea7f2f92cb9ecf6923ecea52120c312840494a0',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2406,7 +2406,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'EQKzOXcfxGc6pp0NyDCDBQYJ68PTOs19P4zEraID18kC',
+              'version': 'SfTjETaHqxbqyJ2oM5I95Iff9NJRgm9LHaDH03COwT0C',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2645,7 +2645,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'Lha0rEJ7GHU0Fil1gSD6dalZtxzX6uaFjpYvWih41WIC',
+          'version': 'FqgGUYCOqrRnp8FnQKKpTVCh2qW_G9ACEGWzbAxNqxwC',
         },
       ],
       'dep_type': 'cipd',
@@ -2677,7 +2677,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-arm64',
-          'version': 'Gt9vuY-MHU7Sm1HRXh-XGw7kzNXCTwMpt4LhVmc5I58C',
+          'version': 'bnOHfm8fLa2gZiirRaLqMN1SfJM2_XMMXzCTNDB8nmQC',
         },
       ],
       'dep_type': 'cipd',
@@ -2729,7 +2729,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '89jJxGdC3qmK1J1fp1ZNaY13kIdSvb9x7-v6olrmmMUC',
+        'version': 'e4qu68x_6WIyxoUnyH7pwI9DNinm9bt7o2V3xFvAbQ4C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2740,7 +2740,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'vz74_JlLvOje7YIj2eHCLzIk-XuLRrNGCjliqPYx2r4C',
+        'version': 'QrBhujKPik4umQtwcRIJKRkw9OrQDbH7kkRT7LeodBkC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4382,7 +4382,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '68b91da9d364b3e1c0af9b80156e674458b525ba',
+        'ec602e23d833ae149c27f173248ef9c6255442bc',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
index f8fca3ff..9df9ef61 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
@@ -40,7 +40,6 @@
 import org.chromium.android_webview.AwThreadUtils;
 import org.chromium.android_webview.AwTracingController;
 import org.chromium.android_webview.HttpAuthDatabase;
-import org.chromium.android_webview.ProductConfig;
 import org.chromium.android_webview.R;
 import org.chromium.android_webview.WebViewChromiumRunQueue;
 import org.chromium.android_webview.common.AwFeatures;
@@ -51,7 +50,6 @@
 import org.chromium.android_webview.variations.FastVariationsSeedSafeModeAction;
 import org.chromium.android_webview.variations.VariationsSeedLoader;
 import org.chromium.base.BuildInfo;
-import org.chromium.base.BundleUtils;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.FieldTrialList;
@@ -193,8 +191,6 @@
 
             ResourceBundle.setAvailablePakLocales(AwLocaleConfig.getWebViewSupportedPakLocales());
 
-            BundleUtils.setIsBundle(ProductConfig.IS_BUNDLE);
-
             // We are rewriting Java resources in the background.
             // NOTE: Any reference to Java resources will cause a crash.
 
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 7ed3bff..b78980d3 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -40,7 +40,6 @@
 import org.chromium.android_webview.AwContentsStatics;
 import org.chromium.android_webview.AwSettings;
 import org.chromium.android_webview.BrowserSafeModeActionList;
-import org.chromium.android_webview.ProductConfig;
 import org.chromium.android_webview.R;
 import org.chromium.android_webview.WebViewChromiumRunQueue;
 import org.chromium.android_webview.common.AwSwitches;
@@ -426,7 +425,7 @@
                     VersionConstants.PRODUCT_VERSION,
                     BuildConfig.VERSION_CODE,
                     BuildConfig.MIN_SDK_VERSION,
-                    ProductConfig.IS_BUNDLE,
+                    BuildConfig.IS_BUNDLE,
                     multiProcess,
                     packageId);
 
@@ -608,7 +607,7 @@
     }
 
     public static boolean preloadInZygote() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P && ProductConfig.IS_BUNDLE) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P && BuildConfig.IS_BUNDLE) {
             // Apply workaround if we're a bundle on O, where the split APK handling bug exists.
             SplitApkWorkaround.apply();
         }
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
index 4bcb585..34b7956 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
@@ -15,7 +15,6 @@
 import org.jni_zero.NativeMethods;
 
 import org.chromium.android_webview.AwLocaleConfig;
-import org.chromium.android_webview.ProductConfig;
 import org.chromium.android_webview.common.CommandLineUtil;
 import org.chromium.android_webview.common.PlatformServiceBridge;
 import org.chromium.android_webview.common.SafeModeController;
@@ -64,7 +63,7 @@
                 VersionConstants.PRODUCT_VERSION,
                 BuildConfig.VERSION_CODE,
                 BuildConfig.MIN_SDK_VERSION,
-                ProductConfig.IS_BUNDLE,
+                BuildConfig.IS_BUNDLE,
                 ContextUtils.getProcessName());
 
         ContextUtils.initApplicationContext(this);
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 7c4a4e60..c7bd886 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -5011,6 +5011,7 @@
     "display/mirror_window_test_api.h",
     "display/screen_orientation_controller_test_api.cc",
     "display/screen_orientation_controller_test_api.h",
+    "display/virtual_display_util_ash.cc",
     "drag_drop/drag_drop_controller_test_api.h",
     "drag_drop/draggable_test_view.cc",
     "drag_drop/draggable_test_view.h",
diff --git a/ash/birch/birch_coral_provider.cc b/ash/birch/birch_coral_provider.cc
index 37bee80..6ffdec2c 100644
--- a/ash/birch/birch_coral_provider.cc
+++ b/ash/birch/birch_coral_provider.cc
@@ -4,22 +4,105 @@
 
 #include "ash/birch/birch_coral_provider.h"
 
-#include "ash/birch/birch_model.h"
-#include "ash/public/cpp/coral_util.h"
+#include <variant>
+
 #include "ash/birch/birch_item.h"
+#include "ash/birch/birch_model.h"
 #include "ash/constants/ash_switches.h"
+#include "ash/public/cpp/app_types_util.h"
+#include "ash/public/cpp/coral_util.h"
+#include "ash/public/cpp/saved_desk_delegate.h"
 #include "ash/public/cpp/tab_cluster/tab_cluster_ui_controller.h"
 #include "ash/public/cpp/tab_cluster/tab_cluster_ui_item.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
+#include "ash/wm/desks/desks_util.h"
+#include "ash/wm/desks/templates/saved_desk_util.h"
+#include "ash/wm/mru_window_tracker.h"
 #include "base/command_line.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chromeos/ui/base/window_properties.h"
+#include "ui/wm/core/window_util.h"
 
+namespace ash {
 namespace {
+
 bool HasValidClusterCount(size_t num_clusters) {
   return num_clusters <= 2;
 }
-}  // namespace
 
-namespace ash {
+bool IsBrowserWindow(aura::Window* window) {
+  return window->GetProperty(chromeos::kAppTypeKey) ==
+         chromeos::AppType::BROWSER;
+}
+
+// Gets the data of the tabs opening on the active desk.
+std::vector<coral_util::TabData> GetInSessionTabData() {
+  // TODO(yulunwu, zxdan) add more tab metadata, app data,
+  // and handle in-session use cases.
+  std::vector<coral_util::TabData> tab_data;
+  for (const std::unique_ptr<TabClusterUIItem>& tab :
+       Shell::Get()->tab_cluster_ui_controller()->tab_items()) {
+    // Filter out the browser window which is not on the active desk.
+    if (!desks_util::BelongsToActiveDesk(tab->current_info().browser_window)) {
+      continue;
+    }
+
+    // Filter out non-browser tab info.
+    if (!IsBrowserWindow(tab->current_info().browser_window)) {
+      continue;
+    }
+
+    // TODO(http://b/363353433): filter out the tabs info from incognito window.
+
+    tab_data.push_back({.tab_title = tab->current_info().title,
+                        .source = tab->current_info().source});
+  }
+
+  return tab_data;
+}
+
+// Gets the data of the apps opening on the active desk.
+std::vector<coral_util::AppData> GetInSessionAppData() {
+  std::vector<coral_util::AppData> app_data;
+
+  auto* const shell = Shell::Get();
+  auto mru_windows =
+      shell->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
+  auto* delegate = shell->saved_desk_delegate();
+  for (aura::Window* window : mru_windows) {
+    // Skip transient windows.
+    if (wm::GetTransientParent(window)) {
+      continue;
+    }
+
+    // Skip browser windows.
+    if (IsBrowserWindow(window)) {
+      continue;
+    }
+
+    // We should guarantee the app can be launched in saved desk template.
+    if (!delegate->IsWindowSupportedForSavedDesk(window)) {
+      continue;
+    }
+
+    // Skip windows that do not associate with a full restore app id.
+    const std::string app_id = saved_desk_util::GetAppId(window);
+    if (app_id.empty()) {
+      continue;
+    }
+
+    const std::string* app_id_key = window->GetProperty(kAppIDKey);
+    app_data.push_back(
+        {.app_id = app_id,
+         .app_name = (!app_id_key || IsArcWindow(window))
+                         ? base::UTF16ToUTF8(window->GetTitle())
+                         : delegate->GetAppShortName(*app_id_key)});
+  }
+  return app_data;
+}
+
+}  // namespace
 
 BirchCoralProvider::BirchCoralProvider(BirchModel* birch_model)
     : birch_model_(birch_model) {
@@ -73,13 +156,14 @@
   // TODO(yulunwu, zxdan) add more tab metadata, app data,
   // and handle in-session use cases.
   std::vector<coral_util::ContentItem> active_tab_app_data;
-  for (const std::unique_ptr<TabClusterUIItem>& tab :
-       Shell::Get()->tab_cluster_ui_controller()->tab_items()) {
-    coral_util::ContentItem curr_tab =
-        coral_util::TabData{.tab_title = tab->current_info().title,
-                            .source = tab->current_info().source};
-    active_tab_app_data.emplace_back(std::move(curr_tab));
+  for (const auto& tab_data : GetInSessionTabData()) {
+    active_tab_app_data.push_back(tab_data);
   }
+
+  for (const auto& app_data : GetInSessionAppData()) {
+    active_tab_app_data.push_back(app_data);
+  }
+
   request_.set_content(std::move(active_tab_app_data));
 }
 
diff --git a/ash/birch/birch_coral_provider.h b/ash/birch/birch_coral_provider.h
index 9a1c9d1..d44be74 100644
--- a/ash/birch/birch_coral_provider.h
+++ b/ash/birch/birch_coral_provider.h
@@ -31,6 +31,8 @@
   // Called from birch model to request coral information to be displayed.
   void RequestBirchDataFetch() override;
 
+  const coral_util::CoralRequest& request_for_test() const { return request_; }
+
  private:
   // Whether we should handle post-login or in-session data.
   bool HasValidPostLoginData() const;
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index f3ac574..51f15d2 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -256,8 +256,11 @@
              "CrosBatterySaverAlwaysOn",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enable the use of biometric authentication for showing passwords in password manager or via autofil.
-BASE_FEATURE(kBiometricsInPasswordManager, "BiometricsInPasswordManager", base::FEATURE_DISABLED_BY_DEFAULT);
+// Enable the use of biometric authentication for showing passwords in password
+// manager or via autofil.
+BASE_FEATURE(kBiometricsInPasswordManager,
+             "BiometricsInPasswordManager",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Display coral information in birch UI.
 BASE_FEATURE(kBirchCoral, "BirchCoral", base::FEATURE_DISABLED_BY_DEFAULT);
@@ -3600,7 +3603,8 @@
 }
 
 bool IsBiometricsInPasswordManagerEnabled() {
-  return base::FeatureList::IsEnabled(kBiometricsInPasswordManager) && IsUseAuthPanelInSessionEnabled();
+  return base::FeatureList::IsEnabled(kBiometricsInPasswordManager) &&
+         IsUseAuthPanelInSessionEnabled();
 }
 
 bool IsBirchCoralEnabled() {
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 6d72fe5..aedda02 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -74,7 +74,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kAutozoomNudgeSessionReset);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBatterySaver);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBiometricsInPasswordManager);
+COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kBiometricsInPasswordManager);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBirchCoral);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBirchWeather);
 COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 362ff34..4125b5f 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -65,6 +65,7 @@
 #include "ui/display/manager/util/display_manager_util.h"
 #include "ui/display/screen.h"
 #include "ui/display/test/display_manager_test_api.h"
+#include "ui/display/test/virtual_display_util.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/display/util/display_util.h"
 #include "ui/events/devices/touchscreen_device.h"
@@ -5482,4 +5483,73 @@
   UpdateDisplay("800x600,800x600");
 }
 
+// Tests adding a display via the VirtualDisplayUtil interface.
+// This test should roughly match other platforms, i.e.
+// //ui/display/linux/test/virtual_display_util_linux_interactive_uitest.cc
+// TODO(crbug.com/40271794): Consolidate testing of VirtualDisplayUtil.
+TEST_F(DisplayManagerTest, VirtualDisplayUtilAddDisplay) {
+  const display::Screen* screen = display::Screen::GetScreen();
+  std::unique_ptr<display::test::VirtualDisplayUtil> virtual_display_util =
+      std::make_unique<display::test::DisplayManagerTestApi>(display_manager());
+  int initial_display_count = screen->GetNumDisplays();
+  int64_t display_id = virtual_display_util->AddDisplay(
+      2, display::test::VirtualDisplayUtil::k1920x1080);
+  EXPECT_NE(display_id, display::kInvalidDisplayId);
+  EXPECT_EQ(screen->GetNumDisplays(), initial_display_count + 1);
+  display::Display d;
+  EXPECT_TRUE(screen->GetDisplayWithDisplayId(display_id, &d));
+  EXPECT_EQ(d.size(), gfx::Size(1920, 1080));
+
+  // Expect failure when adding a duplicate index.
+  EXPECT_EQ(virtual_display_util->AddDisplay(
+                2, display::test::VirtualDisplayUtil::k1920x1080),
+            display::kInvalidDisplayId);
+
+  virtual_display_util->ResetDisplays();
+  EXPECT_FALSE(screen->GetDisplayWithDisplayId(display_id, &d));
+  EXPECT_EQ(screen->GetNumDisplays(), initial_display_count);
+}
+
+// Tests adding and removing displays via the VirtualDisplayUtil interface.
+// This test should roughly match other platforms, i.e.
+// TODO(crbug.com/40271794): Consolidate testing of VirtualDisplayUtil.
+TEST_F(DisplayManagerTest, VirtualDisplayUtilAddRemove) {
+  const display::Screen* screen = display::Screen::GetScreen();
+  std::unique_ptr<display::test::VirtualDisplayUtil> virtual_display_util =
+      std::make_unique<display::test::DisplayManagerTestApi>(display_manager());
+  int64_t display_id[3];
+  int initial_display_count = screen->GetNumDisplays();
+  display_id[0] = virtual_display_util->AddDisplay(
+      2, display::test::VirtualDisplayUtil::k1920x1080);
+  EXPECT_NE(display_id[0], display::kInvalidDisplayId);
+  display::Display d;
+  EXPECT_TRUE(screen->GetDisplayWithDisplayId(display_id[0], &d));
+
+  display_id[1] = virtual_display_util->AddDisplay(
+      3, display::test::VirtualDisplayUtil::k1024x768);
+  EXPECT_NE(display_id[1], display::kInvalidDisplayId);
+  EXPECT_TRUE(screen->GetDisplayWithDisplayId(display_id[1], &d));
+
+  display_id[2] = virtual_display_util->AddDisplay(
+      4, display::test::VirtualDisplayUtil::k1920x1080);
+  EXPECT_NE(display_id[2], display::kInvalidDisplayId);
+  EXPECT_TRUE(screen->GetDisplayWithDisplayId(display_id[2], &d));
+
+  EXPECT_EQ(screen->GetNumDisplays(), initial_display_count + 3);
+  virtual_display_util->RemoveDisplay(display_id[1]);
+  EXPECT_EQ(screen->GetNumDisplays(), initial_display_count + 2);
+  // Only virtual display 2 should no longer exist.
+  EXPECT_TRUE(screen->GetDisplayWithDisplayId(display_id[0], &d));
+  EXPECT_EQ(d.size(), gfx::Size(1920, 1080));
+  EXPECT_FALSE(screen->GetDisplayWithDisplayId(display_id[1], &d));
+  EXPECT_TRUE(screen->GetDisplayWithDisplayId(display_id[2], &d));
+  EXPECT_EQ(d.size(), gfx::Size(1920, 1080));
+
+  virtual_display_util->ResetDisplays();
+  EXPECT_FALSE(screen->GetDisplayWithDisplayId(display_id[0], &d));
+  EXPECT_FALSE(screen->GetDisplayWithDisplayId(display_id[1], &d));
+  EXPECT_FALSE(screen->GetDisplayWithDisplayId(display_id[2], &d));
+  EXPECT_EQ(screen->GetNumDisplays(), initial_display_count);
+}
+
 }  // namespace ash
diff --git a/ash/display/virtual_display_util_ash.cc b/ash/display/virtual_display_util_ash.cc
new file mode 100644
index 0000000..f7eb297
--- /dev/null
+++ b/ash/display/virtual_display_util_ash.cc
@@ -0,0 +1,19 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/shell.h"
+#include "ui/display/test/display_manager_test_api.h"
+#include "ui/display/test/virtual_display_util.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace display::test {
+
+// static
+std::unique_ptr<VirtualDisplayUtil> VirtualDisplayUtil::TryCreate(
+    Screen* screen) {
+  return std::make_unique<DisplayManagerTestApi>(
+      ash::Shell::Get()->display_manager());
+}
+
+}  // namespace display::test
diff --git a/ash/public/cpp/coral_util.h b/ash/public/cpp/coral_util.h
index 26c8d5c..1f0945d 100644
--- a/ash/public/cpp/coral_util.h
+++ b/ash/public/cpp/coral_util.h
@@ -17,6 +17,9 @@
 struct ASH_PUBLIC_EXPORT AppData {
   std::string app_id;
   std::string app_name;
+
+  // Enable the auto comparator.
+  auto operator<=>(const AppData&) const = default;
 };
 
 // TODO(zxdan) Look into additional metadata.
@@ -24,6 +27,9 @@
   std::string tab_title;
   // The url or source link of a tab.
   std::string source;
+
+  // Enable the auto comparator.
+  auto operator<=>(const TabData&) const = default;
 };
 
 using ContentItem = std::variant<AppData, TabData>;
@@ -45,6 +51,8 @@
     content_ = std::move(content);
   }
 
+  const std::vector<ContentItem>& content() const { return content_; }
+
  private:
   // Tab/app content with arbitrary ordering.
   std::vector<ContentItem> content_;
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
index 6d46c2f..06b6897 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
@@ -33,6 +33,7 @@
 #include "ui/events/event_handler.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/geometry/transform.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/public/cpp/message_center_constants.h"
@@ -398,14 +399,10 @@
 
 void ArcNotificationContentView::UpdateCornerRadius(float top_radius,
                                                     float bottom_radius) {
-  bool force_update =
-      top_radius_ != top_radius || bottom_radius_ != bottom_radius;
-
-  top_radius_ = top_radius;
-  bottom_radius_ = bottom_radius;
-
-  if (GetWidget() && GetNativeViewContainer()) {
-    UpdateMask(force_update);
+  contents_radii_ = gfx::RoundedCornersF(top_radius, top_radius, bottom_radius,
+                                         bottom_radius);
+  if (GetWidget()) {
+    SetCornerRadii(contents_radii_);
   }
 }
 
@@ -564,8 +561,6 @@
 
   // (Re-)create the floating buttons after |surface_| is attached to a widget.
   MaybeCreateFloatingControlButtons();
-
-  UpdateMask(false /* force_update */);
 }
 
 void ArcNotificationContentView::SetVisible(bool visible) {
@@ -604,8 +599,7 @@
   surface_copy_->root()->SetBounds(size);
   layer()->Add(surface_copy_->root());
 
-  surface_copy_->root()->SetRoundedCornerRadius(
-      {top_radius_, top_radius_, bottom_radius_, bottom_radius_});
+  surface_copy_->root()->SetRoundedCornerRadius(contents_radii_);
   surface_copy_->root()->SetIsFastRoundedCorner(true);
 
   // Changes the opacity instead of setting the visibility, to keep
@@ -620,34 +614,6 @@
   surface_->GetWindow()->layer()->SetOpacity(1.0f);
   DeprecatedLayoutImmediately();
   surface_copy_.reset();
-
-  // Re-install the mask since the custom mask is unset by
-  // |::wm::RecreateLayers()| in |ShowCopiedSurface()| method.
-  UpdateMask(true /* force_update */);
-}
-
-void ArcNotificationContentView::UpdateMask(bool force_update) {
-  if (top_radius_ == 0 && bottom_radius_ == 0) {
-    SetCustomMask(nullptr);
-    mask_insets_.reset();
-    return;
-  }
-
-  gfx::Insets new_insets = GetContentsBounds().InsetsFrom(GetVisibleBounds());
-  if (mask_insets_ == new_insets && !force_update)
-    return;
-  mask_insets_ = new_insets;
-
-  // The color of the mask, which is used only for corner-rounding, should be
-  // pure opaque white.
-  const SkColor mask_color = SK_ColorWHITE;
-  auto mask_painter =
-      std::make_unique<message_center::NotificationBackgroundPainter>(
-          top_radius_, bottom_radius_, mask_color);
-  // Set insets to round visible notification corners. https://crbug.com/866777
-  mask_painter->set_insets(new_insets);
-
-  SetCustomMask(views::Painter::CreatePaintedLayer(std::move(mask_painter)));
 }
 
 void ArcNotificationContentView::AddedToWidget() {
@@ -660,6 +626,8 @@
   // Hide the copied surface since it may be visible by OnWidgetClosing().
   if (surface_copy_)
     HideCopiedSurface();
+
+  SetCornerRadii(contents_radii_);
 }
 
 void ArcNotificationContentView::RemovedFromWidget() {
@@ -709,9 +677,6 @@
     // views::NativeViewHostAura::ShowWidget() and aura::Window::Show() which
     // DCHECKs the opacity of the window.
     LayoutSuperclass<views::NativeViewHost>(this);
-    // Reinstall mask to update rounded mask insets. Set null mask unless radius
-    // is set.
-    UpdateMask(false /* force_update */);
 
     // Scale notification surface if necessary.
     gfx::Transform transform;
@@ -752,11 +717,14 @@
 void ArcNotificationContentView::OnPaint(gfx::Canvas* canvas) {
   views::NativeViewHost::OnPaint(canvas);
 
-  SkScalar radii[8] = {top_radius_,    top_radius_,      // top-left
-                       top_radius_,    top_radius_,      // top-right
-                       bottom_radius_, bottom_radius_,   // bottom-right
-                       bottom_radius_, bottom_radius_};  // bottom-left
-
+  SkScalar radii[8] = {contents_radii_.upper_left(),
+                       contents_radii_.upper_left(),  // top-left
+                       contents_radii_.upper_right(),
+                       contents_radii_.upper_right(),  // top-right
+                       contents_radii_.lower_right(),
+                       contents_radii_.lower_right(),  // bottom-right
+                       contents_radii_.lower_left(),
+                       contents_radii_.lower_left()};  // bottom-left
   SkPath path;
   path.addRoundRect(gfx::RectToSkRect(GetLocalBounds()), radii,
                     SkPathDirection::kCCW);
@@ -813,9 +781,6 @@
 
 void ArcNotificationContentView::OnThemeChanged() {
   View::OnThemeChanged();
-  // OnThemeChanged may be called before container is set.
-  if (GetWidget() && GetNativeViewContainer())
-    UpdateMask(true);
 
   // Adjust control button color.
   control_buttons_view_.SetButtonIconColors(
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.h b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.h
index c44ba9e04..f460392 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.h
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.h
@@ -14,6 +14,7 @@
 #include "base/memory/raw_ptr.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/message_center/views/notification_background_painter.h"
 #include "ui/message_center/views/notification_control_buttons_view.h"
 #include "ui/views/controls/native/native_view_host.h"
@@ -101,9 +102,6 @@
   void ShowCopiedSurface();
   void HideCopiedSurface();
 
-  // Generates a mask using |top_radius_| and |bottom_radius_| and installs it.
-  void UpdateMask(bool force_update);
-
   // views::NativeViewHost
   void ViewHierarchyChanged(
       const views::ViewHierarchyChangedDetails& details) override;
@@ -210,12 +208,7 @@
   // If it's true, the surface gets active when attached to this view.
   bool activate_on_attach_ = false;
 
-  // Radiuses of rounded corners. These values are used in UpdateMask().
-  float top_radius_ = 0;
-  float bottom_radius_ = 0;
-
-  // Current insets of mask layer.
-  std::optional<gfx::Insets> mask_insets_;
+  gfx::RoundedCornersF contents_radii_;
 
   std::unique_ptr<ui::LayerTreeOwner> surface_copy_;
 };
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc
index cc84ff6..2948234 100644
--- a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc
@@ -40,6 +40,9 @@
 constexpr base::TimeDelta kCreateBondTimeout = base::Seconds(15);
 // Advertisement flag indicating BR/EDR support
 constexpr uint8_t kBrEdrNotSupportedFlag = 0x04;
+// Key-based Pairing Extended Response Flag indicating if the Provider is LE
+// only device
+constexpr uint8_t kLEOnly = 0x80;
 // Key-based Pairing Extended Response Flag indicating if the Provider prefers
 // LE bonding
 constexpr uint8_t kPrefersLEBonding = 0x40;
@@ -213,10 +216,11 @@
               base::BindOnce(&FastPairPairerImpl::OnCreateBondTimeout,
                              weak_ptr_factory_.GetWeakPtr()));
           // On Floss, always connect via classic unless device explicitly
-          // doesn't support BREDR
+          // doesn't support BREDR or indicates it prefers LE.
           if (floss::features::IsFlossEnabled() &&
               !(bt_device->GetAdvertisingDataFlags().value_or(0) &
-                kBrEdrNotSupportedFlag)) {
+                    kBrEdrNotSupportedFlag ||
+                pairing_flags & kLEOnly || pairing_flags & kPrefersLEBonding)) {
             bt_device->ConnectClassic(
                 /*pairing_delegate=*/this,
                 base::BindOnce(&FastPairPairerImpl::OnConnected,
@@ -264,10 +268,12 @@
       if (bt_device) {
         pairing_flow_ = FastPairPairingFlow::kPair;
         // On Floss, always connect via classic unless device explicitly
-        // doesn't support BREDR. ConnectClassic is equivalent to Pair.
+        // doesn't support BREDR or indicates it prefers LE. ConnectClassic is
+        // equivalent to Pair.
         if (floss::features::IsFlossEnabled() &&
             !(bt_device->GetAdvertisingDataFlags().value_or(0) &
-              kBrEdrNotSupportedFlag)) {
+                  kBrEdrNotSupportedFlag ||
+              pairing_flags & kLEOnly || pairing_flags & kPrefersLEBonding)) {
           bt_device->ConnectClassic(
               /*pairing_delegate=*/this,
               base::BindOnce(&FastPairPairerImpl::OnPairConnected,
@@ -311,9 +317,12 @@
     CD_LOG(INFO, Feature::FP) << __func__ << " on Floss";
 
     // Always connect via classic unless device explicitly
-    // doesn't support BREDR. ConnectClassic is equivalent to Pair.
+    // doesn't support BREDR or indicates it prefers LE. ConnectClassic is
+    // equivalent to Pair.
+    uint8_t pairing_flags = device_->key_based_pairing_flags().value_or(0);
     if (!(device->GetAdvertisingDataFlags().value_or(0) &
-          kBrEdrNotSupportedFlag)) {
+              kBrEdrNotSupportedFlag ||
+          pairing_flags & kLEOnly || pairing_flags & kPrefersLEBonding)) {
       device->ConnectClassic(
           /*pairing_delegate=*/this,
           base::BindOnce(&FastPairPairerImpl::OnPairConnected,
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc
index 795bfa2..8cab1b0 100644
--- a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc
@@ -167,6 +167,7 @@
       BluetoothDevice::PairingDelegate* pairing_delegate,
       base::OnceCallback<void(std::optional<ConnectErrorCode> error_code)>
           callback) override {
+    is_device_classic_paired = true;
     if (floss::features::IsFlossEnabled()) {
       // On Floss, ConnectClassic is equivalent to Pair
       Pair(pairing_delegate, std::move(callback));
@@ -193,6 +194,8 @@
 
   bool IsDevicePaired() { return is_device_paired_; }
 
+  bool IsDeviceClassicPaired() { return is_device_classic_paired; }
+
  protected:
   base::OnceCallback<void(std::optional<ConnectErrorCode> error_code)>
       pair_callback_;
@@ -202,6 +205,7 @@
   bool connect_failure_ = false;
   bool connect_timeout_ = false;
   bool is_device_paired_ = false;
+  bool is_device_classic_paired = false;
 };
 
 class FakeFastPairGattServiceClientImplFactory
@@ -387,6 +391,10 @@
 
   bool IsDevicePaired() { return fake_bluetooth_device_ptr_->IsDevicePaired(); }
 
+  bool IsDeviceClassicPaired() {
+    return fake_bluetooth_device_ptr_->IsDeviceClassicPaired();
+  }
+
   bool IsAccountKeySavedToFootprints() {
     return fast_pair_repository_->HasKeyForDevice(
         fake_bluetooth_device_ptr_->GetAddress());
@@ -654,6 +662,7 @@
   CreatePairer();
   fake_bluetooth_device_ptr_->TriggerPairCallback();
   EXPECT_EQ(GetPairFailure(), std::nullopt);
+  EXPECT_TRUE(IsDeviceClassicPaired());
   ExpectStepMetrics<FastPairProtocolPairingSteps>(
       kProtocolPairingStepInitial,
       {FastPairProtocolPairingSteps::kPairingStarted,
@@ -682,6 +691,7 @@
   CreatePairer();
   fake_bluetooth_device_ptr_->TriggerPairCallback();
   EXPECT_EQ(GetPairFailure(), std::nullopt);
+  EXPECT_FALSE(IsDeviceClassicPaired());
   ExpectStepMetrics<FastPairProtocolPairingSteps>(
       kProtocolPairingStepInitial,
       {FastPairProtocolPairingSteps::kPairingStarted,
diff --git a/ash/system/focus_mode/sounds/focus_mode_youtube_music_delegate.cc b/ash/system/focus_mode/sounds/focus_mode_youtube_music_delegate.cc
index 86bb7df..ec6a10e 100644
--- a/ash/system/focus_mode/sounds/focus_mode_youtube_music_delegate.cc
+++ b/ash/system/focus_mode/sounds/focus_mode_youtube_music_delegate.cc
@@ -62,7 +62,9 @@
   // list, and update the total number of API request to run.
   get_playlists_state_.done_callback = std::move(callback);
   const bool playlist_reserved =
-      get_playlists_state_.reserved_playlist_id.has_value();
+      get_playlists_state_.reserved_playlist_id.has_value() &&
+      get_playlists_state_.reserved_playlist_id.value() !=
+          kFocusSupermixPlaylistId;
   get_playlists_state_.target_count = playlist_reserved ? 3 : 2;
 
   // Invoke sub requests. Please note, sub request failures are more permissive
@@ -334,7 +336,7 @@
   }
 
   const std::vector<Playlist>& results = get_playlists_state_.GetTopPlaylists();
-  if (results.size() >= kFocusModePlaylistViewsNum) {
+  if (results.size() == kFocusModePlaylistViewsNum) {
     std::move(get_playlists_state_.done_callback).Run(results);
     get_playlists_state_.done_callback = base::NullCallback();
   }
diff --git a/ash/system/network/network_detailed_network_view_impl.cc b/ash/system/network/network_detailed_network_view_impl.cc
index 1640252..3f368aa 100644
--- a/ash/system/network/network_detailed_network_view_impl.cc
+++ b/ash/system/network/network_detailed_network_view_impl.cc
@@ -78,7 +78,8 @@
     case NetworkType::kCellular:
       [[fallthrough]];
     case NetworkType::kMobile:
-      return l10n_util::GetStringUTF16(GetAddESimTooltipMessageId());
+      return l10n_util::GetStringUTF16(
+          GetCellularInhibitReasonMessageId(GetCellularInhibitReason()));
     default:
       NOTREACHED();
   }
diff --git a/ash/system/network/network_list_view_controller_impl.cc b/ash/system/network/network_list_view_controller_impl.cc
index 0c132f5..44f79da 100644
--- a/ash/system/network/network_list_view_controller_impl.cc
+++ b/ash/system/network/network_list_view_controller_impl.cc
@@ -54,6 +54,7 @@
 using ::chromeos::network_config::mojom::DeviceStateType;
 using ::chromeos::network_config::mojom::FilterType;
 using ::chromeos::network_config::mojom::GlobalPolicy;
+using ::chromeos::network_config::mojom::InhibitReason;
 using ::chromeos::network_config::mojom::ManagedPropertiesPtr;
 using ::chromeos::network_config::mojom::NetworkFilter;
 using ::chromeos::network_config::mojom::NetworkStateProperties;
@@ -193,6 +194,10 @@
   GetNetworkStateList();
 }
 
+void NetworkListViewControllerImpl::DeviceStateListChanged() {
+  UpdateMobileSection();
+}
+
 void NetworkListViewControllerImpl::GlobalPolicyChanged() {
   UpdateMobileSection();
   GetNetworkStateList();
@@ -287,7 +292,7 @@
         &previous_network_views);
 
     // Add mobile status message to NetworkDetailedNetworkView's
-    // `mobile_network_list_view_` if it exist.
+    // `mobile_network_list_view_` if it exists.
     if (mobile_status_message_) {
       network_detailed_network_view()
           ->GetNetworkList(GetMobileSectionNetworkType())
@@ -815,6 +820,19 @@
                                           /*animate_toggle=*/true);
       network_detailed_network_view()->UpdateMobileStatus(true);
 
+      if (has_cellular_networks_ || has_tether_networks_) {
+        RemoveAndResetViewIfExists(&mobile_status_message_);
+        return;
+      }
+      const InhibitReason inhibit_reason = GetCellularInhibitReason();
+      if (inhibit_reason == InhibitReason::kInstallingProfile ||
+          inhibit_reason == InhibitReason::kRefreshingProfileList ||
+          inhibit_reason == InhibitReason::kRequestingAvailableProfiles) {
+        CreateInfoLabelIfMissingAndUpdate(
+            GetCellularInhibitReasonMessageId(inhibit_reason),
+            &mobile_status_message_);
+        return;
+      }
       RemoveAndResetViewIfExists(&mobile_status_message_);
       return;
     }
diff --git a/ash/system/network/network_list_view_controller_impl.h b/ash/system/network/network_list_view_controller_impl.h
index 828d288..f08f496 100644
--- a/ash/system/network/network_list_view_controller_impl.h
+++ b/ash/system/network/network_list_view_controller_impl.h
@@ -91,6 +91,7 @@
   // TrayNetworkStateObserver:
   void ActiveNetworkStateChanged() override;
   void NetworkListChanged() override;
+  void DeviceStateListChanged() override;
   void GlobalPolicyChanged() override;
 
   // bluetooth_config::mojom::SystemPropertiesObserver:
diff --git a/ash/system/network/network_list_view_controller_unittest.cc b/ash/system/network/network_list_view_controller_unittest.cc
index 8b6d3f5..df4aba3 100644
--- a/ash/system/network/network_list_view_controller_unittest.cc
+++ b/ash/system/network/network_list_view_controller_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 "ash/system/network/network_list_view_controller_impl.h"
-
 #include <algorithm>
 #include <cstddef>
 #include <memory>
@@ -19,6 +17,7 @@
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/network/network_detailed_network_view.h"
 #include "ash/system/network/network_detailed_network_view_impl.h"
+#include "ash/system/network/network_list_view_controller_impl.h"
 #include "ash/system/network/network_utils.h"
 #include "ash/system/network/tray_network_state_model.h"
 #include "ash/system/tray/detailed_view_delegate.h"
@@ -28,6 +27,7 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test_shell_delegate.h"
+#include "base/containers/flat_map.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
@@ -671,7 +671,8 @@
   // status message shouldn't been shown.
   EXPECT_TRUE(GetAddESimEntry()->GetVisible());
   EXPECT_EQ(GetAddESimEntry()->GetTooltipText(),
-            l10n_util::GetStringUTF16(GetAddESimTooltipMessageId()));
+            l10n_util::GetStringUTF16(GetCellularInhibitReasonMessageId(
+                InhibitReason::kNotInhibited)));
   ASSERT_THAT(GetMobileStatusMessage(), NotNull());
 
   // Add eSIM button is not enabled when inhibited.
@@ -687,7 +688,8 @@
   ASSERT_THAT(GetAddESimEntry(), NotNull());
   EXPECT_TRUE(GetAddESimEntry()->GetVisible());
   EXPECT_EQ(GetAddESimEntry()->GetTooltipText(),
-            l10n_util::GetStringUTF16(GetAddESimTooltipMessageId()));
+            l10n_util::GetStringUTF16(GetCellularInhibitReasonMessageId(
+                InhibitReason::kNotInhibited)));
 
   // When no Mobile networks are available and eSIM policy is set to allow only
   // cellular devices which means adding a new eSIM is disallowed by enterprise
@@ -1187,11 +1189,41 @@
   EXPECT_TRUE(GetMobileToggleButton()->GetVisible());
   EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
 
-  // No message is shown when inhibited.
-  properties->inhibit_reason = InhibitReason::kResettingEuiccMemory;
-  cros_network()->SetDeviceProperties(properties.Clone());
-  EXPECT_THAT(GetMobileStatusMessage(), IsNull());
-  CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/true);
+  const base::flat_map<InhibitReason, int> inhibit_reason_to_message_id = {
+      {{InhibitReason::kInstallingProfile,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_INSTALLING_PROFILE},
+       {InhibitReason::kRenamingProfile,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RENAMING_PROFILE},
+       {InhibitReason::kRemovingProfile,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REMOVING_PROFILE},
+       {InhibitReason::kConnectingToProfile,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_CONNECTING_TO_PROFILE},
+       {InhibitReason::kRefreshingProfileList,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REFRESHING_PROFILE_LIST},
+       {InhibitReason::kResettingEuiccMemory,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RESETTING_ESIM},
+       {InhibitReason::kDisablingProfile,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_DISABLING_PROFILE},
+       {InhibitReason::kRequestingAvailableProfiles,
+        IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REQUESTING_AVAILABLE_PROFILES}}};
+
+  for (const auto& [inhibit_reason, message_id] :
+       inhibit_reason_to_message_id) {
+    // Message shown when inhibited that communicates the inhibit state.
+    properties->inhibit_reason = inhibit_reason;
+    cros_network()->SetDeviceProperties(properties.Clone());
+    CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/true);
+
+    if (inhibit_reason == InhibitReason::kInstallingProfile ||
+        inhibit_reason == InhibitReason::kRefreshingProfileList ||
+        inhibit_reason == InhibitReason::kRequestingAvailableProfiles) {
+      ASSERT_THAT(GetMobileStatusMessage(), NotNull());
+      EXPECT_EQ(l10n_util::GetStringUTF16(message_id),
+                GetMobileStatusMessage()->label()->GetText());
+      continue;
+    }
+    ASSERT_THAT(GetMobileStatusMessage(), IsNull());
+  }
 
   // Uninhibit the device.
   properties->inhibit_reason = InhibitReason::kNotInhibited;
diff --git a/ash/system/network/network_utils.cc b/ash/system/network/network_utils.cc
index 170f759..1db1e23 100644
--- a/ash/system/network/network_utils.cc
+++ b/ash/system/network/network_utils.cc
@@ -39,14 +39,16 @@
   }
 }
 
-int GetAddESimTooltipMessageId() {
+InhibitReason GetCellularInhibitReason() {
   const DeviceStateProperties* cellular_device =
       Shell::Get()->system_tray_model()->network_state_model()->GetDevice(
           NetworkType::kCellular);
-
   CHECK(cellular_device);
+  return cellular_device->inhibit_reason;
+}
 
-  switch (cellular_device->inhibit_reason) {
+int GetCellularInhibitReasonMessageId(InhibitReason inhibit_reason) {
+  switch (inhibit_reason) {
     case InhibitReason::kInstallingProfile:
       return IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_INSTALLING_PROFILE;
     case InhibitReason::kRenamingProfile:
diff --git a/ash/system/network/network_utils.h b/ash/system/network/network_utils.h
index 403c83a..c5c0123c 100644
--- a/ash/system/network/network_utils.h
+++ b/ash/system/network/network_utils.h
@@ -45,8 +45,13 @@
     chromeos::network_config::mojom::NetworkType network_type,
     bool new_state);
 
-// Returns the add esim entry tooltip message id.
-ASH_EXPORT int GetAddESimTooltipMessageId();
+// Returns the cellular device inhibit reason.
+ASH_EXPORT chromeos::network_config::mojom::InhibitReason
+GetCellularInhibitReason();
+
+// Returns the message ID corresponding to the cellular device inhibit reason.
+ASH_EXPORT int GetCellularInhibitReasonMessageId(
+    chromeos::network_config::mojom::InhibitReason inhibit_reason);
 
 // Returns the subtext to display for a connected network in a portal state.
 // This is used in the network menu, the tooltip, and for a11y.
diff --git a/ash/webui/sanitize_ui/resources/sanitize_done.html b/ash/webui/sanitize_ui/resources/sanitize_done.html
index c017e01..6ddee68 100644
--- a/ash/webui/sanitize_ui/resources/sanitize_done.html
+++ b/ash/webui/sanitize_ui/resources/sanitize_done.html
@@ -184,7 +184,8 @@
                 <cros-button role="button" button-style="secondary"
                     id="chromeSiteContentButton"
                     on-click="onChromeSiteContentClick_"
-                    label="Chrome Site Content">
+                    aria-label="$i18n{sanitizeDoneButtonChromeSiteContent}"
+                    label="$i18n{sanitizeDoneButtonChromeSiteContent}">
                 </cros-button>
               </span>
             </div>
diff --git a/ash/webui/sanitize_ui/sanitize_ui.cc b/ash/webui/sanitize_ui/sanitize_ui.cc
index 5173bf5..6ef056f 100644
--- a/ash/webui/sanitize_ui/sanitize_ui.cc
+++ b/ash/webui/sanitize_ui/sanitize_ui.cc
@@ -108,6 +108,8 @@
        IDS_SANITIZE_DONE_BUTTON_CHROMEOS_INPUT},
       {"sanitizeDoneButtonChromeOSNetwork",
        IDS_SANITIZE_DONE_BUTTON_CHROMEOS_NETWORK},
+      {"sanitizeDoneButtonChromeSiteContent",
+       IDS_SANITIZE_DONE_BUTTON_CHROME_SITE_CONTENT},
       {"sanitizeDoneButtonChromeStartup",
        IDS_SANITIZE_DONE_BUTTON_CHROME_STARTUP},
       {"sanitizeDoneButtonChromeHomepage",
diff --git a/ash/wm/overview/birch/birch_chip_button.cc b/ash/wm/overview/birch/birch_chip_button.cc
index 9867b69..351ef1b3 100644
--- a/ash/wm/overview/birch/birch_chip_button.cc
+++ b/ash/wm/overview/birch/birch_chip_button.cc
@@ -7,6 +7,7 @@
 #include "ash/birch/birch_item.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
+#include "ash/shell_delegate.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/typography.h"
 #include "ash/wm/overview/birch/birch_bar_constants.h"
@@ -394,6 +395,12 @@
       birch_bar_controller->SetShowSuggestionType(BirchSuggestionType::kCoral,
                                                   /*show=*/false);
       break;
+    case base::to_underlying(CommandId::kProvideFeedback):
+      Shell::Get()->shell_delegate()->OpenFeedbackDialog(
+          ShellDelegate::FeedbackSource::kOverview,
+          /*description_template=*/std::string(),
+          /*category_tag=*/"Coral");
+      break;
     default:
       birch_bar_controller->ExecuteMenuCommand(command_id, /*from_chip=*/true);
   }
diff --git a/ash/wm/overview/birch/birch_chip_context_menu_model.cc b/ash/wm/overview/birch/birch_chip_context_menu_model.cc
index 408691ae..4b5fd55 100644
--- a/ash/wm/overview/birch/birch_chip_context_menu_model.cc
+++ b/ash/wm/overview/birch/birch_chip_context_menu_model.cc
@@ -8,6 +8,7 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "ash/shell_delegate.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/wm/overview/overview_utils.h"
 #include "components/prefs/pref_service.h"
@@ -99,6 +100,13 @@
                 is_celsius ? IDS_ASH_BIRCH_SHOW_TEMPERATURE_IN_FAHRENHEIT
                            : IDS_ASH_BIRCH_SHOW_TEMPERATURE_IN_CELSIUS));
   }
+
+  // Add feedback menu for Coral
+  if (chip_type == BirchSuggestionType::kCoral) {
+    AddSeparator(ui::NORMAL_SEPARATOR);
+    AddItemWithIcon(base::to_underlying(CommandId::kProvideFeedback),
+                    u"Send feedback", CreateIconForMenuItem(kFeedbackIcon));
+  }
 }
 
 BirchChipContextMenuModel::~BirchChipContextMenuModel() = default;
diff --git a/ash/wm/overview/birch/birch_chip_context_menu_model.h b/ash/wm/overview/birch/birch_chip_context_menu_model.h
index 9557d01d..865536f 100644
--- a/ash/wm/overview/birch/birch_chip_context_menu_model.h
+++ b/ash/wm/overview/birch/birch_chip_context_menu_model.h
@@ -35,6 +35,7 @@
     kHideCoralSuggestions,      // Hide all coral related chips.
     kCustomizeSuggestions,  // Pop out the expanded bar menu with customizing
                             // suggestions options.
+    kProvideFeedback,       // Pop out UI for collecting feature feedback.
   };
 
   BirchChipContextMenuModel(ui::SimpleMenuModel::Delegate* delegate,
diff --git a/base/BUILD.gn b/base/BUILD.gn
index db14741..47871db 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -5112,7 +5112,6 @@
     srcjar_deps = [ ":base_java_test_support_uncommon_jni" ]
     sources = [
       "test/android/javatests/src/org/chromium/base/FakeTimeTestRule.java",
-      "test/android/javatests/src/org/chromium/base/test/BundleTestRule.java",
       "test/android/javatests/src/org/chromium/base/test/SetUpStatement.java",
       "test/android/javatests/src/org/chromium/base/test/SetUpTestRule.java",
       "test/android/javatests/src/org/chromium/base/test/task/SchedulerTestHelpers.java",
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/no_destructor_pa_unittest.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/no_destructor_pa_unittest.cc
index 35f61d4..474f19f 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/no_destructor_pa_unittest.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/no_destructor_pa_unittest.cc
@@ -4,13 +4,14 @@
 
 #include <vector>
 
+#include "partition_alloc/partition_alloc_base/compiler_specific.h"
 #include "partition_alloc/partition_alloc_base/no_destructor.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace partition_alloc::internal::base {
 
-static constinit NoDestructor<int> an_int;
+static PA_CONSTINIT NoDestructor<int> an_int;
 
 static auto& GetVector() {
   static NoDestructor<std::vector<int>> a_vec({1, 2, 3});
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_freelist_entry.h b/base/allocator/partition_allocator/src/partition_alloc/partition_freelist_entry.h
index d1adf38..f6370de 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_freelist_entry.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_freelist_entry.h
@@ -107,7 +107,7 @@
 #else
   static const PartitionFreelistDispatcher* Create(
       PartitionFreelistEncoding encoding) {
-    static constinit PartitionFreelistDispatcher dispatcher =
+    static PA_CONSTINIT PartitionFreelistDispatcher dispatcher =
         PartitionFreelistDispatcher();
     return &dispatcher;
   }
diff --git a/base/android/java/src/org/chromium/base/BundleUtils.java b/base/android/java/src/org/chromium/base/BundleUtils.java
index d8cf7e9..e9df8e2 100644
--- a/base/android/java/src/org/chromium/base/BundleUtils.java
+++ b/base/android/java/src/org/chromium/base/BundleUtils.java
@@ -34,27 +34,10 @@
 import java.util.Collections;
 import java.util.Map;
 
-/**
- * Utils for working with android app bundles.
- *
- * Important notes about bundle status as interpreted by this class:
- *
- * <ul>
- *   <li>If {@link BuildConfig#BUNDLES_SUPPORTED} is false, then we are definitely not in a bundle,
- *   and ProGuard is able to strip out the bundle support library.</li>
- *   <li>If {@link BuildConfig#BUNDLES_SUPPORTED} is true, then we MIGHT be in a bundle.
- *   {@link BundleUtils#sIsBundle} is the source of truth.</li>
- * </ul>
- *
- * We need two fields to store one bit of information here to ensure that ProGuard can optimize out
- * the bundle support library (since {@link BuildConfig#BUNDLES_SUPPORTED} is final) and so that
- * we can dynamically set whether or not we're in a bundle for targets that use static shared
- * library APKs.
- */
+/** Utils for working with android app bundles. */
 public class BundleUtils {
     private static final String TAG = "BundleUtils";
     private static final String LOADED_SPLITS_KEY = "split_compat_loaded_splits";
-    private static Boolean sIsBundle;
     private static final Object sSplitLock = new Object();
 
     // This cache is needed to support the workaround for b/172602571, see
@@ -70,42 +53,15 @@
     private static ArrayList<String> sSplitsToRestore;
 
     public static void resetForTesting() {
-        sIsBundle = null;
         sCachedClassLoaders.clear();
         sInflationClassLoaders.clear();
         sSplitCompatClassLoaderInstance = null;
         sSplitsToRestore = null;
     }
 
-    /**
-     * {@link BundleUtils#isBundle()}  is not called directly by native because
-     * {@link CalledByNative} prevents inlining, causing the bundle support lib to not be
-     * removed non-bundle builds.
-     *
-     * @return true if the current build is a bundle.
-     */
     @CalledByNative
-    public static boolean isBundleForNative() {
-        return isBundle();
-    }
-
-    /**
-     * @return true if the current build is a bundle.
-     */
-    public static boolean isBundle() {
-        if (!BuildConfig.BUNDLES_SUPPORTED) {
-            return false;
-        }
-        assert sIsBundle != null;
-        return sIsBundle;
-    }
-
-    public static void setIsBundle(boolean isBundle) {
-        sIsBundle = isBundle;
-    }
-
-    public static boolean isolatedSplitsEnabled() {
-        return BuildConfig.ISOLATED_SPLITS_ENABLED;
+    private static boolean isBundleForNative() {
+        return BuildConfig.IS_BUNDLE;
     }
 
     @RequiresApi(api = Build.VERSION_CODES.O)
@@ -124,7 +80,7 @@
      * below O, where isolated splits are not supported.
      */
     public static boolean isIsolatedSplitInstalled(String splitName) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+        if (!BuildConfig.IS_BUNDLE || Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
             return false;
         }
         return getSplitApkPath(splitName) != null;
@@ -145,7 +101,7 @@
     public static Context createIsolatedSplitContext(Context base, String splitName) {
         // Isolated splits are only supported in O+, so just return the base context on other
         // versions, since this will have access to all splits.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+        if (!BuildConfig.IS_BUNDLE || Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
             return base;
         }
 
@@ -174,8 +130,7 @@
             // SplitCompatAppComponentFactory, but modules which depend on the chrome module need
             // special handling here to make sure they have the correct parent.
             boolean shouldReplaceClassLoader =
-                    isolatedSplitsEnabled()
-                            && !parent.equals(BundleUtils.class.getClassLoader())
+                    !parent.equals(BundleUtils.class.getClassLoader())
                             && appContext != null
                             && !parent.equals(appContext.getClassLoader());
             synchronized (sCachedClassLoaders) {
@@ -322,10 +277,12 @@
     }
 
     /**
-     * Returns the ClassLoader for the given split, loading the split if it has not yet been
-     * loaded.
+     * Returns the ClassLoader for the given split, loading the split if it has not yet been loaded.
      */
     public static ClassLoader getOrCreateSplitClassLoader(String splitName) {
+        if (!BuildConfig.IS_BUNDLE) {
+            return BundleUtils.class.getClassLoader();
+        }
         ClassLoader ret;
         synchronized (sCachedClassLoaders) {
             ret = sCachedClassLoaders.get(splitName);
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index 4b871e2..7067dfa 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -43,14 +43,6 @@
   return ToJavaByteArray(env, base::as_byte_span(str));
 }
 
-ScopedJavaLocalRef<jbooleanArray> ToJavaBooleanArray(JNIEnv* env,
-                                                     const bool* bools,
-                                                     size_t len) {
-  // SAFETY: The caller must provide a valid pointer and length, as enforced
-  // by UNSAFE_BUFFER_USAGE in the header.
-  return ToJavaBooleanArray(env, UNSAFE_BUFFERS(base::span(bools, len)));
-}
-
 ScopedJavaLocalRef<jbooleanArray> ToJavaBooleanArray(
     JNIEnv* env,
     const std::vector<bool>& bools) {
@@ -77,14 +69,6 @@
   return ScopedJavaLocalRef<jbooleanArray>(env, boolean_array);
 }
 
-// TODO(tsepez): this should be declared UNSAFE_BUFFER_USAGE in the header.
-ScopedJavaLocalRef<jintArray> ToJavaIntArray(JNIEnv* env,
-                                             const int32_t* ints,
-                                             size_t len) {
-  // SAFETY: The caller must provide a valid pointer and length.
-  return ToJavaIntArray(env, UNSAFE_BUFFERS(base::span(ints, len)));
-}
-
 ScopedJavaLocalRef<jintArray> ToJavaIntArray(JNIEnv* env,
                                              base::span<const int32_t> ints) {
   jintArray int_array = env->NewIntArray(checked_cast<jsize>(ints.size()));
@@ -100,14 +84,6 @@
   return ScopedJavaLocalRef<jintArray>(env, int_array);
 }
 
-ScopedJavaLocalRef<jlongArray> ToJavaLongArray(JNIEnv* env,
-                                               const int64_t* longs,
-                                               size_t len) {
-  // SAFETY: The caller must provide a valid pointer and length, as enforced
-  // by UNSAFE_BUFFER_USAGE in the header.
-  return ToJavaLongArray(env, UNSAFE_BUFFERS(base::span(longs, len)));
-}
-
 // Returns a new Java long array converted from the given int64_t array.
 BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
     JNIEnv* env,
@@ -126,14 +102,6 @@
   return ScopedJavaLocalRef<jlongArray>(env, long_array);
 }
 
-// Returns a new Java float array converted from the given C++ float array.
-BASE_EXPORT ScopedJavaLocalRef<jfloatArray>
-ToJavaFloatArray(JNIEnv* env, const float* floats, size_t len) {
-  // SAFETY: The caller must provide a valid pointer and length, as enforced
-  // by UNSAFE_BUFFER_USAGE in the header.
-  return ToJavaFloatArray(env, UNSAFE_BUFFERS(base::span(floats, len)));
-}
-
 BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
     JNIEnv* env,
     base::span<const float> floats) {
@@ -152,13 +120,6 @@
   return ScopedJavaLocalRef<jfloatArray>(env, float_array);
 }
 
-BASE_EXPORT ScopedJavaLocalRef<jdoubleArray>
-ToJavaDoubleArray(JNIEnv* env, const double* doubles, size_t len) {
-  // SAFETY: The caller must provide a valid pointer and length, as enforced
-  // by UNSAFE_BUFFER_USAGE in the header.
-  return ToJavaDoubleArray(env, UNSAFE_BUFFERS(base::span(doubles, len)));
-}
-
 BASE_EXPORT ScopedJavaLocalRef<jdoubleArray> ToJavaDoubleArray(
     JNIEnv* env,
     base::span<const double> doubles) {
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
index 479eb4a..64776a7 100644
--- a/base/android/jni_array.h
+++ b/base/android/jni_array.h
@@ -59,57 +59,26 @@
     JNIEnv* env,
     const std::vector<bool>& bools);
 
-// Returns a new Java boolean array converted from the given bool array.
-//
-// TODO(crbug.com/40284755): Remove this overload, use spans.
-UNSAFE_BUFFER_USAGE BASE_EXPORT ScopedJavaLocalRef<jbooleanArray>
-ToJavaBooleanArray(JNIEnv* env, const bool* bools, size_t len);
-
 // Returns a new Java int array converted from the given int array.
 BASE_EXPORT ScopedJavaLocalRef<jintArray> ToJavaIntArray(
     JNIEnv* env,
     span<const int32_t> ints);
 
-// Returns a new Java int array converted from the given int array.
-//
-// TODO(crbug.com/40284755): Remove this overload, use spans.
-BASE_EXPORT ScopedJavaLocalRef<jintArray> ToJavaIntArray(JNIEnv* env,
-                                                         const int32_t* ints,
-                                                         size_t len);
-
 // Returns a new Java long array converted from the given int64_t array.
 BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
     JNIEnv* env,
     span<const int64_t> longs);
 
-// Returns a new Java long array converted from the given int64_t array.
-//
-// TODO(crbug.com/40284755): Remove this overload, use spans.
-UNSAFE_BUFFER_USAGE BASE_EXPORT ScopedJavaLocalRef<jlongArray>
-ToJavaLongArray(JNIEnv* env, const int64_t* longs, size_t len);
-
 // Returns a new Java float array converted from the given C++ float array.
 BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
     JNIEnv* env,
     span<const float> floats);
 
-// Returns a new Java float array converted from the given C++ float array.
-//
-// TODO(crbug.com/40284755): Remove this overload, use spans.
-UNSAFE_BUFFER_USAGE BASE_EXPORT ScopedJavaLocalRef<jfloatArray>
-ToJavaFloatArray(JNIEnv* env, const float* floats, size_t len);
-
 // Returns a new Java double array converted from the given C++ double array.
 BASE_EXPORT ScopedJavaLocalRef<jdoubleArray> ToJavaDoubleArray(
     JNIEnv* env,
     span<const double> doubles);
 
-// Returns a new Java double array converted from the given C++ double array.
-//
-// TODO(crbug.com/40284755): Remove this overload, use spans.
-UNSAFE_BUFFER_USAGE BASE_EXPORT ScopedJavaLocalRef<jdoubleArray>
-ToJavaDoubleArray(JNIEnv* env, const double* doubles, size_t len);
-
 // Returns a new clazz[] with the content of |v|.
 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfObjects(
     JNIEnv* env,
diff --git a/base/process/process_info_win.cc b/base/process/process_info_win.cc
index 04b3425..a6e4e78 100644
--- a/base/process/process_info_win.cc
+++ b/base/process/process_info_win.cc
@@ -20,7 +20,7 @@
 IntegrityLevel GetProcessIntegrityLevelInternal(
     std::optional<win::AccessToken> token) {
   if (!token) {
-    PLOG(ERROR) << "AccessToken::FromCurrentProcess() failed";
+    PLOG(ERROR) << "AccessToken `token` is invalid";
     return INTEGRITY_UNKNOWN;
   }
   DWORD integrity_level = token->IntegrityLevel();
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BundleTestRule.java b/base/test/android/javatests/src/org/chromium/base/test/BundleTestRule.java
deleted file mode 100644
index 319c8d1a..0000000
--- a/base/test/android/javatests/src/org/chromium/base/test/BundleTestRule.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.base.test;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import org.chromium.base.BundleUtils;
-
-/** Ensures that BundleUtils#isBundle returns true for the duration of the test. */
-public class BundleTestRule implements TestRule {
-    @Override
-    public Statement apply(Statement base, Description description) {
-        return new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                boolean oldValue = BundleUtils.isBundle();
-                try {
-                    BundleUtils.setIsBundle(true);
-                    base.evaluate();
-                } finally {
-                    BundleUtils.setIsBundle(oldValue);
-                }
-            }
-        };
-    }
-}
diff --git a/base/third_party/icu/README.chromium b/base/third_party/icu/README.chromium
index c514fc5..691795d 100644
--- a/base/third_party/icu/README.chromium
+++ b/base/third_party/icu/README.chromium
@@ -3,6 +3,7 @@
 Version: 60
 License: Unicode
 License File: LICENSE
+Security Critical: yes
 Shipped: no
 
 This file has the relevant components from ICU copied to handle basic UTF8/16/32
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc
index 55633f7..9ec4c77e 100644
--- a/base/threading/thread_restrictions.cc
+++ b/base/threading/thread_restrictions.cc
@@ -4,58 +4,54 @@
 
 #include "base/threading/thread_restrictions.h"
 
+#include "base/check.h"
 #include "base/threading/hang_watcher.h"
 #include "base/trace_event/base_tracing.h"
 #include "build/build_config.h"
-
-#if DCHECK_IS_ON()
-#include "base/check_op.h"
 #include "third_party/abseil-cpp/absl/base/attributes.h"
 
-// NaCL doesn't support stack sampling and Android is slow at stack sampling and
-// this causes timeouts (crbug.com/959139).
-#if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_ANDROID)
-constexpr bool kCaptureStackTraces = false;
-#else
-// Always disabled when !EXPENSIVE_DCHECKS_ARE_ON() because user-facing builds
-// typically drop log strings anyways.
-constexpr bool kCaptureStackTraces = EXPENSIVE_DCHECKS_ARE_ON();
-#endif
-
 namespace base {
 
-BooleanWithStack::BooleanWithStack(bool value) : value_(value) {
-  if (kCaptureStackTraces) {
-    stack_.emplace();
-  }
+BooleanWithOptionalStack::BooleanWithOptionalStack(bool value) : value_(value) {
+#if CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES()
+  stack_.emplace();
+#endif  // CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES()
 }
 
-std::ostream& operator<<(std::ostream& out, const BooleanWithStack& bws) {
+std::ostream& operator<<(std::ostream& out,
+                         const BooleanWithOptionalStack& bws) {
   out << bws.value_;
-  if (kCaptureStackTraces) {
-    if (bws.stack_.has_value()) {
-      out << " set by\n" << bws.stack_.value();
-    } else {
-      out << " (value by default)";
-    }
+#if CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES()
+  if (bws.stack_.has_value()) {
+    out << " set by\n" << bws.stack_.value();
+  } else {
+    out << " (value by default)";
   }
+#endif  // CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES()
   return out;
 }
 
+// A macro that dumps in official builds (non-fatal) if the condition is false,
+// or behaves as DCHECK in DCHECK-enabled builds. Unlike DUMP_WILL_BE_CHECK,
+// there is no intent to transform those into CHECKs. Used to report potential
+// performance issues.
+#define DUMP_OR_DCHECK DUMP_WILL_BE_CHECK
+
 namespace {
 
-ABSL_CONST_INIT thread_local BooleanWithStack tls_blocking_disallowed;
-ABSL_CONST_INIT thread_local BooleanWithStack tls_singleton_disallowed;
-ABSL_CONST_INIT thread_local BooleanWithStack
+ABSL_CONST_INIT thread_local BooleanWithOptionalStack tls_blocking_disallowed;
+ABSL_CONST_INIT thread_local BooleanWithOptionalStack tls_singleton_disallowed;
+ABSL_CONST_INIT thread_local BooleanWithOptionalStack
     tls_base_sync_primitives_disallowed;
-ABSL_CONST_INIT thread_local BooleanWithStack tls_cpu_intensive_work_disallowed;
+ABSL_CONST_INIT thread_local BooleanWithOptionalStack
+    tls_cpu_intensive_work_disallowed;
 
 }  // namespace
 
 namespace internal {
 
 void AssertBlockingAllowed() {
-  DCHECK(!tls_blocking_disallowed)
+  DUMP_OR_DCHECK(!tls_blocking_disallowed)
       << "Function marked as blocking was called from a scope that disallows "
          "blocking! If this task is running inside the ThreadPool, it needs "
          "to have MayBlock() in its TaskTraits. Otherwise, consider making "
@@ -72,11 +68,11 @@
 }  // namespace internal
 
 void DisallowBlocking() {
-  tls_blocking_disallowed = BooleanWithStack(true);
+  tls_blocking_disallowed = BooleanWithOptionalStack(true);
 }
 
 ScopedDisallowBlocking::ScopedDisallowBlocking()
-    : resetter_(&tls_blocking_disallowed, BooleanWithStack(true)) {}
+    : resetter_(&tls_blocking_disallowed, BooleanWithOptionalStack(true)) {}
 
 ScopedDisallowBlocking::~ScopedDisallowBlocking() {
   DCHECK(tls_blocking_disallowed)
@@ -86,11 +82,12 @@
 }
 
 void DisallowBaseSyncPrimitives() {
-  tls_base_sync_primitives_disallowed = BooleanWithStack(true);
+  tls_base_sync_primitives_disallowed = BooleanWithOptionalStack(true);
 }
 
 ScopedDisallowBaseSyncPrimitives::ScopedDisallowBaseSyncPrimitives()
-    : resetter_(&tls_base_sync_primitives_disallowed, BooleanWithStack(true)) {}
+    : resetter_(&tls_base_sync_primitives_disallowed,
+                BooleanWithOptionalStack(true)) {}
 
 ScopedDisallowBaseSyncPrimitives::~ScopedDisallowBaseSyncPrimitives() {
   DCHECK(tls_base_sync_primitives_disallowed)
@@ -101,7 +98,8 @@
 }
 
 ScopedAllowBaseSyncPrimitives::ScopedAllowBaseSyncPrimitives()
-    : resetter_(&tls_base_sync_primitives_disallowed, BooleanWithStack(false)) {
+    : resetter_(&tls_base_sync_primitives_disallowed,
+                BooleanWithOptionalStack(false)) {
   DCHECK(!tls_blocking_disallowed)
       << "To allow //base sync primitives in a scope where blocking is "
          "disallowed use ScopedAllowBaseSyncPrimitivesOutsideBlockingScope.\n"
@@ -118,8 +116,8 @@
 
 ScopedAllowBaseSyncPrimitivesForTesting::
     ScopedAllowBaseSyncPrimitivesForTesting()
-    : resetter_(&tls_base_sync_primitives_disallowed, BooleanWithStack(false)) {
-}
+    : resetter_(&tls_base_sync_primitives_disallowed,
+                BooleanWithOptionalStack(false)) {}
 
 ScopedAllowBaseSyncPrimitivesForTesting::
     ~ScopedAllowBaseSyncPrimitivesForTesting() {
@@ -132,10 +130,11 @@
 
 ScopedAllowUnresponsiveTasksForTesting::ScopedAllowUnresponsiveTasksForTesting()
     : base_sync_resetter_(&tls_base_sync_primitives_disallowed,
-                          BooleanWithStack(false)),
-      blocking_resetter_(&tls_blocking_disallowed, BooleanWithStack(false)),
+                          BooleanWithOptionalStack(false)),
+      blocking_resetter_(&tls_blocking_disallowed,
+                         BooleanWithOptionalStack(false)),
       cpu_resetter_(&tls_cpu_intensive_work_disallowed,
-                    BooleanWithStack(false)) {}
+                    BooleanWithOptionalStack(false)) {}
 
 ScopedAllowUnresponsiveTasksForTesting::
     ~ScopedAllowUnresponsiveTasksForTesting() {
@@ -158,7 +157,7 @@
 namespace internal {
 
 void AssertBaseSyncPrimitivesAllowed() {
-  DCHECK(!tls_base_sync_primitives_disallowed)
+  DUMP_OR_DCHECK(!tls_base_sync_primitives_disallowed)
       << "Waiting on a //base sync primitive is not allowed on this thread to "
          "prevent jank and deadlock. If waiting on a //base sync primitive is "
          "unavoidable, do it within the scope of a "
@@ -171,14 +170,14 @@
 }
 
 void ResetThreadRestrictionsForTesting() {
-  tls_blocking_disallowed = BooleanWithStack(false);
-  tls_singleton_disallowed = BooleanWithStack(false);
-  tls_base_sync_primitives_disallowed = BooleanWithStack(false);
-  tls_cpu_intensive_work_disallowed = BooleanWithStack(false);
+  tls_blocking_disallowed = BooleanWithOptionalStack(false);
+  tls_singleton_disallowed = BooleanWithOptionalStack(false);
+  tls_base_sync_primitives_disallowed = BooleanWithOptionalStack(false);
+  tls_cpu_intensive_work_disallowed = BooleanWithOptionalStack(false);
 }
 
 void AssertSingletonAllowed() {
-  DCHECK(!tls_singleton_disallowed)
+  DUMP_OR_DCHECK(!tls_singleton_disallowed)
       << "LazyInstance/Singleton is not allowed to be used on this thread. "
          "Most likely it's because this thread is not joinable (or the current "
          "task is running with TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN "
@@ -192,11 +191,11 @@
 }  // namespace internal
 
 void DisallowSingleton() {
-  tls_singleton_disallowed = BooleanWithStack(true);
+  tls_singleton_disallowed = BooleanWithOptionalStack(true);
 }
 
 ScopedDisallowSingleton::ScopedDisallowSingleton()
-    : resetter_(&tls_singleton_disallowed, BooleanWithStack(true)) {}
+    : resetter_(&tls_singleton_disallowed, BooleanWithOptionalStack(true)) {}
 
 ScopedDisallowSingleton::~ScopedDisallowSingleton() {
   DCHECK(tls_singleton_disallowed)
@@ -206,7 +205,7 @@
 }
 
 void AssertLongCPUWorkAllowed() {
-  DCHECK(!tls_cpu_intensive_work_disallowed)
+  DUMP_OR_DCHECK(!tls_cpu_intensive_work_disallowed)
       << "Function marked as CPU intensive was called from a scope that "
          "disallows this kind of work! Consider making this work "
          "asynchronous.\n"
@@ -217,30 +216,21 @@
 void DisallowUnresponsiveTasks() {
   DisallowBlocking();
   DisallowBaseSyncPrimitives();
-  tls_cpu_intensive_work_disallowed = BooleanWithStack(true);
+  tls_cpu_intensive_work_disallowed = BooleanWithOptionalStack(true);
 }
 
 // static
 void PermanentThreadAllowance::AllowBlocking() {
-  tls_blocking_disallowed = BooleanWithStack(false);
+  tls_blocking_disallowed = BooleanWithOptionalStack(false);
 }
 
 // static
 void PermanentThreadAllowance::AllowBaseSyncPrimitives() {
-  tls_base_sync_primitives_disallowed = BooleanWithStack(false);
+  tls_base_sync_primitives_disallowed = BooleanWithOptionalStack(false);
 }
 
-}  // namespace base
-
-#endif  // DCHECK_IS_ON()
-
-namespace base {
-
 ScopedAllowBlocking::ScopedAllowBlocking(const Location& from_here)
-#if DCHECK_IS_ON()
-    : resetter_(&tls_blocking_disallowed, BooleanWithStack(false))
-#endif
-{
+    : resetter_(&tls_blocking_disallowed, BooleanWithOptionalStack(false)) {
   TRACE_EVENT_BEGIN(
       "base", "ScopedAllowBlocking", [&](perfetto::EventContext ctx) {
         ctx.event()->set_source_location_iid(
@@ -251,20 +241,16 @@
 ScopedAllowBlocking::~ScopedAllowBlocking() {
   TRACE_EVENT_END0("base", "ScopedAllowBlocking");
 
-#if DCHECK_IS_ON()
   DCHECK(!tls_blocking_disallowed)
       << "~ScopedAllowBlocking() running while surprisingly already no longer "
          "allowed.\n"
       << "tls_blocking_disallowed " << tls_blocking_disallowed;
-#endif
 }
 
 ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
     ScopedAllowBaseSyncPrimitivesOutsideBlockingScope(const Location& from_here)
-#if DCHECK_IS_ON()
-    : resetter_(&tls_base_sync_primitives_disallowed, BooleanWithStack(false))
-#endif
-{
+    : resetter_(&tls_base_sync_primitives_disallowed,
+                BooleanWithOptionalStack(false)) {
   TRACE_EVENT_BEGIN(
       "base", "ScopedAllowBaseSyncPrimitivesOutsideBlockingScope",
       [&](perfetto::EventContext ctx) {
@@ -282,13 +268,11 @@
     ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() {
   TRACE_EVENT_END0("base", "ScopedAllowBaseSyncPrimitivesOutsideBlockingScope");
 
-#if DCHECK_IS_ON()
   DCHECK(!tls_base_sync_primitives_disallowed)
       << "~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() running while "
          "surprisingly already no longer allowed.\n"
       << "tls_base_sync_primitives_disallowed "
       << tls_base_sync_primitives_disallowed;
-#endif
 }
 
 }  // namespace base
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index b40103d..0de909d 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -5,20 +5,16 @@
 #ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_
 #define BASE_THREADING_THREAD_RESTRICTIONS_H_
 
+#include <optional>
+
 #include "base/auto_reset.h"
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
-#include "base/dcheck_is_on.h"
+#include "base/debug/stack_trace.h"
 #include "base/gtest_prod_util.h"
 #include "base/location.h"
 #include "build/build_config.h"
 
-#if DCHECK_IS_ON()
-#include <optional>
-
-#include "base/debug/stack_trace.h"
-#endif
-
 // -----------------------------------------------------------------------------
 // Usage documentation
 // -----------------------------------------------------------------------------
@@ -505,76 +501,66 @@
 class TestCustomDisallow;
 class Thread;
 
-#if DCHECK_IS_ON()
-// NOT_TAIL_CALLED if dcheck-is-on so it's always evident who irrevocably
-// altered the allowance (dcheck-builds will provide the setter's stack on
-// assertion) or who made a failing Assert*() call.
-#define INLINE_OR_NOT_TAIL_CALLED NOT_TAIL_CALLED BASE_EXPORT
-#define EMPTY_BODY_IF_DCHECK_IS_OFF
-#define DEFAULT_IF_DCHECK_IS_OFF
+// NaCL doesn't support stack capture.
+// Android can hang in stack capture (crbug.com/959139).
+#if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_ANDROID)
+#define CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES() false
+#else
+// Stack capture is slow. Only enable it in developer builds, to avoid user
+// visible jank when thread restrictions are set.
+#define CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES() EXPENSIVE_DCHECKS_ARE_ON()
+#endif
 
-class BooleanWithStack {
+// A boolean and the stack from which it was set. Note: The stack is not
+// captured in all builds, see `CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES()`.
+class BooleanWithOptionalStack {
  public:
   // Default value.
-  BooleanWithStack() = default;
+  BooleanWithOptionalStack() = default;
 
   // Value when explicitly set.
-  explicit BooleanWithStack(bool value);
+  explicit BooleanWithOptionalStack(bool value);
 
   explicit operator bool() const { return value_; }
 
   friend std::ostream& operator<<(std::ostream& out,
-                                  const BooleanWithStack& bws);
+                                  const BooleanWithOptionalStack& bws);
 
  private:
   bool value_ = false;
+#if CAPTURE_THREAD_RESTRICTIONS_STACK_TRACES()
   std::optional<debug::StackTrace> stack_;
+#endif
 };
 
-#else
-// inline if dcheck-is-off so it's no overhead
-#define INLINE_OR_NOT_TAIL_CALLED inline
-
-// The static_assert() eats follow-on semicolons.
-#define EMPTY_BODY_IF_DCHECK_IS_OFF \
-  {}                                \
-  static_assert(true)
-
-#define DEFAULT_IF_DCHECK_IS_OFF = default
-#endif  // DCHECK_IS_ON()
-
 namespace internal {
 
 // Asserts that blocking calls are allowed in the current scope. This is an
 // internal call, external code should use ScopedBlockingCall instead, which
 // serves as a precise annotation of the scope that may/will block.
-INLINE_OR_NOT_TAIL_CALLED void AssertBlockingAllowed()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
-INLINE_OR_NOT_TAIL_CALLED void AssertBlockingDisallowedForTesting()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void AssertBlockingAllowed();
+NOT_TAIL_CALLED BASE_EXPORT void AssertBlockingDisallowedForTesting();
 
 }  // namespace internal
 
 // Disallows blocking on the current thread.
-INLINE_OR_NOT_TAIL_CALLED void DisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void DisallowBlocking();
 
 // Disallows blocking calls within its scope.
-class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowBlocking {
+class BASE_EXPORT ScopedDisallowBlocking {
  public:
-  ScopedDisallowBlocking() DEFAULT_IF_DCHECK_IS_OFF;
+  ScopedDisallowBlocking();
 
   ScopedDisallowBlocking(const ScopedDisallowBlocking&) = delete;
   ScopedDisallowBlocking& operator=(const ScopedDisallowBlocking&) = delete;
 
-  ~ScopedDisallowBlocking() DEFAULT_IF_DCHECK_IS_OFF;
+  ~ScopedDisallowBlocking();
 
  private:
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> resetter_;
 };
 
-class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBlocking {
+class BASE_EXPORT ScopedAllowBlocking {
  public:
   ScopedAllowBlocking(const ScopedAllowBlocking&) = delete;
   ScopedAllowBlocking& operator=(const ScopedAllowBlocking&) = delete;
@@ -705,12 +691,10 @@
   ScopedAllowBlocking(const Location& from_here = Location::Current());
   ~ScopedAllowBlocking();
 
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> resetter_;
 };
 
-class [[maybe_unused, nodiscard]] ScopedAllowBlockingForTesting {
+class ScopedAllowBlockingForTesting {
  public:
   ScopedAllowBlockingForTesting() = default;
 
@@ -721,33 +705,28 @@
   ~ScopedAllowBlockingForTesting() = default;
 
  private:
-#if DCHECK_IS_ON()
   ScopedAllowBlocking scoped_allow_blocking_;
-#endif
 };
 
-INLINE_OR_NOT_TAIL_CALLED void DisallowBaseSyncPrimitives()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void DisallowBaseSyncPrimitives();
 
 // Disallows singletons within its scope.
-class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowBaseSyncPrimitives {
+class BASE_EXPORT ScopedDisallowBaseSyncPrimitives {
  public:
-  ScopedDisallowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
+  ScopedDisallowBaseSyncPrimitives();
 
   ScopedDisallowBaseSyncPrimitives(const ScopedDisallowBaseSyncPrimitives&) =
       delete;
   ScopedDisallowBaseSyncPrimitives& operator=(
       const ScopedDisallowBaseSyncPrimitives&) = delete;
 
-  ~ScopedDisallowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
+  ~ScopedDisallowBaseSyncPrimitives();
 
  private:
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> resetter_;
 };
 
-class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitives {
+class BASE_EXPORT ScopedAllowBaseSyncPrimitives {
  public:
   ScopedAllowBaseSyncPrimitives(const ScopedAllowBaseSyncPrimitives&) = delete;
   ScopedAllowBaseSyncPrimitives& operator=(
@@ -825,12 +804,10 @@
   friend class viz::SkiaOutputSurfaceImpl;       // http://crbug.com/341151462
   friend class viz::SharedImageInterfaceProvider;  // http://crbug.com/341151462
 
-  ScopedAllowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
-  ~ScopedAllowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
+  ScopedAllowBaseSyncPrimitives();
+  ~ScopedAllowBaseSyncPrimitives();
 
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> resetter_;
 };
 
 class BASE_EXPORT
@@ -938,9 +915,7 @@
 
   ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope();
 
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> resetter_;
 };
 
 // Allow base-sync-primitives in tests, doesn't require explicit friend'ing like
@@ -948,89 +923,76 @@
 // Note: For WaitableEvents in the test logic, base::TestWaitableEvent is
 // exposed as a convenience to avoid the need for
 // ScopedAllowBaseSyncPrimitivesForTesting.
-class BASE_EXPORT
-    [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitivesForTesting {
+class BASE_EXPORT ScopedAllowBaseSyncPrimitivesForTesting {
  public:
-  ScopedAllowBaseSyncPrimitivesForTesting() DEFAULT_IF_DCHECK_IS_OFF;
+  ScopedAllowBaseSyncPrimitivesForTesting();
 
   ScopedAllowBaseSyncPrimitivesForTesting(
       const ScopedAllowBaseSyncPrimitivesForTesting&) = delete;
   ScopedAllowBaseSyncPrimitivesForTesting& operator=(
       const ScopedAllowBaseSyncPrimitivesForTesting&) = delete;
 
-  ~ScopedAllowBaseSyncPrimitivesForTesting() DEFAULT_IF_DCHECK_IS_OFF;
+  ~ScopedAllowBaseSyncPrimitivesForTesting();
 
  private:
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> resetter_;
 };
 
 // Counterpart to base::DisallowUnresponsiveTasks() for tests to allow them to
 // block their thread after it was banned.
-class BASE_EXPORT
-    [[maybe_unused, nodiscard]] ScopedAllowUnresponsiveTasksForTesting {
+class BASE_EXPORT ScopedAllowUnresponsiveTasksForTesting {
  public:
-  ScopedAllowUnresponsiveTasksForTesting() DEFAULT_IF_DCHECK_IS_OFF;
+  ScopedAllowUnresponsiveTasksForTesting();
 
   ScopedAllowUnresponsiveTasksForTesting(
       const ScopedAllowUnresponsiveTasksForTesting&) = delete;
   ScopedAllowUnresponsiveTasksForTesting& operator=(
       const ScopedAllowUnresponsiveTasksForTesting&) = delete;
 
-  ~ScopedAllowUnresponsiveTasksForTesting() DEFAULT_IF_DCHECK_IS_OFF;
+  ~ScopedAllowUnresponsiveTasksForTesting();
 
  private:
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> base_sync_resetter_;
-  const AutoReset<BooleanWithStack> blocking_resetter_;
-  const AutoReset<BooleanWithStack> cpu_resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> base_sync_resetter_;
+  const AutoReset<BooleanWithOptionalStack> blocking_resetter_;
+  const AutoReset<BooleanWithOptionalStack> cpu_resetter_;
 };
 
 namespace internal {
 
 // Asserts that waiting on a //base sync primitive is allowed in the current
 // scope.
-INLINE_OR_NOT_TAIL_CALLED void AssertBaseSyncPrimitivesAllowed()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void AssertBaseSyncPrimitivesAllowed();
 
 // Resets all thread restrictions on the current thread.
-INLINE_OR_NOT_TAIL_CALLED void ResetThreadRestrictionsForTesting()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
+BASE_EXPORT void ResetThreadRestrictionsForTesting();
 
 // Check whether the current thread is allowed to use singletons (Singleton /
 // LazyInstance).  DCHECKs if not.
-INLINE_OR_NOT_TAIL_CALLED void AssertSingletonAllowed()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void AssertSingletonAllowed();
 
 }  // namespace internal
 
 // Disallow using singleton on the current thread.
-INLINE_OR_NOT_TAIL_CALLED void DisallowSingleton() EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void DisallowSingleton();
 
 // Disallows singletons within its scope.
-class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowSingleton {
+class BASE_EXPORT ScopedDisallowSingleton {
  public:
-  ScopedDisallowSingleton() DEFAULT_IF_DCHECK_IS_OFF;
+  ScopedDisallowSingleton();
 
   ScopedDisallowSingleton(const ScopedDisallowSingleton&) = delete;
   ScopedDisallowSingleton& operator=(const ScopedDisallowSingleton&) = delete;
 
-  ~ScopedDisallowSingleton() DEFAULT_IF_DCHECK_IS_OFF;
+  ~ScopedDisallowSingleton();
 
  private:
-#if DCHECK_IS_ON()
-  const AutoReset<BooleanWithStack> resetter_;
-#endif
+  const AutoReset<BooleanWithOptionalStack> resetter_;
 };
 
 // Asserts that running long CPU work is allowed in the current scope.
-INLINE_OR_NOT_TAIL_CALLED void AssertLongCPUWorkAllowed()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void AssertLongCPUWorkAllowed();
 
-INLINE_OR_NOT_TAIL_CALLED void DisallowUnresponsiveTasks()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
+NOT_TAIL_CALLED BASE_EXPORT void DisallowUnresponsiveTasks();
 
 // Friend-only methods to permanently allow the current thread to use
 // blocking/sync-primitives calls. Threads start out in the *allowed* state but
@@ -1054,14 +1016,10 @@
 #endif  // BUILDFLAG(IS_IOS)
   friend class web::WebMainLoop;
 
-  static void AllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
-  static void AllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
+  static void AllowBlocking();
+  static void AllowBaseSyncPrimitives();
 };
 
-#undef INLINE_OR_NOT_TAIL_CALLED
-#undef EMPTY_BODY_IF_DCHECK_IS_OFF
-#undef DEFAULT_IF_DCHECK_IS_OFF
-
 }  // namespace base
 
 #endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index 2f1c81a..ccd31464 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -167,8 +167,8 @@
   additional_space += 56 * 1024;
 #endif
 #if DCHECK_IS_ON()
-  // The thread restrictions add four BooleanWithStacks (which are ~2k each).
-  additional_space += sizeof(BooleanWithStack) * 4;
+  // The thread restrictions add four BooleanWithOptionalStacks (~2k each).
+  additional_space += sizeof(BooleanWithOptionalStack) * 4;
 #endif
 
   Thread a("StartWithStackSize");
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto
index eb14cae..ceddb270 100644
--- a/base/tracing/protos/chrome_track_event.proto
+++ b/base/tracing/protos/chrome_track_event.proto
@@ -1928,6 +1928,7 @@
     GOOGLE_ADS_LIBRARIES = 14;
     FUNDING_CHOICES = 15;
     ELEMENTOR = 16;
+    SLIDER_REVOLUTION = 17;
   }
   optional ThirdPartyTechnology third_party_technology = 10;
 }
@@ -1979,9 +1980,91 @@
   optional BeginFrameId last_begin_frame_id_during_first_draw = 5;
 }
 
+message ChromeLatencyInfo2 {
+  optional int64 trace_id = 1;
+
+  // NEXT ID: 12
+  // All step are optional but the enum is ordered (not by number) below in the
+  // order we expect them to appear if they are emitted in trace in a blocking
+  // fashion.
+  enum Step {
+    STEP_UNSPECIFIED = 0;
+    // Emitted on the browser main thread.
+    STEP_SEND_INPUT_EVENT_UI = 3;
+    // Happens on the renderer's compositor.
+    STEP_HANDLE_INPUT_EVENT_IMPL = 5;
+    STEP_DID_HANDLE_INPUT_AND_OVERSCROLL = 8;
+    // Occurs on the Renderer's main thread.
+    STEP_HANDLE_INPUT_EVENT_MAIN = 4;
+    STEP_MAIN_THREAD_SCROLL_UPDATE = 2;
+    STEP_HANDLE_INPUT_EVENT_MAIN_COMMIT = 1;
+    // Could be emitted on both the renderer's main OR compositor.
+    STEP_HANDLED_INPUT_EVENT_MAIN_OR_IMPL = 9;
+    // Optionally sometimes HANDLED_INPUT_EVENT_MAIN_OR_IMPL will proxy to the
+    // renderer's compositor and this will be emitted.
+    STEP_HANDLED_INPUT_EVENT_IMPL = 10;
+    // Renderer's compositor.
+    STEP_SWAP_BUFFERS = 6;
+    // Happens on the VizCompositor in the GPU process.
+    STEP_DRAW_AND_SWAP = 7 [deprecated = true];
+    // Happens on the GPU main thread after the swap has completed.
+    STEP_FINISHED_SWAP_BUFFERS = 11 [deprecated = true];
+    // See above for NEXT ID, enum steps are not ordered by tag number.
+  };
+
+  optional Step step = 2;
+  optional int32 frame_tree_node_id = 3;
+
+  // This enum is a copy of LatencyComponentType enum in Chrome, located in
+  // ui/latency/latency_info.h, modulo added UNKNOWN value per protobuf
+  // practices.
+  enum LatencyComponentType {
+    COMPONENT_UNSPECIFIED = 0;
+    COMPONENT_INPUT_EVENT_LATENCY_BEGIN_RWH = 1;
+    COMPONENT_INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL = 2;
+    COMPONENT_INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL = 3;
+    COMPONENT_INPUT_EVENT_LATENCY_ORIGINAL = 4;
+    COMPONENT_INPUT_EVENT_LATENCY_UI = 5;
+    COMPONENT_INPUT_EVENT_LATENCY_RENDERER_MAIN = 6;
+    COMPONENT_INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN = 7;
+    COMPONENT_INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL = 8;
+    COMPONENT_INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT = 9;
+    COMPONENT_INPUT_EVENT_LATENCY_ACK_RWH = 10;
+    COMPONENT_INPUT_EVENT_LATENCY_RENDERER_SWAP = 11;
+    COMPONENT_DISPLAY_COMPOSITOR_RECEIVED_FRAME = 12;
+    COMPONENT_INPUT_EVENT_GPU_SWAP_BUFFER = 13;
+    COMPONENT_INPUT_EVENT_LATENCY_FRAME_SWAP = 14;
+  }
+
+  message ComponentInfo {
+    optional LatencyComponentType component_type = 1;
+
+    // Microsecond timestamp in CLOCK_MONOTONIC domain
+    optional uint64 time_us = 2;
+  };
+
+  repeated ComponentInfo component_info = 4;
+  optional bool is_coalesced = 5;
+  optional int64 gesture_scroll_id = 6;
+  optional int64 touch_id = 7;
+
+  enum InputType {
+    UNSPECIFIED_OR_OTHER = 0;
+    TOUCH_MOVED = 1;
+    GESTURE_SCROLL_BEGIN = 2;
+    GESTURE_SCROLL_UPDATE = 3;
+    GESTURE_SCROLL_END = 4;
+    GESTURE_TAP = 5;
+    GESTURE_TAP_CANCEL = 6;
+  }
+
+  // The type of input corresponding to this `ChromeLatencyInfo`.
+  optional InputType input_type = 8;
+}
+
 message ChromeTrackEvent {
   // Extension range for Chrome: 1000-1999
-  // Next ID: 1068
+  // Next ID: 1069
   extend TrackEvent {
     optional ChromeAppState chrome_app_state = 1000;
 
@@ -2125,5 +2208,7 @@
     optional ScrollMetrics scroll_metrics = 1066;
 
     optional MainFramePipeline main_frame_pipeline = 1067;
+
+    optional ChromeLatencyInfo2 chrome_latency_info = 1068;
   }
 }
diff --git a/build/OWNERS b/build/OWNERS
index 25b0e7e..93a042c1 100644
--- a/build/OWNERS
+++ b/build/OWNERS
@@ -4,7 +4,6 @@
 agrieve@chromium.org
 brucedawson@chromium.org
 dpranke@google.com
-jochen@chromium.org
 sdefresne@chromium.org
 thakis@chromium.org
 thomasanderson@chromium.org
diff --git a/build/OWNERS.status b/build/OWNERS.status
index f5cc1fc..e9fcfb0 100644
--- a/build/OWNERS.status
+++ b/build/OWNERS.status
@@ -9,4 +9,3 @@
 #  you@chromium.org: Single line status message.
 #
 
-jochen@chromium.org: EMEA based reviewer.
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index 56b47fe..aca3737 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -59,6 +59,8 @@
     r'Missing class android.adservices.common.AdServicesOutcomeReceiver',
     # We enforce that this class is removed via -checkdiscard.
     r'FastServiceLoader\.class:.*Could not inline ServiceLoader\.load',
+    # Happens on internal builds. It's a real failure, but happens in dead code.
+    r'(?:GeneratedExtensionRegistryLoader|ExtensionRegistryLite)\.class:.*Could not inline ServiceLoader\.load',   # pylint: disable=line-too-long
 
     # Ignore MethodParameter attribute count isn't matching in espresso.
     # This is a banner warning and each individual file affected will have
diff --git a/build/android/gyp/util/resources_parser.py b/build/android/gyp/util/resources_parser.py
index ec3495f..8551370 100644
--- a/build/android/gyp/util/resources_parser.py
+++ b/build/android/gyp/util/resources_parser.py
@@ -19,7 +19,7 @@
 
 
 def _ResourceNameToJavaSymbol(resource_name):
-  return re.sub('[\.:]', '_', resource_name)
+  return re.sub(r'[\.:]', '_', resource_name)
 
 
 class RTxtGenerator:
diff --git a/build/android/java/templates/BuildConfig.template b/build/android/java/templates/BuildConfig.template
index 2efb64d2..59ad4da 100644
--- a/build/android/java/templates/BuildConfig.template
+++ b/build/android/java/templates/BuildConfig.template
@@ -59,10 +59,10 @@
     public static long VERSION_CODE = 1;
 #endif
 
-#if defined(_BUNDLES_SUPPORTED)
-    public static boolean BUNDLES_SUPPORTED = true;
+#if defined(_IS_BUNDLE)
+    public static boolean IS_BUNDLE = true;
 #else
-    public static boolean BUNDLES_SUPPORTED;
+    public static boolean IS_BUNDLE;
 #endif
 
 #if defined(_IS_INCREMENTAL_INSTALL)
@@ -71,12 +71,6 @@
     public static boolean IS_INCREMENTAL_INSTALL;
 #endif
 
-#if defined(_ISOLATED_SPLITS_ENABLED)
-    public static boolean ISOLATED_SPLITS_ENABLED = true;
-#else
-    public static boolean ISOLATED_SPLITS_ENABLED;
-#endif
-
 #if defined(_IS_FOR_TEST)
     public static boolean IS_FOR_TEST = true;
 #else
diff --git a/build/android/java/templates/ProductConfig.template b/build/android/java/templates/ProductConfig.template
index d6e1236b..05d9b51 100644
--- a/build/android/java/templates/ProductConfig.template
+++ b/build/android/java/templates/ProductConfig.template
@@ -7,11 +7,9 @@
 #if defined(USE_FINAL)
 #define MAYBE_FINAL final
 #define MAYBE_USE_CHROMIUM_LINKER = USE_CHROMIUM_LINKER_VALUE
-#define MAYBE_IS_BUNDLE = IS_BUNDLE_VALUE
 #else
 #define MAYBE_FINAL
 #define MAYBE_USE_CHROMIUM_LINKER
-#define MAYBE_IS_BUNDLE
 #endif
 
 /**
@@ -27,5 +25,4 @@
 #endif
 
    public static MAYBE_FINAL boolean USE_CHROMIUM_LINKER MAYBE_USE_CHROMIUM_LINKER;
-   public static MAYBE_FINAL boolean IS_BUNDLE MAYBE_IS_BUNDLE;
 }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 470b780..3b5eb1f3 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1899,8 +1899,8 @@
         defines += [ "_IS_CHROME_BRANDED" ]
       }
 
-      if (defined(invoker.bundles_supported) && invoker.bundles_supported) {
-        defines += [ "_BUNDLES_SUPPORTED" ]
+      if (defined(invoker.is_bundle) && invoker.is_bundle) {
+        defines += [ "_IS_BUNDLE" ]
       }
 
       if (defined(invoker.isolated_splits_enabled) &&
@@ -1970,7 +1970,6 @@
   #
   # Variables:
   #   build_config: Path to build_config used for locale lists.
-  #   is_bundle_module: Whether or not this target is part of a bundle build.
   #   java_package: Java package for the generated class.
   #   use_chromium_linker:
   template("generate_product_config_srcjar") {
@@ -1988,11 +1987,7 @@
 
       _use_chromium_linker =
           defined(invoker.use_chromium_linker) && invoker.use_chromium_linker
-      _is_bundle = defined(invoker.is_bundle_module) && invoker.is_bundle_module
-      defines += [
-        "USE_CHROMIUM_LINKER_VALUE=$_use_chromium_linker",
-        "IS_BUNDLE_VALUE=$_is_bundle",
-      ]
+      defines += [ "USE_CHROMIUM_LINKER_VALUE=$_use_chromium_linker" ]
       if (defined(invoker.build_config)) {
         forward_variables_from(invoker, TESTONLY_AND_VISIBILITY + [ "deps" ])
         _rebased_build_config =
@@ -2629,11 +2624,7 @@
                                  "disable_strict_mode_context",
                                  "isolated_splits_enabled",
                                ])
-        _bundles_supported = _is_bundle_module
-        if (defined(invoker.bundles_supported)) {
-          _bundles_supported = invoker.bundles_supported
-        }
-        bundles_supported = _bundles_supported
+        is_bundle = _is_bundle_module
         assertions_implicitly_enabled = _assertions_implicitly_enabled
         is_incremental_install = _incremental_apk
         version_code = _version_code
@@ -2662,7 +2653,6 @@
         _locale_target_name =
             "${_template_name}_${_package}__product_config_srcjar"
         generate_product_config_srcjar("$_locale_target_name") {
-          forward_variables_from(invoker, [ "is_bundle_module" ])
           build_config = _build_config
           java_package = _package
           use_chromium_linker = _use_chromium_linker
diff --git a/build/config/unsafe_buffers_paths.txt b/build/config/unsafe_buffers_paths.txt
index bec2a8a1..4ca2724 100644
--- a/build/config/unsafe_buffers_paths.txt
+++ b/build/config/unsafe_buffers_paths.txt
@@ -113,7 +113,6 @@
 -gpu/ipc/service/
 -ios/
 -ios_internal/
--media/
 -native_client/
 -net/third_party/
 -printing/
diff --git a/build/fuchsia/sdk-hash-files.list b/build/fuchsia/sdk-hash-files.list
deleted file mode 100644
index 6f37bcd..0000000
--- a/build/fuchsia/sdk-hash-files.list
+++ /dev/null
@@ -1 +0,0 @@
-{platform}.sdk.sha1
diff --git a/build/util/lib/proto/measures.py b/build/util/lib/proto/measures.py
index 33fcfeed..5742753 100755
--- a/build/util/lib/proto/measures.py
+++ b/build/util/lib/proto/measures.py
@@ -9,7 +9,7 @@
 import os
 
 from google.protobuf import any_pb2
-from google.protobuf.json_format import MessageToJson
+from google.protobuf.json_format import MessageToDict
 
 from average import Average
 from count import Count
@@ -18,9 +18,13 @@
 from metric import Metric
 from time_consumption import TimeConsumption
 
+# This is used as the key when being uploaded to ResultDB via result_sink
+# and shouldn't be changed
+TEST_SCRIPT_METRICS_KEY = 'test_script_metrics'
+
 # The file name is used as the key when being loaded into the ResultDB and
 # shouldn't be changed.
-TEST_SCRIPT_METRICS_JSONPB_FILENAME = 'test_script_metrics.jsonpb'
+TEST_SCRIPT_METRICS_JSONPB_FILENAME = f'{TEST_SCRIPT_METRICS_KEY}.jsonpb'
 
 _metric = Metric()
 
@@ -52,17 +56,37 @@
   return _register(TimeConsumption(_create_name(*name_pieces)))
 
 
+def clear() -> None:
+  """Clear all the registered Measures."""
+  _metric.clear()
+
+
+def size() -> int:
+  """Get the current size of registered Measures."""
+  return _metric.size()
+
+def to_dict() -> dict:
+  """Convert all the registered Measures to a dict.
+
+  The records are wrapped in protobuf Any message before exported as dict
+  so that an additional key "@type" is included.
+  """
+  any_msg = any_pb2.Any()
+  any_msg.Pack(_metric.dump())
+  return MessageToDict(any_msg, preserving_proto_field_name=True)
+
+
+def to_json() -> str:
+  """Convert all the registered Measures to a json str."""
+  return json.dumps(to_dict(), sort_keys=True, indent=2)
+
 # TODO(crbug.com/343242386): May need to implement a lock and reset logic to
 # clear in-memory data and lock the instance to block further operations and
 # avoid accidentally accumulating data which won't be published at all.
 def dump(dir_path: str) -> None:
   """Dumps the metric data into test_script_metrics.jsonpb in the |path|."""
   os.makedirs(dir_path, exist_ok=True)
-  any_msg = any_pb2.Any()
-  any_msg.Pack(_metric.dump())
   with open(os.path.join(dir_path, TEST_SCRIPT_METRICS_JSONPB_FILENAME),
             'w',
             encoding='utf-8') as wf:
-    wf.write(
-        MessageToJson(any_msg, preserving_proto_field_name=True,
-                      sort_keys=True))
+    wf.write(to_json())
diff --git a/build/util/lib/proto/metric.py b/build/util/lib/proto/metric.py
index 9751cf19..a3d28b84 100755
--- a/build/util/lib/proto/metric.py
+++ b/build/util/lib/proto/metric.py
@@ -17,6 +17,12 @@
   def register(self, metric: Measure) -> None:
     self._metrics.append(metric)
 
+  def size(self) -> int:
+    return len(self._metrics)
+
+  def clear(self) -> None:
+    self._metrics.clear()
+
   def dump(self) -> TestScriptMetrics:
     result = TestScriptMetrics()
     result.metrics.extend([m.dump() for m in self._metrics])
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
index de4b1d1..c0c5d06a 100644
--- a/buildtools/deps_revisions.gni
+++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # Used to cause full rebuilds on libc++ rolls. This should be kept in sync
   # with the libcxx_revision vars in //DEPS.
-  libcxx_revision = "7ef1f0a187aa3320426084c19e42833568f779a9"
+  libcxx_revision = "9be1056e883d3fe5cd6666ac69702a6c5e9a39df"
 }
diff --git a/cc/input/input_handler.cc b/cc/input/input_handler.cc
index 86c75e08..8f4a8dc 100644
--- a/cc/input/input_handler.cc
+++ b/cc/input/input_handler.cc
@@ -64,6 +64,12 @@
 InputHandlerCommitData::InputHandlerCommitData() = default;
 InputHandlerCommitData::~InputHandlerCommitData() = default;
 
+// The minimum amount of scroll delta that must be consumed before we consider
+// a scroll to have happened.
+// TODO(tdresser): Use a more rational epsilon. See crbug.com/510550 for
+// details.
+const float kScrollEpsilon = 0.1f;
+
 // static
 base::WeakPtr<InputHandler> InputHandler::Create(
     CompositorDelegateForInput& compositor_delegate) {
@@ -1643,9 +1649,6 @@
   gfx::Vector2dF applied_delta;
   gfx::Vector2dF delta_applied_to_content;
   std::optional<gfx::PointF> snap_strategy_offset;
-  // TODO(tdresser): Use a more rational epsilon. See crbug.com/510550 for
-  // details.
-  const float kEpsilon = 0.1f;
 
   if (ShouldAnimateScroll(scroll_state)) {
     DCHECK(!scroll_state.is_in_inertial_phase());
@@ -1690,14 +1693,7 @@
       if (scroll_node.scrolls_outer_viewport) {
         auto result = GetViewport().ScrollAnimated(delta, delayed_by);
         applied_delta = result.consumed_delta;
-        if (std::abs(result.outer_viewport_scrolled_delta.x()) > kEpsilon ||
-            std::abs(result.outer_viewport_scrolled_delta.y()) > kEpsilon) {
-          outer_viewport_consumed_delta_ = true;
-        }
-        if (std::abs(result.inner_viewport_scrolled_delta.x()) > kEpsilon ||
-            std::abs(result.inner_viewport_scrolled_delta.y()) > kEpsilon) {
-          inner_viewport_consumed_delta_ = true;
-        }
+        SetViewportConsumedDelta(result);
       } else {
         applied_delta = ComputeScrollDelta(scroll_node, delta);
         compositor_delegate_->GetImplDeprecated().ScrollAnimationCreate(
@@ -1723,21 +1719,14 @@
       // want to scroll *only* the inner viewport -- to allow panning while
       // zoomed -- but still use Viewport::ScrollBy to also move browser
       // controls if needed.
-      Viewport::ScrollResult result = GetViewport().ScrollBy(
+      ViewportScrollResult result = GetViewport().ScrollBy(
           delta, viewport_point, scroll_state.is_direct_manipulation(),
           latched_scroll_type_ != ui::ScrollInputType::kWheel,
           scroll_node.scrolls_outer_viewport);
 
       applied_delta = result.consumed_delta;
       delta_applied_to_content = result.content_scrolled_delta;
-      if (std::abs(result.outer_viewport_scrolled_delta.x()) > kEpsilon ||
-          std::abs(result.outer_viewport_scrolled_delta.y()) > kEpsilon) {
-        outer_viewport_consumed_delta_ = true;
-      }
-      if (std::abs(result.inner_viewport_scrolled_delta.x()) > kEpsilon ||
-          std::abs(result.inner_viewport_scrolled_delta.y()) > kEpsilon) {
-        inner_viewport_consumed_delta_ = true;
-      }
+      SetViewportConsumedDelta(result);
     } else {
       applied_delta = ScrollSingleNode(scroll_node, delta, viewport_point,
                                        scroll_state.is_direct_manipulation());
@@ -1747,8 +1736,8 @@
   overscroll_delta_for_main_thread_ += delta - applied_delta;
 
   // If the layer wasn't able to move, try the next one in the hierarchy.
-  bool scrolled = std::abs(applied_delta.x()) > kEpsilon;
-  scrolled = scrolled || std::abs(applied_delta.y()) > kEpsilon;
+  bool scrolled = std::abs(applied_delta.x()) > kScrollEpsilon;
+  scrolled = scrolled || std::abs(applied_delta.y()) > kScrollEpsilon;
   if (!scrolled) {
     // TODO(bokan): This preserves existing behavior by not allowing tiny
     // scrolls to produce overscroll but is inconsistent in how delta gets
@@ -1775,8 +1764,8 @@
   }
 
   scroll_state.set_caused_scroll(
-      std::abs(delta_applied_to_content.x()) > kEpsilon,
-      std::abs(delta_applied_to_content.y()) > kEpsilon);
+      std::abs(delta_applied_to_content.x()) > kScrollEpsilon,
+      std::abs(delta_applied_to_content.y()) > kScrollEpsilon);
   scroll_state.ConsumeDelta(applied_delta.x(), applied_delta.y());
 
   did_scroll_x_for_scroll_gesture_ |= scroll_state.caused_scroll_x();
@@ -1993,11 +1982,10 @@
   if (scroll_node->scrolls_outer_viewport) {
     gfx::Vector2dF scaled_delta(delta);
     scaled_delta.Scale(compositor_delegate_->PageScaleFactor());
-    gfx::Vector2dF consumed_delta =
-        GetViewport()
-            .ScrollAnimated(scaled_delta, base::TimeDelta())
-            .consumed_delta;
+    auto result = GetViewport().ScrollAnimated(scaled_delta, base::TimeDelta());
+    gfx::Vector2dF consumed_delta = result.consumed_delta;
     did_animate = !consumed_delta.IsZero();
+    SetViewportConsumedDelta(result);
   } else {
     did_animate =
         compositor_delegate_->GetImplDeprecated().ScrollAnimationCreate(
@@ -2180,4 +2168,16 @@
   }
 }
 
+void InputHandler::SetViewportConsumedDelta(
+    const ViewportScrollResult& result) {
+  if (std::abs(result.outer_viewport_scrolled_delta.x()) > kScrollEpsilon ||
+      std::abs(result.outer_viewport_scrolled_delta.y()) > kScrollEpsilon) {
+    outer_viewport_consumed_delta_ = true;
+  }
+  if (std::abs(result.inner_viewport_scrolled_delta.x()) > kScrollEpsilon ||
+      std::abs(result.inner_viewport_scrolled_delta.y()) > kScrollEpsilon) {
+    inner_viewport_consumed_delta_ = true;
+  }
+}
+
 }  // namespace cc
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index a73cfb0f..38f8d71 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -266,6 +266,23 @@
     bool viewport_cannot_scroll = false;
   };
 
+  // ViewportScrollResult records, for a scroll gesture affecting a page's
+  // viewport:
+  // - the amount from the scroll gesture's delta that actually resulted in
+  //   scrolling: |consumed_delta|,
+  // - the amount from the scroll gesture's delta that applied to the content of
+  //   the page, i.e. excluding movement of browser controls.
+  // - the distribution of the scroll gesture's delta between the inner and
+  //   outer viewports, {inner,outer}_viewport_consumed_delta_
+  // TODO(tdresser): eventually |consumed_delta| should equal
+  // |content_scrolled_delta|. See crbug.com/510045 for details.
+  struct ViewportScrollResult {
+    gfx::Vector2dF consumed_delta;
+    gfx::Vector2dF content_scrolled_delta;
+    gfx::Vector2dF outer_viewport_scrolled_delta;
+    gfx::Vector2dF inner_viewport_scrolled_delta;
+  };
+
   enum class TouchStartOrMoveEventListenerType {
     kNoHandler,
     kHandler,
@@ -502,6 +519,10 @@
     return snap_strategy_;
   }
 
+  // Detects whether or not the scroll generating the |result| affected the
+  // inner or outer viewports.
+  void SetViewportConsumedDelta(const ViewportScrollResult& result);
+
   // =========== InputDelegateForCompositor Interface - This section implements
   // the interface that LayerTreeHostImpl uses to communicate with the input
   // system.
diff --git a/cc/layers/viewport.h b/cc/layers/viewport.h
index 1cfa641..c1ba3632 100644
--- a/cc/layers/viewport.h
+++ b/cc/layers/viewport.h
@@ -33,20 +33,13 @@
 // we should still scroll using this class.
 class CC_EXPORT Viewport {
  public:
+  using ScrollResult = InputHandler::ViewportScrollResult;
+
   // If the pinch zoom anchor on the first PinchUpdate is within this length
   // of the screen edge, "snap" the zoom to that edge. Experimentally
   // determined.
   static const int kPinchZoomSnapMarginDips = 100;
 
-  // TODO(tdresser): eventually |consumed_delta| should equal
-  // |content_scrolled_delta|. See crbug.com/510045 for details.
-  struct ScrollResult {
-    gfx::Vector2dF consumed_delta;
-    gfx::Vector2dF content_scrolled_delta;
-    gfx::Vector2dF outer_viewport_scrolled_delta;
-    gfx::Vector2dF inner_viewport_scrolled_delta;
-  };
-
   static std::unique_ptr<Viewport> Create(LayerTreeHostImpl* host_impl);
 
   Viewport(const Viewport&) = delete;
diff --git a/cc/trees/latency_info_swap_promise.cc b/cc/trees/latency_info_swap_promise.cc
index e5ea0595..7e8bc133 100644
--- a/cc/trees/latency_info_swap_promise.cc
+++ b/cc/trees/latency_info_swap_promise.cc
@@ -42,19 +42,20 @@
 
 // Trace the original LatencyInfo of a LatencyInfoSwapPromise
 void LatencyInfoSwapPromise::OnCommit() {
-  using perfetto::protos::pbzero::ChromeLatencyInfo;
   using perfetto::protos::pbzero::TrackEvent;
 
-  TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
-              [this](perfetto::EventContext ctx) {
-                ChromeLatencyInfo* latency_info =
-                    ctx.event()->set_chrome_latency_info();
-                latency_info->set_trace_id(GetTraceId());
-                latency_info->set_step(
-                    ChromeLatencyInfo::STEP_HANDLE_INPUT_EVENT_MAIN_COMMIT);
-                tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_INOUT,
-                                       GetTraceId());
-              });
+  TRACE_EVENT(
+      "input,benchmark,latencyInfo", "LatencyInfo.Flow",
+      [this](perfetto::EventContext ctx) {
+        auto* latency_info =
+            ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                ->set_chrome_latency_info();
+        latency_info->set_trace_id(GetTraceId());
+        latency_info->set_step(perfetto::protos::pbzero::ChromeLatencyInfo2::
+                                   Step::STEP_HANDLE_INPUT_EVENT_MAIN_COMMIT);
+        tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_INOUT,
+                               GetTraceId());
+      });
 }
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index c19e700..d813fae0 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1147,16 +1147,17 @@
   DCHECK(!in_apply_compositor_changes_);
   base::AutoReset<bool> in_apply_changes(&in_apply_compositor_changes_, true);
 
-  using perfetto::protos::pbzero::ChromeLatencyInfo;
   using perfetto::protos::pbzero::TrackEvent;
 
   for (auto& swap_promise : commit_data->swap_promises) {
     TRACE_EVENT(
         "input,benchmark", "LatencyInfo.Flow",
         [&swap_promise](perfetto::EventContext ctx) {
-          ChromeLatencyInfo* info = ctx.event()->set_chrome_latency_info();
+          auto* info = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                           ->set_chrome_latency_info();
           info->set_trace_id(swap_promise->GetTraceId());
-          info->set_step(ChromeLatencyInfo::STEP_MAIN_THREAD_SCROLL_UPDATE);
+          info->set_step(perfetto::protos::pbzero::ChromeLatencyInfo2::Step::
+                             STEP_MAIN_THREAD_SCROLL_UPDATE);
           tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_INOUT,
                                  swap_promise->GetTraceId());
         });
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 2d0c27f4..2270145 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -279,9 +279,6 @@
 
     if (_is_bundle) {
       is_base_module = true
-
-      # Sets ISOLATED_SPLITS_ENABLED in BuildConfig.java.
-      isolated_splits_enabled = true
     }
 
     product_config_java_packages = [ "org.chromium.chrome.browser" ]
@@ -738,7 +735,6 @@
     }
 
     if (_is_test) {
-      bundles_supported = true
       deps += [ "//third_party/androidx:androidx_test_runner_java" ]
 
       # For EmbeddedTestServer.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
index 839b034..19100e8 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
@@ -55,10 +55,6 @@
                 accessibilityTextId =
                         R.string.iph_tab_groups_tap_to_see_another_tab_accessibility_text;
                 break;
-            case FeatureConstants.TAB_GROUPS_YOUR_TABS_ARE_TOGETHER_FEATURE:
-                textId = R.string.iph_tab_groups_your_tabs_together_text;
-                accessibilityTextId = textId;
-                break;
             default:
                 assert false;
                 return;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
index ceb11c3..39825a3c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
@@ -33,7 +33,6 @@
 import org.chromium.chrome.browser.tab_ui.TabListFaviconProvider;
 import org.chromium.chrome.browser.tab_ui.TabThumbnailView;
 import org.chromium.chrome.browser.tab_ui.TabUiThemeUtils;
-import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.IphProvider;
 import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.TabActionButtonData;
 import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.TabActionButtonData.TabActionButtonType;
 import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.TabActionListener;
@@ -163,9 +162,6 @@
             PropertyModel model, ViewLookupCachingFrameLayout view, PropertyKey propertyKey) {
         if (CARD_ALPHA == propertyKey) {
             view.setAlpha(model.get(CARD_ALPHA));
-        } else if (TabProperties.IPH_PROVIDER == propertyKey) {
-            IphProvider provider = model.get(TabProperties.IPH_PROVIDER);
-            if (provider != null) provider.showIPH(view.fastFindViewById(R.id.tab_thumbnail));
         } else if (TabProperties.CARD_ANIMATION_STATUS == propertyKey) {
             ((TabGridView) view)
                     .scaleTabGridCardView(model.get(TabProperties.CARD_ANIMATION_STATUS));
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index abe495e0e..e7b8547 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -52,8 +52,6 @@
 import org.chromium.base.shared_preferences.SharedPreferencesManager;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.base.task.PostTask;
-import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.browser.data_sharing.DataSharingServiceFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
@@ -96,7 +94,6 @@
 import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate;
 import org.chromium.components.data_sharing.DataSharingService;
 import org.chromium.components.embedder_support.util.UrlUtilities;
-import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
 import org.chromium.components.tab_groups.TabGroupColorId;
@@ -184,11 +181,6 @@
         boolean isReorderAction(int action);
     }
 
-    /** An interface to show IPH for a tab. */
-    public interface IphProvider {
-        void showIPH(View anchor);
-    }
-
     /** Interface for implementing a {@link Runnable} that takes a tabId for a generic action. */
     public interface TabActionListener {
         /** Run the action for the given view and tabId. */
@@ -384,35 +376,12 @@
     // until `postHiding` is invoked or the mediator is destroyed. While true, this mediator is
     // actively tracking updates to a TabModel.
     private boolean mShowingTabs;
-    private boolean mShownIPH;
     private Tab mTabToAddDelayed;
     private RecyclerViewItemAnimationToggle mRecyclerViewItemAnimationToggle;
     private ListObserver<Void> mListObserver;
     private TabGroupTitleEditor mTabGroupTitleEditor;
     private View.AccessibilityDelegate mAccessibilityDelegate;
 
-    private final IphProvider mIphProvider =
-            new IphProvider() {
-                private static final int IPH_DELAY_MS = 1000;
-
-                @Override
-                public void showIPH(View anchor) {
-                    if (mShownIPH) return;
-                    mShownIPH = true;
-
-                    PostTask.postDelayedTask(
-                            TaskTraits.UI_DEFAULT,
-                            () -> {
-                                TabGroupUtils.maybeShowIPH(
-                                        mProfile,
-                                        FeatureConstants.TAB_GROUPS_YOUR_TABS_ARE_TOGETHER_FEATURE,
-                                        anchor,
-                                        null);
-                            },
-                            IPH_DELAY_MS);
-                }
-            };
-
     private final TabActionListener mTabSelectedListener =
             new TabActionListener() {
                 @Override
@@ -2023,11 +1992,7 @@
 
     private void addTabInfoToModel(Tab tab, int index, boolean isSelected) {
         assert index != TabModel.INVALID_TAB_INDEX;
-        boolean showIPH = false;
         boolean isInTabGroup = isTabInTabGroup(tab);
-        if (mActionsOnAllRelatedTabs && !mShownIPH) {
-            showIPH = isInTabGroup;
-        }
 
         int colorId = TabGroupColorUtils.INVALID_COLOR_ID;
         if (ChromeFeatureList.sTabGroupParityAndroid.isEnabled()) {
@@ -2054,7 +2019,6 @@
                         .with(TabProperties.FAVICON_FETCHER, null)
                         .with(TabProperties.FAVICON_FETCHED, false)
                         .with(TabProperties.IS_SELECTED, isSelected)
-                        .with(TabProperties.IPH_PROVIDER, showIPH ? mIphProvider : null)
                         .with(CARD_ALPHA, 1f)
                         .with(
                                 TabProperties.CARD_ANIMATION_STATUS,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
index 116269e9..a1c87e6e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
@@ -13,7 +13,6 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.chrome.browser.tab_ui.TabListFaviconProvider;
-import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.IphProvider;
 import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.ShoppingPersistedTabDataFetcher;
 import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.TabActionButtonData;
 import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.TabActionListener;
@@ -82,9 +81,6 @@
     public static final WritableObjectPropertyKey<Size> GRID_CARD_SIZE =
             new WritableObjectPropertyKey<>();
 
-    public static final WritableObjectPropertyKey<IphProvider> IPH_PROVIDER =
-            new WritableObjectPropertyKey<>();
-
     public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
 
     public static final WritableBooleanPropertyKey IS_SELECTED = new WritableBooleanPropertyKey();
@@ -141,7 +137,6 @@
                 IS_SELECTED,
                 GRID_CARD_SIZE,
                 THUMBNAIL_FETCHER,
-                IPH_PROVIDER,
                 TITLE,
                 CARD_ALPHA,
                 CARD_ANIMATION_STATUS,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java
index 253c7328..39614c2 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java
@@ -219,14 +219,7 @@
             int rootId = info.tabOriginalRootId;
             if (info.tab.getRootId() == rootId) continue;
 
-            filter.deleteTabGroupTitle(rootId);
-
-            if (ChromeFeatureList.sTabGroupParityAndroid.isEnabled()) {
-                filter.deleteTabGroupColor(rootId);
-            }
-            if (ChromeFeatureList.sTabStripGroupCollapse.isEnabled()) {
-                filter.deleteTabGroupCollapsed(rootId);
-            }
+            filter.deleteTabGroupVisualData(rootId);
         }
     }
 
diff --git a/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd b/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd
index 671a0b2c..6cc4b7d 100644
--- a/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd
+++ b/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd
@@ -179,9 +179,6 @@
       <message name="IDS_IPH_TAB_GROUPS_TAP_TO_SEE_ANOTHER_TAB_TEXT" desc="This in-product help text points to the strip of favicons at the bottom of the page. The favicons indicate all the open tabs within the tab group. The text informs the user that they can tap on any favicon to switch to that tab.">
         Tap to see another tab
       </message>
-      <message name="IDS_IPH_TAB_GROUPS_YOUR_TABS_TOGETHER_TEXT" desc="This in-product help text points to a group of tabs within the Tab Switcher. The text informs the user that they can find existing tab groups in the Tab Switcher.">
-        Your tabs are grouped together here
-      </message>
       <message name="IDS_IPH_TAB_GROUPS_TAP_TO_SEE_ANOTHER_TAB_ACCESSIBILITY_TEXT" desc="This in-product help accessibility text points to the strip of favicons at the bottom of the page. The favicons indicate all the open tabs within the tab group. The text informs the user that they can tap on any favicon to switch to that tab.">
         Switch between tabs in your tab group near bottom of screen
       </message>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java
index 6164093..672da54 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java
@@ -78,7 +78,7 @@
             // Only load the native library early for bundle builds since some tests use the
             // "--disable-native-initialization" switch, and the CommandLine is not initialized at
             // this point to check.
-            if (ProductConfig.IS_BUNDLE) {
+            if (BuildConfig.IS_BUNDLE) {
                 // Kick off library loading in a separate thread so it's ready when we need it.
                 new Thread(() -> LibraryLoader.getInstance().ensureInitialized()).start();
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 706f3e9c..a8bcd01 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -119,6 +119,7 @@
 import org.chromium.chrome.browser.hub.HubLayoutDependencyHolder;
 import org.chromium.chrome.browser.hub.HubManager;
 import org.chromium.chrome.browser.hub.HubProvider;
+import org.chromium.chrome.browser.hub.HubShowPaneHelper;
 import org.chromium.chrome.browser.hub.Pane;
 import org.chromium.chrome.browser.hub.PaneId;
 import org.chromium.chrome.browser.incognito.IncognitoNotificationManager;
@@ -1184,7 +1185,9 @@
                 .runSyncOrOnAvailable(
                         (profileProvider) -> {
                             if (mIncognitoCookiesFetcher == null) {
-                                mIncognitoCookiesFetcher = new CookiesFetcher(profileProvider);
+                                mIncognitoCookiesFetcher =
+                                        new CookiesFetcher(
+                                                profileProvider, CipherFactory.getInstance());
                             }
                             IncognitoStartup.onResumeWithNative(
                                     profileProvider,
@@ -2281,8 +2284,11 @@
                             this,
                             mRootUiCoordinator.getBottomSheetController(),
                             getModalDialogManagerSupplier(),
-                            () -> {
+                            (paneId) -> {
                                 if (mLayoutManager != null) {
+                                    HubShowPaneHelper hubShowPaneHelper =
+                                            mHubProvider.getHubShowPaneHelper();
+                                    hubShowPaneHelper.setPaneToShow(paneId);
                                     mLayoutManager.showLayout(LayoutType.TAB_SWITCHER, false);
                                 }
                             },
@@ -2308,7 +2314,8 @@
         boolean tabMergingEnabled =
                 mMultiInstanceManager != null && mMultiInstanceManager.isTabModelMergingEnabled();
         mTabModelOrchestrator =
-                new TabbedModeTabModelOrchestrator(tabMergingEnabled, getLifecycleDispatcher());
+                new TabbedModeTabModelOrchestrator(
+                        tabMergingEnabled, getLifecycleDispatcher(), CipherFactory.getInstance());
         if (ChromeFeatureList.sTabStripStartupRefactoring.isEnabled()) {
             mTabModelStartupInfoSupplier = new ObservableSupplierImpl<>();
             mTabModelOrchestrator.setStartupInfoObservableSupplier(mTabModelStartupInfoSupplier);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java
index d5c640b..333004f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java
@@ -23,6 +23,7 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskRunner;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -246,7 +247,9 @@
      * to do.
      */
     public void maybeCreateAndInitTabModels(
-            TabContentManager tabContentManager, TabCreator regularTabCreator) {
+            TabContentManager tabContentManager,
+            TabCreator regularTabCreator,
+            CipherFactory cipherFactory) {
         if (mInitCalled) return;
         ThreadUtils.assertOnUiThread();
         assert tabContentManager != null;
@@ -285,7 +288,8 @@
                         mTabPersistencePolicy,
                         mTabModelSelector,
                         mArchivedTabCreatorManager,
-                        mTabWindowManager) {
+                        mTabWindowManager,
+                        cipherFactory) {
                     @Override
                     protected void recordLegacyTabCountMetrics() {
                         // Intentional no-op.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java
index 5d967567..c95c2c55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.app.tabmodel;
 
 import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 import org.chromium.chrome.browser.flags.ActivityType;
 import org.chromium.chrome.browser.profiles.ProfileProvider;
@@ -35,7 +36,8 @@
             TabModelFilterFactory tabModelFilterFactory,
             TabPersistencePolicy persistencePolicy,
             @ActivityType int activityType,
-            AsyncTabParamsManager asyncTabParamsManager) {
+            AsyncTabParamsManager asyncTabParamsManager,
+            CipherFactory cipherFactory) {
         // Instantiate TabModelSelectorImpl
         NextTabPolicySupplier nextTabPolicySupplier = () -> NextTabPolicy.LOCATIONAL;
         mTabModelSelector =
@@ -57,7 +59,8 @@
                         mTabPersistencePolicy,
                         mTabModelSelector,
                         tabCreatorManager,
-                        TabWindowManagerSingleton.getInstance());
+                        TabWindowManagerSingleton.getInstance(),
+                        cipherFactory);
 
         wireSelectorAndStore();
         markTabModelsInitialized();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java
index 0306364..53c67f20 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java
@@ -12,6 +12,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.browser.DeferredStartupHandler;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiInstanceManager;
@@ -37,6 +38,7 @@
 public class TabbedModeTabModelOrchestrator extends TabModelOrchestrator {
     private final boolean mTabMergingEnabled;
     private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
+    private final CipherFactory mCipherFactory;
 
     // This class is driven by TabbedModeTabModelOrchestrator to prevent duplicate glue code in
     //  ChromeTabbedActivity.
@@ -50,11 +52,15 @@
      * @param tabMergingEnabled Whether we are on the platform where tab merging is enabled.
      * @param activityLifecycleDispatcher Used to determine if the current activity context is still
      *     valid when running deferred tasks.
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      */
     public TabbedModeTabModelOrchestrator(
-            boolean tabMergingEnabled, ActivityLifecycleDispatcher activityLifecycleDispatcher) {
+            boolean tabMergingEnabled,
+            ActivityLifecycleDispatcher activityLifecycleDispatcher,
+            CipherFactory cipherFactory) {
         mTabMergingEnabled = tabMergingEnabled;
         mActivityLifecycleDispatcher = activityLifecycleDispatcher;
+        mCipherFactory = cipherFactory;
     }
 
     /**
@@ -122,7 +128,8 @@
                         mTabPersistencePolicy,
                         mTabModelSelector,
                         tabCreatorManager,
-                        TabWindowManagerSingleton.getInstance());
+                        TabWindowManagerSingleton.getInstance(),
+                        mCipherFactory);
 
         wireSelectorAndStore();
         markTabModelsInitialized();
@@ -202,7 +209,7 @@
         TabCreator regularTabCreator = mTabCreatorManager.getTabCreator(/* incognito= */ false);
         mArchivedTabModelOrchestrator = ArchivedTabModelOrchestrator.getForProfile(profile);
         mArchivedTabModelOrchestrator.maybeCreateAndInitTabModels(
-                tabContentManager, regularTabCreator);
+                tabContentManager, regularTabCreator, mCipherFactory);
         mArchivedTabModelOrchestrator.initializeHistoricalTabModelObserver(
                 () -> getTabModelSelector().getModel(/* incognito= */ false));
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
index 4017700..7f15ed2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
@@ -79,7 +79,7 @@
             Log.w(TAG, "Triggering dex compile. Reason=%d", reason);
             try {
                 String cmd = "/system/bin/cmd package compile -r shared ";
-                if (reason == DexFixerReason.NOT_READABLE && BuildConfig.ISOLATED_SPLITS_ENABLED) {
+                if (reason == DexFixerReason.NOT_READABLE && BuildConfig.IS_BUNDLE) {
                     // Isolated processes need only access the base split.
                     String apkBaseName = new File(appInfo.sourceDir).getName();
                     cmd += String.format("--split %s ", apkBaseName);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
index 58541450..1236669 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
@@ -135,7 +135,7 @@
                 VersionConstants.PRODUCT_VERSION,
                 BuildConfig.VERSION_CODE,
                 BuildConfig.MIN_SDK_VERSION,
-                ProductConfig.IS_BUNDLE,
+                BuildConfig.IS_BUNDLE,
                 ContextUtils.getProcessName(),
                 isIsolatedProcess);
 
@@ -189,7 +189,6 @@
         }
 
         maybeInitProcessType();
-        BundleUtils.setIsBundle(ProductConfig.IS_BUNDLE);
 
         if (isBrowserProcess) {
             performBrowserProcessPreloading(context);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index 50bf2e4..03babc8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -40,6 +40,7 @@
 import org.chromium.chrome.browser.browserservices.intents.WebappExtras;
 import org.chromium.chrome.browser.browserservices.ui.controller.Verifier;
 import org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityCoordinator;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabController;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabFactory;
@@ -304,13 +305,15 @@
                                 mNightModeStateController,
                                 intentIgnoringCriterion,
                                 getTopUiThemeColorProvider(),
-                                new DefaultBrowserProviderImpl())
+                                new DefaultBrowserProviderImpl(),
+                                CipherFactory.getInstance())
                         : new BaseCustomTabActivityModule(
                                 mIntentDataProvider,
                                 mNightModeStateController,
                                 intentIgnoringCriterion,
                                 getTopUiThemeColorProvider(),
-                                new DefaultBrowserProviderImpl());
+                                new DefaultBrowserProviderImpl(),
+                                CipherFactory.getInstance());
         BaseCustomTabActivityComponent component =
                 ChromeApplicationImpl.getComponent()
                         .createBaseCustomTabActivityComponent(commonsModule, baseCustomTabsModule);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java
index 913ecb0d..dafe3aea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabTabPersistencePolicy;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
@@ -59,6 +60,7 @@
     private final TabCreatorManager mTabCreatorManager;
     private final Supplier<TabModelSelector> mTabModelSelectorSupplier;
     private final Supplier<CompositorViewHolder> mCompositorViewHolderSupplier;
+    private final CipherFactory mCipherFactory;
 
     private final Lazy<AsyncTabParamsManager> mAsyncTabParamsManager;
 
@@ -77,7 +79,8 @@
             Lazy<AsyncTabParamsManager> asyncTabParamsManager,
             TabCreatorManager tabCreatorManager,
             Supplier<TabModelSelector> tabModelSelectorSupplier,
-            Supplier<CompositorViewHolder> compositorViewHolderSupplier) {
+            Supplier<CompositorViewHolder> compositorViewHolderSupplier,
+            CipherFactory cipherFactory) {
         mActivity = activity;
         mPersistencePolicy = persistencePolicy;
         mTabModelFilterFactory = tabModelFilterFactory;
@@ -89,6 +92,7 @@
         mTabCreatorManager = tabCreatorManager;
         mTabModelSelectorSupplier = tabModelSelectorSupplier;
         mCompositorViewHolderSupplier = compositorViewHolderSupplier;
+        mCipherFactory = cipherFactory;
     }
 
     public void setActivityType(int activityType) {
@@ -115,7 +119,8 @@
                 mTabModelFilterFactory,
                 mPersistencePolicy,
                 mActivityType,
-                mAsyncTabParamsManager.get());
+                mAsyncTabParamsManager.get(),
+                mCipherFactory);
     }
 
     /** Returns the previously created {@link TabModelSelector}. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/BaseCustomTabActivityModule.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/BaseCustomTabActivityModule.java
index 9487229..9668bcc7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/BaseCustomTabActivityModule.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/BaseCustomTabActivityModule.java
@@ -19,6 +19,7 @@
 import org.chromium.chrome.browser.browserservices.ui.controller.webapps.WebApkVerifier;
 import org.chromium.chrome.browser.browserservices.verification.ChromeOriginVerifierFactory;
 import org.chromium.chrome.browser.browserservices.verification.ChromeOriginVerifierFactoryImpl;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabNightModeStateController;
 import org.chromium.chrome.browser.customtabs.DefaultBrowserProviderImpl;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController;
@@ -40,19 +41,22 @@
     private final TopUiThemeColorProvider mTopUiThemeColorProvider;
     private final CustomTabActivityNavigationController.DefaultBrowserProvider
             mDefaultBrowserProvider;
+    private final CipherFactory mCipherFactory;
 
     public BaseCustomTabActivityModule(
             BrowserServicesIntentDataProvider intentDataProvider,
             CustomTabNightModeStateController nightModeController,
             IntentIgnoringCriterion intentIgnoringCriterion,
             TopUiThemeColorProvider topUiThemeColorProvider,
-            CustomTabActivityNavigationController.DefaultBrowserProvider defaultBrowserProvider) {
+            CustomTabActivityNavigationController.DefaultBrowserProvider defaultBrowserProvider,
+            CipherFactory cipherFactory) {
         mIntentDataProvider = intentDataProvider;
         mActivityType = intentDataProvider.getActivityType();
         mNightModeController = nightModeController;
         mIntentIgnoringCriterion = intentIgnoringCriterion;
         mTopUiThemeColorProvider = topUiThemeColorProvider;
         mDefaultBrowserProvider = defaultBrowserProvider;
+        mCipherFactory = cipherFactory;
     }
 
     @Provides
@@ -124,6 +128,11 @@
     }
 
     @Provides
+    public CipherFactory provideCipherFactory() {
+        return mCipherFactory;
+    }
+
+    @Provides
     public IncognitoTabHostRegistry provideIncognitoTabHostRegistry() {
         return IncognitoTabHostRegistry.getInstance();
     }
@@ -134,6 +143,7 @@
                 CustomTabNightModeStateController nightModeController,
                 IntentIgnoringCriterion intentIgnoringCriterion,
                 TopUiThemeColorProvider topUiThemeColorProvider,
-                DefaultBrowserProviderImpl customTabDefaultBrowserProvider);
+                DefaultBrowserProviderImpl customTabDefaultBrowserProvider,
+                CipherFactory cipherFactory);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index 37f359d..8935f3b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -117,8 +117,6 @@
 import org.chromium.components.optimization_guide.proto.HintsProto;
 import org.chromium.components.policy.CombinedPolicyProvider;
 import org.chromium.components.safe_browsing.SafeBrowsingApiBridge;
-import org.chromium.components.signin.AccountManagerFacadeImpl;
-import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.webapps.AppBannerManager;
 import org.chromium.content_public.browser.ChildProcessLauncherHelper;
 import org.chromium.content_public.browser.ContactsPicker;
@@ -212,11 +210,6 @@
     /** Performs the shared class initialization. */
     @CallSuper
     protected void handlePreNativeInitialization() {
-        // Initialize the AccountManagerFacade with the correct AccountManagerDelegate. Must be done
-        // only once and before AccountManagerFacadeProvider.getInstance() is invoked.
-        AccountManagerFacadeProvider.setInstance(
-                new AccountManagerFacadeImpl(AppHooks.get().createAccountManagerDelegate()));
-
         setProcessStateSummaryForAnrs(false);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index 541ba98..3dc4680 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -32,6 +32,7 @@
 import org.chromium.base.task.SequencedTaskRunner;
 import org.chromium.base.task.TaskRunner;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
@@ -301,6 +302,7 @@
     private final TabModelSelector mTabModelSelector;
     private final TabCreatorManager mTabCreatorManager;
     private final TabWindowManager mTabWindowManager;
+    private final CipherFactory mCipherFactory;
     private final ObserverList<TabPersistentStoreObserver> mObservers;
 
     private final Deque<Tab> mTabsToSave;
@@ -342,18 +344,22 @@
      * @param clientTag The client tag used to record metrics.
      * @param modelSelector The {@link TabModelSelector} to restore to and save from.
      * @param tabCreatorManager The {@link TabCreatorManager} to use.
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      */
     public TabPersistentStore(
             String clientTag,
             TabPersistencePolicy policy,
             TabModelSelector modelSelector,
             TabCreatorManager tabCreatorManager,
-            TabWindowManager tabWindowManager) {
+            TabWindowManager tabWindowManager,
+            CipherFactory cipherFactory) {
         mClientTag = clientTag;
         mPersistencePolicy = policy;
         mTabModelSelector = modelSelector;
         mTabCreatorManager = tabCreatorManager;
         mTabWindowManager = tabWindowManager;
+        mCipherFactory = cipherFactory;
+
         mTabsToSave = new ArrayDeque<>();
         mTabsToMigrate = new ArrayDeque<>();
         mTabsToRestore = new ArrayDeque<>();
@@ -454,7 +460,8 @@
                 try {
                     TabState state = TabStateExtractor.from(tab);
                     if (state != null) {
-                        TabStateFileManager.saveState(getStateDirectory(), state, id, incognito);
+                        TabStateFileManager.saveState(
+                                getStateDirectory(), state, id, incognito, mCipherFactory);
                         if (isFlatBufferSchemaEnabled()
                                 && TabStateFileManager.isMigrated(
                                         getStateDirectory(), id, incognito)) {
@@ -462,7 +469,7 @@
                             // Otherwise if the user restarts and is in the experiment, they may
                             // have the Tab restored using an out of date FlatBuffer file.
                             TabStateFileManager.migrateTabState(
-                                    getStateDirectory(), state, id, incognito);
+                                    getStateDirectory(), state, id, incognito, mCipherFactory);
                             // No longer need to migrate the Tab as it was just migrated.
                             tabsToMigrateCopy.remove(tab);
                         }
@@ -503,7 +510,7 @@
                     TabState state = TabStateExtractor.from(tab);
                     if (state != null) {
                         TabStateFileManager.migrateTabState(
-                                getStateDirectory(), state, id, incognito);
+                                getStateDirectory(), state, id, incognito, mCipherFactory);
                         updatedMigrations.add(tab);
                     }
                 } catch (OutOfMemoryError e) {
@@ -753,16 +760,17 @@
             return mPrefetchTabStateActiveTabTask.get();
         }
         // Necessary to do on the UI thread as a last resort.
-        return TabStateFileManager.restoreTabState(getStateDirectory(), tabToRestore.id);
+        return TabStateFileManager.restoreTabState(
+                getStateDirectory(), tabToRestore.id, mCipherFactory);
     }
 
     /**
      * Handles restoring an individual tab.
      *
      * @param tabToRestore Meta data about the tab to be restored.
-     * @param tabState     The previously serialized state of the tab to be restored.
-     * @param setAsActive  Whether the tab should be set as the active tab as part of the
-     *                     restoration process.
+     * @param tabState The previously serialized state of the tab to be restored.
+     * @param setAsActive Whether the tab should be set as the active tab as part of the restoration
+     *     process.
      */
     @VisibleForTesting
     protected void restoreTab(
@@ -1539,7 +1547,7 @@
             try {
                 mMigrationComplete =
                         TabStateFileManager.migrateTabState(
-                                getStateDirectory(), mState, mId, mEncrypted);
+                                getStateDirectory(), mState, mId, mEncrypted, mCipherFactory);
             } catch (Exception e) {
                 Log.d(TAG_MIGRATION, "Error MigrateTabTask#doInBackground", e);
                 throw e;
@@ -1643,7 +1651,8 @@
         if (state == null) return false;
 
         try {
-            TabStateFileManager.saveState(getStateDirectory(), state, tabId, encrypted);
+            TabStateFileManager.saveState(
+                    getStateDirectory(), state, tabId, encrypted, mCipherFactory);
             return true;
         } catch (OutOfMemoryError e) {
             android.util.Log.e(
@@ -1916,7 +1925,8 @@
         protected TabState doInBackground() {
             if (mDestroyed || isCancelled()) return null;
             try {
-                return TabStateFileManager.restoreTabState(getStateDirectory(), mTabToRestore.id);
+                return TabStateFileManager.restoreTabState(
+                        getStateDirectory(), mTabToRestore.id, mCipherFactory);
             } catch (Exception e) {
                 Log.w(TAG, "Unable to read state: " + e);
                 return null;
@@ -2032,7 +2042,7 @@
                     @Override
                     protected TabState doInBackground() {
                         return TabStateFileManager.restoreTabState(
-                                getStateDirectory(), activeTabId);
+                                getStateDirectory(), activeTabId, mCipherFactory);
                     }
                 }.executeOnTaskRunner(taskRunner);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java
index 61d46b0..8965536 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java
@@ -10,7 +10,7 @@
 import static org.chromium.base.test.util.Matchers.containsString;
 import static org.chromium.base.test.util.Matchers.is;
 import static org.chromium.chrome.browser.autofill.AutofillTestHelper.createCreditCard;
-import static org.chromium.chrome.test.R.id.description_line_2;
+import static org.chromium.chrome.test.R.id.first_line_label;
 import static org.chromium.chrome.test.R.id.main_text;
 import static org.chromium.chrome.test.R.id.minor_text;
 import static org.chromium.chrome.test.R.id.sheet_item_list;
@@ -166,7 +166,7 @@
     private void verifyCardSuggestionIsCorrectlyDisplayed(View cardSuggestionItemLayout) {
         TextView mainTextLayout = cardSuggestionItemLayout.findViewById(main_text);
         TextView minorTextLayout = cardSuggestionItemLayout.findViewById(minor_text);
-        TextView cardDescLayout = cardSuggestionItemLayout.findViewById(description_line_2);
+        TextView cardDescLayout = cardSuggestionItemLayout.findViewById(first_line_label);
         // Check that suggestion main text with the card name is displayed
         checkThat(mainTextLayout.getText().toString(), is(CARD_NAME));
         // Check that suggestion minor text with the last four digits of the card are displayed
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java
index 30d8ec3..d30bb6ac 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java
@@ -65,6 +65,7 @@
 import org.chromium.chrome.browser.app.metrics.LaunchCauseMetrics;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.CustomTabsUiType;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler;
 import org.chromium.chrome.browser.customtabs.dependency_injection.BaseCustomTabActivityModule;
 import org.chromium.chrome.browser.dependency_injection.ModuleOverridesRule;
@@ -119,13 +120,15 @@
                                     CustomTabIntentHandler.IntentIgnoringCriterion
                                             intentIgnoringCriterion,
                                     TopUiThemeColorProvider topUiThemeColorProvider,
-                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider) ->
+                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider,
+                                    CipherFactory cipherFactory) ->
                                     new BaseCustomTabActivityModule(
                                             intentDataProvider,
                                             nightModeController,
                                             intentIgnoringCriterion,
                                             topUiThemeColorProvider,
-                                            new FakeDefaultBrowserProviderImpl()));
+                                            new FakeDefaultBrowserProviderImpl(),
+                                            cipherFactory));
 
     @Rule
     public RuleChain mRuleChain =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java
index d685305..ea4cd64 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java
@@ -45,6 +45,7 @@
 import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
 import org.chromium.chrome.browser.app.tabmodel.ChromeTabModelFilterFactory;
 import org.chromium.chrome.browser.app.tabmodel.CustomTabsTabModelOrchestrator;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ActivityType;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileProvider;
@@ -519,7 +520,8 @@
                 new ChromeTabModelFilterFactory(customTabActivity),
                 buildTestPersistencePolicy(),
                 ActivityType.CUSTOM_TAB,
-                AsyncTabParamsManagerSingleton.getInstance());
+                AsyncTabParamsManagerSingleton.getInstance(),
+                CipherFactory.getInstance());
         TabModelSelectorImpl selector = (TabModelSelectorImpl) orchestrator.getTabModelSelector();
         selector.initializeForTesting(normalTabModel, incognitoTabModel);
         ApplicationStatus.onStateChangeForTesting(customTabActivity, ActivityState.DESTROYED);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TabReparentingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TabReparentingTest.java
index 491037b1..75b8cd1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TabReparentingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TabReparentingTest.java
@@ -41,6 +41,7 @@
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.app.metrics.LaunchCauseMetrics;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler;
 import org.chromium.chrome.browser.customtabs.dependency_injection.BaseCustomTabActivityModule;
 import org.chromium.chrome.browser.dependency_injection.ModuleOverridesRule;
@@ -80,13 +81,15 @@
                                     CustomTabIntentHandler.IntentIgnoringCriterion
                                             intentIgnoringCriterion,
                                     TopUiThemeColorProvider topUiThemeColorProvider,
-                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider) ->
+                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider,
+                                    CipherFactory cipherFactory) ->
                                     new BaseCustomTabActivityModule(
                                             intentDataProvider,
                                             nightModeController,
                                             intentIgnoringCriterion,
                                             topUiThemeColorProvider,
-                                            new FakeDefaultBrowserProviderImpl()));
+                                            new FakeDefaultBrowserProviderImpl(),
+                                            cipherFactory));
 
     @Rule
     public RuleChain mRuleChain =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TrustedCdnPublisherUrlTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TrustedCdnPublisherUrlTest.java
index 80abfa8..621368b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TrustedCdnPublisherUrlTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/TrustedCdnPublisherUrlTest.java
@@ -57,6 +57,7 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler;
 import org.chromium.chrome.browser.customtabs.dependency_injection.BaseCustomTabActivityModule;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
@@ -104,13 +105,15 @@
                                     CustomTabIntentHandler.IntentIgnoringCriterion
                                             intentIgnoringCriterion,
                                     TopUiThemeColorProvider topUiThemeColorProvider,
-                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider) ->
+                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider,
+                                    CipherFactory cipherFactory) ->
                                     new BaseCustomTabActivityModule(
                                             intentDataProvider,
                                             nightModeController,
                                             intentIgnoringCriterion,
                                             topUiThemeColorProvider,
-                                            new FakeDefaultBrowserProviderImpl()));
+                                            new FakeDefaultBrowserProviderImpl(),
+                                            cipherFactory));
 
     public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule();
     public ChromeRenderTestRule mRenderTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java
index 1fa5e2f..f23cf46 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java
@@ -185,7 +185,7 @@
      */
     @Test
     @LargeTest
-    @DisableIf.Build(sdk_equals = VERSION_CODES.VANILLA_ICE_CREAM, message = "crbug.com/41401048")
+    @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.TIRAMISU, message = "crbug.com/365516493")
     public void testBrowserDisplayCutoutTakesPrecedence() throws Exception {
         final ObservableSupplierImpl<Integer> browserCutoutModeSupplier =
                 ThreadUtils.runOnUiThreadBlocking(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
index 5db8909a..33f0de4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -176,7 +176,6 @@
                 });
 
         FirstRunStatus.setFirstRunSkippedByPolicy(false);
-        AccountManagerFacadeProvider.resetInstanceForTests();
     }
 
     private ActivityMonitor getMonitor(Class activityClass) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/HomeSurfaceTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/HomeSurfaceTestUtils.java
index 3a66f577..79b6ee19 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/HomeSurfaceTestUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/HomeSurfaceTestUtils.java
@@ -20,6 +20,7 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabState;
 import org.chromium.chrome.browser.tab.TabUtils;
@@ -217,9 +218,12 @@
                         /* isFlatBuffer= */ false);
         writeFile(file, M26_GOOGLE_COM.encodedTabState);
 
-        TabState tabState = TabStateFileManager.restoreTabStateInternal(file, false);
+        TabState tabState =
+                TabStateFileManager.restoreTabStateInternal(
+                        file, false, CipherFactory.getInstance());
         tabState.rootId = rootId;
-        TabStateFileManager.saveStateInternal(file, tabState, encrypted);
+        TabStateFileManager.saveStateInternal(
+                file, tabState, encrypted, CipherFactory.getInstance());
     }
 
     private static void writeFile(File file, String data) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabStateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabStateTest.java
index 9f1124d..5b7fe785 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabStateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabStateTest.java
@@ -15,6 +15,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.tabmodel.TestTabModelDirectory;
 import org.chromium.chrome.browser.tabpersistence.TabStateFileManager;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
@@ -47,7 +48,9 @@
         mTestTabModelDirectory.writeTabStateFile(info);
 
         File tabStateFile = new File(mTestTabModelDirectory.getBaseDirectory(), info.filename);
-        TabState tabState = TabStateFileManager.restoreTabStateInternal(tabStateFile, false);
+        TabState tabState =
+                TabStateFileManager.restoreTabStateInternal(
+                        tabStateFile, false, CipherFactory.getInstance());
         Assert.assertNotNull(tabState);
         Assert.assertEquals(info.url, tabState.contentsState.getVirtualUrlFromState());
         Assert.assertEquals(info.title, tabState.contentsState.getDisplayTitleFromState());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java
index 9434f6a..04ccf73 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java
@@ -17,6 +17,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Batch;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.tabmodel.TestTabModelDirectory;
 import org.chromium.chrome.browser.tabpersistence.TabStateFileManager;
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
@@ -74,7 +75,9 @@
                 });
 
         File tabStateFile = new File(mTestTabModelDirectory.getBaseDirectory(), "tab0");
-        TabState tabState = TabStateFileManager.restoreTabStateInternal(tabStateFile, false);
+        TabState tabState =
+                TabStateFileManager.restoreTabStateInternal(
+                        tabStateFile, false, CipherFactory.getInstance());
         // Garbage-in, garbage out. Client code must be tolerant to null TabState
         Assert.assertNotNull(tabState);
         Assert.assertNotNull(tabState.contentsState);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/TabStateFlatBufferTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/TabStateFlatBufferTest.java
index a17011f..e4c1373 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/TabStateFlatBufferTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/TabStateFlatBufferTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.base.test.util.Matchers;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.Tab;
@@ -65,6 +66,7 @@
     @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
 
     private static EmbeddedTestServer sTestServer;
+    private static CipherFactory sCipherFactory;
 
     private static final String TEST_URL = "/chrome/test/data/browsing_data/e.html";
     private static final String TEST_URL_DISPLAY_TITLE = "My_title";
@@ -72,6 +74,7 @@
     @BeforeClass
     public static void beforeClass() {
         sTestServer = sActivityTestRule.getTestServer();
+        sCipherFactory = CipherFactory.getInstance();
     }
 
     @Test
@@ -79,8 +82,9 @@
     public void testFlatBufferTabStateRegularTab() throws ExecutionException, IOException {
         TabState state = getTestTabState(false);
         File file = getTestFile(1, false);
-        TabStateFileManager.saveStateInternal(file, state, false);
-        TabState restoredTabState = TabStateFileManager.restoreTabStateInternal(file, false);
+        TabStateFileManager.saveStateInternal(file, state, false, sCipherFactory);
+        TabState restoredTabState =
+                TabStateFileManager.restoreTabStateInternal(file, false, sCipherFactory);
         verifyTabStateResult(restoredTabState, state);
     }
 
@@ -89,8 +93,9 @@
     public void testFlatBufferTabStateIncognitoTab() throws ExecutionException, IOException {
         TabState state = getTestTabState(true);
         File file = getTestFile(2, true);
-        TabStateFileManager.saveStateInternal(file, state, false);
-        TabState restoredTabState = TabStateFileManager.restoreTabStateInternal(file, false);
+        TabStateFileManager.saveStateInternal(file, state, false, sCipherFactory);
+        TabState restoredTabState =
+                TabStateFileManager.restoreTabStateInternal(file, false, sCipherFactory);
         verifyTabStateResult(restoredTabState, state);
     }
 
@@ -122,12 +127,14 @@
                     legacyHandWrittenFiles.get(tabId),
                     tabState,
                     /** encrypted = */
-                    tabId % 2 == 0);
+                    tabId % 2 == 0,
+                    sCipherFactory);
             TabStateFileManager.saveStateInternal(
                     flatBufferFiles.get(tabId),
                     tabState,
                     /** encrypted = */
-                    tabId % 2 == 0);
+                    tabId % 2 == 0,
+                    sCipherFactory);
         }
         for (File file :
                 Stream.concat(legacyHandWrittenFiles.stream(), flatBufferFiles.stream())
@@ -161,13 +168,13 @@
     public void testFlatBufferMetrics() throws ExecutionException, IOException {
         TabState state = getTestTabState(false);
         File file = getTestFile(1, false);
-        TabStateFileManager.saveStateInternal(file, state, false);
+        TabStateFileManager.saveStateInternal(file, state, false, sCipherFactory);
         var histograms =
                 HistogramWatcher.newSingleRecordWatcher(
                         "Tabs.TabState.RestoreMethod",
                         TabStateFileManager.TabStateRestoreMethod.FLATBUFFER);
         TabState restoredTabState =
-                TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 1);
+                TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 1, sCipherFactory);
         Assert.assertNotNull(restoredTabState);
         histograms.assertExpected();
     }
@@ -178,13 +185,13 @@
     public void testLegacyHandWrittenMetrics() throws ExecutionException, IOException {
         TabState state = getTestTabState(false);
         File file = getLegacyTestFile(1, false);
-        TabStateFileManager.saveStateInternal(file, state, false);
+        TabStateFileManager.saveStateInternal(file, state, false, sCipherFactory);
         var histograms =
                 HistogramWatcher.newSingleRecordWatcher(
                         "Tabs.TabState.RestoreMethod",
                         TabStateFileManager.TabStateRestoreMethod.LEGACY_HAND_WRITTEN);
         TabState restoredTabState =
-                TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 1);
+                TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 1, sCipherFactory);
         Assert.assertNotNull(restoredTabState);
         histograms.assertExpected();
     }
@@ -206,7 +213,7 @@
                         "Tabs.TabState.RestoreMethod",
                         TabStateFileManager.TabStateRestoreMethod.FAILED);
         TabState restoredTabState =
-                TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 1);
+                TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 1, sCipherFactory);
         Assert.assertNull(restoredTabState);
         histograms.assertExpected();
     }
@@ -223,8 +230,10 @@
                         /* encrypted= */ true,
                         /* isFlatBuffer= */ true),
                 state,
-                /* isEncrypted= */ true);
-        TabState restored = TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 4);
+                /* isEncrypted= */ true,
+                sCipherFactory);
+        TabState restored =
+                TabStateFileManager.restoreTabState(temporaryFolder.getRoot(), 4, sCipherFactory);
         Assert.assertTrue(restored.isIncognito);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
index 3915ad2..b8d7d4d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
@@ -25,6 +25,7 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -96,7 +97,8 @@
                                     persistencePolicy,
                                     selector,
                                     null,
-                                    TabWindowManagerSingleton.getInstance());
+                                    TabWindowManagerSingleton.getInstance(),
+                                    CipherFactory.getInstance());
                     store.waitForMigrationToFinish();
                 });
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/RestoreMigrateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/RestoreMigrateTest.java
index 8f8df05d..c3a8ffc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/RestoreMigrateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/RestoreMigrateTest.java
@@ -26,6 +26,7 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -132,7 +133,8 @@
                                     persistencePolicy,
                                     selector,
                                     null,
-                                    TabWindowManagerSingleton.getInstance());
+                                    TabWindowManagerSingleton.getInstance(),
+                                    CipherFactory.getInstance());
                     return store;
                 });
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
index 0d0832b5..9698c9b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
@@ -48,6 +48,7 @@
 import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
 import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelper;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ActivityType;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -146,6 +147,7 @@
     /** Used when testing interactions of TabPersistentStore with real {@link TabModelImpl}s. */
     static class TestTabModelSelector extends TabModelSelectorBase implements TabModelDelegate {
         final TabPersistentStore mTabPersistentStore;
+        final CipherFactory mCipherFactory;
         final MockTabPersistentStoreObserver mTabPersistentStoreObserver;
         private final TabModelOrderController mTabModelOrderController;
         // Required to ensure TabContentManager is not null.
@@ -160,6 +162,7 @@
             // real object is not available from {@link ChromeActivity} due to the test structure.
             // {@link TabModelImpl} requires a non-null {@link TabContentManager} to initialize.
             mMockTabContentManager = Mockito.mock(TabContentManager.class);
+            mCipherFactory = CipherFactory.getInstance();
             mTabPersistentStore =
                     ThreadUtils.runOnUiThreadBlocking(
                             new Callable<TabPersistentStore>() {
@@ -174,7 +177,8 @@
                                                     persistencePolicy,
                                                     TestTabModelSelector.this,
                                                     getTabCreatorManager(),
-                                                    TabWindowManagerSingleton.getInstance());
+                                                    TabWindowManagerSingleton.getInstance(),
+                                                    mCipherFactory);
                                     tabPersistentStore.addObserver(mTabPersistentStoreObserver);
                                     return tabPersistentStore;
                                 }
@@ -293,6 +297,7 @@
                 }
             };
     private static TabWindowManagerImpl sTabWindowManager;
+    private static CipherFactory sCipherFactory;
 
     /** Class for mocking out the directory containing all of the TabState files. */
     private TestTabModelDirectory mMockDirectory;
@@ -317,6 +322,8 @@
         TabWindowManagerSingleton.setTabModelSelectorFactoryForTesting(
                 sMockTabModelSelectorFactory);
 
+        sCipherFactory = CipherFactory.getInstance();
+
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     sTabWindowManager =
@@ -435,7 +442,8 @@
                             persistencePolicy,
                             modelSelector,
                             creatorManager,
-                            TabWindowManagerSingleton.getInstance());
+                            TabWindowManagerSingleton.getInstance(),
+                            sCipherFactory);
                 });
     }
 
@@ -809,13 +817,19 @@
 
     private int getRootIdFromLegacyTabStateFile(Tab tab) {
         return TabStateFileManager.restoreTabState(
-                        mMockDirectory.getDataDirectory(), tab.getId(), /* useFlatBuffer= */ false)
+                        mMockDirectory.getDataDirectory(),
+                        tab.getId(),
+                        sCipherFactory,
+                        /* useFlatBuffer= */ false)
                 .rootId;
     }
 
     private int getRootIdFromFlatBufferTabStateFile(Tab tab) {
         return TabStateFileManager.restoreTabState(
-                        mMockDirectory.getDataDirectory(), tab.getId(), /* useFlatBuffer= */ true)
+                        mMockDirectory.getDataDirectory(),
+                        tab.getId(),
+                        sCipherFactory,
+                        /* useFlatBuffer= */ true)
                 .rootId;
     }
 
@@ -1356,7 +1370,9 @@
                 if (restoredFromDisk(selector.getModel(false).getTabAt(j))) {
                     TabState currentState =
                             TabStateFileManager.restoreTabState(
-                                    mMockDirectory.getDataDirectory(), info.contents[j].tabId);
+                                    mMockDirectory.getDataDirectory(),
+                                    info.contents[j].tabId,
+                                    sCipherFactory);
                     Assert.assertEquals(
                             info.contents[j].title,
                             currentState.contentsState.getDisplayTitleFromState());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicyTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicyTest.java
index a441281c..8851860 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicyTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicyTest.java
@@ -36,6 +36,7 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
 import org.chromium.chrome.browser.app.tabmodel.TabbedModeTabModelOrchestrator;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures;
@@ -156,7 +157,9 @@
                             profileProviderSupplier.set(mProfileProvider);
                             TabbedModeTabModelOrchestrator tmpOrchestrator =
                                     new TabbedModeTabModelOrchestrator(
-                                            false, mActivityLifecycleDispatcher);
+                                            false,
+                                            mActivityLifecycleDispatcher,
+                                            CipherFactory.getInstance());
                             tmpOrchestrator.createTabModels(
                                     new ChromeTabbedActivity(),
                                     profileProviderSupplier,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java
index 4858338..936a4c0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java
@@ -34,6 +34,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.intents.WebappConstants;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabNightModeStateController;
 import org.chromium.chrome.browser.customtabs.DefaultBrowserProviderImpl;
 import org.chromium.chrome.browser.customtabs.FakeDefaultBrowserProviderImpl;
@@ -66,13 +67,15 @@
                                     CustomTabIntentHandler.IntentIgnoringCriterion
                                             intentIgnoringCriterion,
                                     TopUiThemeColorProvider topUiThemeColorProvider,
-                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider) ->
+                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider,
+                                    CipherFactory cipherFactory) ->
                                     new BaseCustomTabActivityModule(
                                             intentDataProvider,
                                             nightModeController,
                                             intentIgnoringCriterion,
                                             topUiThemeColorProvider,
-                                            new FakeDefaultBrowserProviderImpl()));
+                                            new FakeDefaultBrowserProviderImpl(),
+                                            cipherFactory));
 
     @Rule
     public RuleChain mRuleChain =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
index 8a2b93898..8b336bab 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
@@ -47,6 +47,7 @@
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.intents.WebappConstants;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabNightModeStateController;
 import org.chromium.chrome.browser.customtabs.DefaultBrowserProviderImpl;
 import org.chromium.chrome.browser.customtabs.FakeDefaultBrowserProviderImpl;
@@ -96,13 +97,15 @@
                                     CustomTabIntentHandler.IntentIgnoringCriterion
                                             intentIgnoringCriterion,
                                     TopUiThemeColorProvider topUiThemeColorProvider,
-                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider) ->
+                                    DefaultBrowserProviderImpl customTabDefaultBrowserProvider,
+                                    CipherFactory cipherFactory) ->
                                     new BaseCustomTabActivityModule(
                                             intentDataProvider,
                                             nightModeController,
                                             intentIgnoringCriterion,
                                             topUiThemeColorProvider,
-                                            new FakeDefaultBrowserProviderImpl()));
+                                            new FakeDefaultBrowserProviderImpl(),
+                                            cipherFactory));
 
     @Rule
     public RuleChain mRuleChain =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java
index 16fcbdb..2abcf2a5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java
@@ -35,6 +35,7 @@
 import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.homepage.HomepageManager;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
@@ -127,7 +128,9 @@
 
         mOrchestrator =
                 new TabbedModeTabModelOrchestrator(
-                        /* tabMergingEnabled= */ true, mActivityLifecycleDispatcher);
+                        /* tabMergingEnabled= */ true,
+                        mActivityLifecycleDispatcher,
+                        CipherFactory.getInstance());
         mOrchestrator.createTabModels(
                 mChromeActivity,
                 profileProviderSupplier,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestratorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestratorUnitTest.java
index 9004cb1..8a8ccbb 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestratorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestratorUnitTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiWindowTestUtils;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
@@ -47,12 +48,13 @@
 
     private OneshotSupplierImpl<ProfileProvider> mProfileProviderSupplier =
             new OneshotSupplierImpl<>();
+    private CipherFactory mCipherFactory;
 
     // TabbedModeTabModelOrchestrator running on Android S where tab merging into other instance
     // is not performed.
     private class TabbedModeTabModelOrchestratorApi31 extends TabbedModeTabModelOrchestrator {
         public TabbedModeTabModelOrchestratorApi31() {
-            super(/* tabMergingEnabled= */ false, mActivityLifecycleDispatcher);
+            super(/* tabMergingEnabled= */ false, mActivityLifecycleDispatcher, mCipherFactory);
         }
 
         @Override
@@ -65,6 +67,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mProfileProviderSupplier.set(mProfileProvider);
+        mCipherFactory = CipherFactory.getInstance();
     }
 
     @After
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/base/SplitPreloaderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/base/SplitPreloaderTest.java
index 6f99686..b721437 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/base/SplitPreloaderTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/base/SplitPreloaderTest.java
@@ -16,6 +16,7 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,6 +26,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.build.BuildConfig;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -117,6 +119,15 @@
 
     @Before
     public void setUp() {
+        BuildConfig.IS_BUNDLE = true;
+        mContext = new MainContext(ContextUtils.getApplicationContext());
+        ContextUtils.initApplicationContextForTests(mContext);
+        mPreloader = new SplitPreloader(mContext);
+    }
+
+    @After
+    public void tearDown() {
+        BuildConfig.IS_BUNDLE = false;
         mContext = new MainContext(ContextUtils.getApplicationContext());
         ContextUtils.initApplicationContextForTests(mContext);
         mPreloader = new SplitPreloader(mContext);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreUnitTest.java
index 3aaf8fe..7c45ab4 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreUnitTest.java
@@ -39,6 +39,7 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabCreationState;
@@ -87,6 +88,7 @@
     private TabModelFilter mNormalTabModelFilter;
     private TabModelFilter mIncognitoTabModelFilter;
     private TabPersistentStore mPersistentStore;
+    private CipherFactory mCipherFactory;
 
     @Before
     public void setUp() {
@@ -107,6 +109,8 @@
         mIncognitoTabModelFilter = new TabGroupModelFilter(mIncognitoTabModel);
         when(mTabModelFilterProvider.getTabModelFilter(false)).thenReturn(mNormalTabModelFilter);
         when(mTabModelFilterProvider.getTabModelFilter(true)).thenReturn(mIncognitoTabModelFilter);
+
+        mCipherFactory = CipherFactory.getInstance();
     }
 
     @After
@@ -132,7 +136,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager) {
+                        mTabWindowManager,
+                        mCipherFactory) {
                     @Override
                     protected void saveNextTab() {
                         // Intentionally ignore to avoid triggering async task creation.
@@ -161,7 +166,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(false);
 
         TabRestoreDetails emptyNtpDetails =
@@ -189,7 +195,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(false);
 
         LoadUrlParamsUrlMatcher paramsMatcher = new LoadUrlParamsUrlMatcher(UrlConstants.NTP_URL);
@@ -223,7 +230,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(false);
 
         LoadUrlParamsUrlMatcher paramsMatcher = new LoadUrlParamsUrlMatcher(UrlConstants.NTP_URL);
@@ -263,7 +271,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(false);
 
         TabRestoreDetails ntpDetails =
@@ -287,7 +296,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(false);
 
         LoadUrlParamsUrlMatcher paramsMatcher = new LoadUrlParamsUrlMatcher(UrlConstants.NTP_URL);
@@ -318,7 +328,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(false);
 
         TabRestoreDetails emptyNtpDetails =
@@ -338,7 +349,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(true);
 
         TabRestoreDetails emptyNtpDetails =
@@ -359,7 +371,8 @@
                         mPersistencePolicy,
                         mTabModelSelector,
                         mTabCreatorManager,
-                        mTabWindowManager);
+                        mTabWindowManager,
+                        mCipherFactory);
         mPersistentStore.initializeRestoreVars(false);
 
         TabRestoreDetails regularTabRestoreDetails =
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 4a857461..8b20319a 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -5738,14 +5738,14 @@
   <message name="IDS_SETTINGS_FACTORY_CONTINUE_BUTTON_LABEL" desc="Label for the button that navigates from the eSIM warning to the 'Factory Reset' UI.">
     Continue
   </message>
-  <message name="IDS_OS_SETTINGS_SANITIZE" desc="The string sanitize will be used for title, button name, and button label.">
-    Sanitize
+  <message name="IDS_OS_SETTINGS_SANITIZE" desc="The heading and the button string of the safety reset feature.">
+    Safety reset
   </message>
   <message name="IDS_OS_SETTINGS_SANITIZE_HEADING" desc="Name of the sanitize dialog describes the feature to the user before they proceed.">
     Sanitize your device
   </message>
-  <message name="IDS_OS_SETTINGS_SANITIZE_SHORT_DESCRIPTION" desc="Short description of the sanitize feature on the ChromeOS settings page.">
-    Reset settings on your ChromeOS device to safe defaults.
+  <message name="IDS_OS_SETTINGS_SANITIZE_SHORT_DESCRIPTION" desc="Short description of the safety reset feature on the ChromeOS settings page.">
+    Remove unwanted pop-ups, fix network issues, and more by restoring your settings to safe defaults.
   </message>
   <message name="IDS_OS_SETTINGS_SANITIZE_DESCRIPTION" desc="Description of the sanitize feature on the sanitize window.">
     Getting unwanted pop-ups, or other unexpected behavior? Sometimes, apps and extensions that you install can change your ChromeOS settings without you knowing.
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE.png.sha1
index e258aa2..a37561b 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE.png.sha1
@@ -1 +1 @@
-e641c35c789c43f87f3d9611f656327dc826f8b0
\ No newline at end of file
+6948c2cf54709d6924ed782634f1485a6dd848d1
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE_SHORT_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE_SHORT_DESCRIPTION.png.sha1
index 53bb045..c8c51ca 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE_SHORT_DESCRIPTION.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SANITIZE_SHORT_DESCRIPTION.png.sha1
@@ -1 +1 @@
-61fe92190780f7b97dc32297c23bff9f45d1d430
\ No newline at end of file
+5bdbc84f95f7672c3921883ecde68440258a0ba5
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 58fc6a97..d36e905 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1084,6 +1084,8 @@
     "policy/device_management_service_configuration.h",
     "policy/dm_token_utils.cc",
     "policy/dm_token_utils.h",
+    "policy/gen_ai_default_settings_policy_handler.cc",
+    "policy/gen_ai_default_settings_policy_handler.h",
     "policy/homepage_location_policy_handler.cc",
     "policy/homepage_location_policy_handler.h",
     "policy/javascript_policy_handler.cc",
@@ -6629,12 +6631,15 @@
   }
 
   if (enterprise_data_controls) {
+    sources += [
+      "//chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.cc",
+      "//chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h",
+    ]
+
     # TODO(b/352728209): Update the logic for which file compiles on Android
     # when the proper methods have been migrated to components/.
     if (!is_android) {
       sources += [
-        "//chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.cc",
-        "//chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h",
         "//chrome/browser/enterprise/data_protection/paste_allowed_request.cc",
         "//chrome/browser/enterprise/data_protection/paste_allowed_request.h",
       ]
@@ -8350,13 +8355,6 @@
   if (enable_reporting) {
     deps += [ "//components/tpcd/enterprise_reporting" ]
   }
-
-  if (is_win || is_mac || is_linux || is_chromeos) {
-    sources += [
-      "policy/gen_ai_default_settings_policy_handler.cc",
-      "policy/gen_ai_default_settings_policy_handler.h",
-    ]
-  }
 }
 
 # These are the dependencies for the "browser" target that are outside of
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ca43e76..89dd56c 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2238,10 +2238,14 @@
 
 const FeatureEntry::FeatureParam kEducationalTipModule_force_tab_group[] = {
     {"force_tab_group", "true"}};
+const FeatureEntry::FeatureParam kEducationalTipModule_force_tab_group_sync[] =
+    {{"force_tab_group_sync", "true"}};
 
 const FeatureEntry::FeatureVariation kEducationalTipModuleVariations[] = {
     {"Show tab group promo", kEducationalTipModule_force_tab_group,
      std::size(kEducationalTipModule_force_tab_group), nullptr},
+    {"Show tab group sync promo", kEducationalTipModule_force_tab_group_sync,
+     std::size(kEducationalTipModule_force_tab_group_sync), nullptr},
 };
 
 const FeatureEntry::FeatureParam
@@ -5002,17 +5006,6 @@
      FEATURE_VALUE_TYPE(ash::features::kOngoingProcesses)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(IS_ANDROID)
-    {"adaptive-button-in-top-toolbar-translate",
-     flag_descriptions::kAdaptiveButtonInTopToolbarTranslateName,
-     flag_descriptions::kAdaptiveButtonInTopToolbarTranslateDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kAdaptiveButtonInTopToolbarTranslate)},
-    {"adaptive-button-in-top-toolbar-add-to-bookmarks",
-     flag_descriptions::kAdaptiveButtonInTopToolbarAddToBookmarksName,
-     flag_descriptions::kAdaptiveButtonInTopToolbarAddToBookmarksDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(
-         chrome::android::kAdaptiveButtonInTopToolbarAddToBookmarks)},
     {"adaptive-button-in-top-toolbar-page-summary",
      flag_descriptions::kAdaptiveButtonInTopToolbarPageSummaryName,
      flag_descriptions::kAdaptiveButtonInTopToolbarPageSummaryDescription,
diff --git a/chrome/browser/android/cookies/BUILD.gn b/chrome/browser/android/cookies/BUILD.gn
index a3b1449..75ec56f 100644
--- a/chrome/browser/android/cookies/BUILD.gn
+++ b/chrome/browser/android/cookies/BUILD.gn
@@ -36,6 +36,7 @@
     "//base:base_java",
     "//base:base_java_test_support",
     "//base:base_junit_test_support",
+    "//chrome/browser/android/crypto:java",
     "//chrome/browser/profiles/android:java",
     "//third_party/hamcrest:hamcrest_java",
     "//third_party/jni_zero:gendeps_java",
diff --git a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java
index 2e276c04..9a46955 100644
--- a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java
+++ b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java
@@ -52,6 +52,7 @@
     private static final String TAG = "CookiesFetcher";
 
     private final ProfileProvider mProfileProvider;
+    private final CipherFactory mCipherFactory;
     private final ProfileManager.Observer mProfileManagerObserver;
     private final String mCookieDirPath;
 
@@ -60,8 +61,9 @@
      *
      * <p>Consumers must call {@link #destroy()} on this object.
      */
-    public CookiesFetcher(ProfileProvider profileProvider) {
+    public CookiesFetcher(ProfileProvider profileProvider, CipherFactory cipherFactory) {
         mProfileProvider = profileProvider;
+        mCipherFactory = cipherFactory;
 
         mProfileManagerObserver =
                 new ProfileManager.Observer() {
@@ -162,7 +164,7 @@
                 List<CanonicalCookie> cookies = new ArrayList<CanonicalCookie>();
                 DataInputStream in = null;
                 try {
-                    Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
+                    Cipher cipher = mCipherFactory.getCipher(Cipher.DECRYPT_MODE);
                     if (cipher == null) {
                         // Something is wrong. Can't encrypt, don't restore cookies.
                         return cookies;
@@ -301,17 +303,18 @@
                     Log.e(TAG, "Unable to save OTR cookies because file is null");
                     return null;
                 }
-                saveFetchedCookiesToDisk(fileName, cookies);
+                saveFetchedCookiesToDisk(fileName, mCipherFactory, cookies);
                 return null;
             }
         }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
     }
 
     @VisibleForTesting
-    static void saveFetchedCookiesToDisk(String fileName, CanonicalCookie[] cookies) {
+    static void saveFetchedCookiesToDisk(
+            String fileName, CipherFactory cipherFactory, CanonicalCookie[] cookies) {
         DataOutputStream out = null;
         try {
-            Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
+            Cipher cipher = cipherFactory.getCipher(Cipher.ENCRYPT_MODE);
             if (cipher == null) {
                 // Something is wrong. Can't encrypt, don't save cookies.
                 return;
diff --git a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java
index b0d13df..070ecacc 100644
--- a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java
+++ b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java
@@ -28,6 +28,7 @@
 import org.chromium.base.task.test.ShadowPostTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileProvider;
 
@@ -50,6 +51,8 @@
     @Mock private CookiesFetcher.Natives mCookiesFetcherJni;
     @Mock private ImportantFileWriterAndroid.Natives mImportantFileWriterJni;
 
+    private CipherFactory mCipherFactory;
+
     private CanonicalCookie mCookie0;
     private CanonicalCookie mCookie1;
     private CanonicalCookie mCookie2;
@@ -100,6 +103,8 @@
                             }
                         });
 
+        mCipherFactory = CipherFactory.getInstance();
+
         mCookie0 =
                 new CanonicalCookie(
                         "name",
@@ -181,7 +186,7 @@
     @Test
     public void testRestoreCookies_NoOtrProfile_NoExistingFile() throws Exception {
         setupProfileProvider(mProfile1, null);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
 
         assertCookieFileExists(fetcher, false);
         assertLegacyCookieFileExists(false);
@@ -198,7 +203,7 @@
             throws Exception {
         setupProfileProvider(mProfile1, null);
         Mockito.when(mProfile1.isInitialProfile()).thenReturn(true);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
 
         File cookieFile = new File(CookiesFetcher.fetchLegacyFileName());
         try (PrintWriter writer = new PrintWriter(cookieFile)) {
@@ -219,7 +224,7 @@
     public void testRestoreCookies_NoOtrProfile_InitialProfile_ExistingFile() throws Exception {
         setupProfileProvider(mProfile1, null);
         Mockito.when(mProfile1.isInitialProfile()).thenReturn(true);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
 
         File cookieFile = new File(fetcher.fetchFileName());
         try (PrintWriter writer = new PrintWriter(cookieFile)) {
@@ -241,7 +246,7 @@
             throws Exception {
         setupProfileProvider(mProfile1, null);
         Mockito.when(mProfile1.isInitialProfile()).thenReturn(false);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
 
         File cookieFile = new File(CookiesFetcher.fetchLegacyFileName());
         try (PrintWriter writer = new PrintWriter(cookieFile)) {
@@ -258,7 +263,7 @@
     @Test
     public void testRestoreCookies_HasOtrProfile_NoExistingFile() throws Exception {
         setupProfileProvider(mProfile1, mIncognitoProfile1);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
         assertLegacyCookieFileExists(false);
         fetcher.restoreCookies();
         ShadowLooper.idleMainLooper();
@@ -268,7 +273,7 @@
     @Test
     public void testPersistRestoreCookies() throws Exception {
         setupProfileProvider(mProfile1, mIncognitoProfile1);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
 
         fetcher.persistCookies();
         Mockito.verify(mCookiesFetcherJni)
@@ -315,13 +320,14 @@
     public void testRestoreCookies_InitialProfile_LegacyFile() throws Exception {
         setupProfileProvider(mProfile1, mIncognitoProfile1);
         Mockito.when(mProfile1.isInitialProfile()).thenReturn(true);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
 
         CanonicalCookie[] cookies = new CanonicalCookie[3];
         cookies[0] = mCookie0;
         cookies[1] = mCookie1;
         cookies[2] = mCookie2;
-        CookiesFetcher.saveFetchedCookiesToDisk(CookiesFetcher.fetchLegacyFileName(), cookies);
+        CookiesFetcher.saveFetchedCookiesToDisk(
+                CookiesFetcher.fetchLegacyFileName(), mCipherFactory, cookies);
         ShadowLooper.idleMainLooper();
 
         assertLegacyCookieFileExists(true);
@@ -360,13 +366,14 @@
     public void testRestoreCookies_NotInitialProfile_LegacyFile() throws Exception {
         setupProfileProvider(mProfile1, mIncognitoProfile1);
         Mockito.when(mProfile1.isInitialProfile()).thenReturn(false);
-        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider);
+        CookiesFetcher fetcher = new CookiesFetcher(mProfileProvider, mCipherFactory);
 
         CanonicalCookie[] cookies = new CanonicalCookie[3];
         cookies[0] = mCookie0;
         cookies[1] = mCookie1;
         cookies[2] = mCookie2;
-        CookiesFetcher.saveFetchedCookiesToDisk(CookiesFetcher.fetchLegacyFileName(), cookies);
+        CookiesFetcher.saveFetchedCookiesToDisk(
+                CookiesFetcher.fetchLegacyFileName(), mCipherFactory, cookies);
         ShadowLooper.idleMainLooper();
 
         assertLegacyCookieFileExists(true);
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 7f02ebc..4f07ecd 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -1930,6 +1930,7 @@
     "//chrome/browser/ash/floating_sso:browser_tests",
     "//chrome/browser/ash/geolocation:browser_tests",
     "//chrome/browser/ash/guest_os:browser_tests",
+    "//chrome/browser/ash/input_device_settings:browser_tests",
     "//chrome/browser/ash/input_method:browser_tests",
     "//chrome/browser/ash/kcer:browser_tests",
     "//chrome/browser/ash/kerberos:browser_tests",
diff --git a/chrome/browser/ash/auth/active_session_fingerprint_client_impl.cc b/chrome/browser/ash/auth/active_session_fingerprint_client_impl.cc
index 7767957..8fb48601 100644
--- a/chrome/browser/ash/auth/active_session_fingerprint_client_impl.cc
+++ b/chrome/browser/ash/auth/active_session_fingerprint_client_impl.cc
@@ -92,7 +92,7 @@
     case AuthRequest::Reason::kSettings:
       return false;
     case AuthRequest::Reason::kPasswordManager: {
-      if (ash::features::IsBiometricsInPasswordManagerEnabled()){
+      if (ash::features::IsBiometricsInPasswordManagerEnabled()) {
         const base::Value::List& factors =
             pref_service->GetList(prefs::kQuickUnlockModeAllowlist);
         if (base::Contains(factors, base::Value(kFactorsOptionAll)) ||
diff --git a/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.cc b/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.cc
index e06d7169..ac971d9e 100644
--- a/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.cc
+++ b/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.cc
@@ -20,7 +20,9 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chromeos/window_pin_util.h"
+#include "chromeos/ash/components/boca/on_task/on_task_blocklist.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
 #include "url/gurl.h"
 
 namespace ash::boca {
@@ -146,16 +148,24 @@
 
 void OnTaskSystemWebAppManagerImpl::CreateBackgroundTabWithUrl(
     SessionID window_id,
-    GURL url) {
+    GURL url,
+    OnTaskBlocklist::RestrictionLevel restriction_level) {
   Browser* const browser = GetBrowserWindowWithID(window_id);
   if (!browser) {
     return;
   }
-
-  // TODO (b/353758782): Set navigation restrictions for the URL.
   NavigateParams navigate_params(browser, url, ui::PAGE_TRANSITION_FROM_API);
   navigate_params.disposition = WindowOpenDisposition::NEW_BACKGROUND_TAB;
-  Navigate(&navigate_params);
+  base::WeakPtr<content::NavigationHandle> navigation_handle =
+      Navigate(&navigate_params);
+  content::WebContents* const tab = navigation_handle->GetWebContents();
+  LockedSessionWindowTracker* const window_tracker =
+      LockedSessionWindowTrackerFactory::GetForBrowserContext(profile_);
+  if (!window_tracker) {
+    return;
+  }
+  window_tracker->on_task_blocklist()->SetParentURLRestrictionLevel(
+      tab, restriction_level);
 }
 
 }  // namespace ash::boca
diff --git a/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.h b/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.h
index f6c33e2..4efcb4d 100644
--- a/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.h
+++ b/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.h
@@ -8,6 +8,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/boca/on_task/on_task_blocklist.h"
 #include "chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h"
 #include "url/gurl.h"
 
@@ -33,7 +34,10 @@
   void SetPinStateForSystemWebAppWindow(bool pinned,
                                         SessionID window_id) override;
   void SetWindowTrackerForSystemWebAppWindow(SessionID window_id) override;
-  void CreateBackgroundTabWithUrl(SessionID window_id, GURL url) override;
+  void CreateBackgroundTabWithUrl(
+      SessionID window_id,
+      GURL url,
+      OnTaskBlocklist::RestrictionLevel restriction_level) override;
 
  private:
   raw_ptr<Profile> profile_;
diff --git a/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl_browsertest.cc b/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl_browsertest.cc
index 0dda2e3..8e21b14 100644
--- a/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl_browsertest.cc
+++ b/chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl_browsertest.cc
@@ -8,11 +8,14 @@
 #include "ash/webui/system_apps/public/system_web_app_type.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
+#include "chrome/browser/ash/boca/on_task/locked_session_window_tracker_factory.h"
+#include "chrome/browser/ash/boca/on_task/on_task_locked_session_window_tracker.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "components/sessions/content/session_tab_helper.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -25,7 +28,7 @@
 namespace ash::boca {
 namespace {
 
-constexpr char kTestUrl[] = "https://www.google.com";
+constexpr char kTestUrl[] = "https://www.test.com";
 
 class OnTaskSystemWebAppManagerImplBrowserTest : public InProcessBrowserTest {
  protected:
@@ -143,13 +146,24 @@
 
   // Create tab from the url and verify that Boca has the tab.
   system_web_app_manager.CreateBackgroundTabWithUrl(
-      boca_app_browser->session_id(), GURL(kTestUrl));
+      boca_app_browser->session_id(), GURL(kTestUrl),
+      OnTaskBlocklist::RestrictionLevel::kLimitedNavigation);
   EXPECT_EQ(boca_app_browser->tab_strip_model()->count(), 2);
   content::WebContents* web_contents =
       boca_app_browser->tab_strip_model()->GetWebContentsAt(1);
   content::TestNavigationObserver observer(web_contents);
   observer.Wait();
   EXPECT_EQ(web_contents->GetLastCommittedURL(), GURL(kTestUrl));
+
+  // Verify that the restriction is applied to the tab.
+  LockedSessionWindowTracker* const window_tracker =
+      LockedSessionWindowTrackerFactory::GetForBrowserContext(profile());
+  OnTaskBlocklist* const blocklist = window_tracker->on_task_blocklist();
+  EXPECT_EQ(
+      blocklist
+          ->parent_tab_to_nav_filters()[sessions::SessionTabHelper::IdForTab(
+              web_contents)],
+      OnTaskBlocklist::RestrictionLevel::kLimitedNavigation);
 }
 
 }  // namespace
diff --git a/chrome/browser/ash/bruschetta/bruschetta_download.cc b/chrome/browser/ash/bruschetta/bruschetta_download.cc
index c54a253a0..5212d7f3 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_download.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_download.cc
@@ -75,22 +75,21 @@
 
   std::unique_ptr<crypto::SecureHash> ctx(
       crypto::SecureHash::Create(crypto::SecureHash::SHA256));
-  const size_t kReadBufferSize = 4096;
-  char buffer[kReadBufferSize];
+  std::array<uint8_t, 4096> buffer;
   while (true) {
-    int count = file.ReadAtCurrentPos(buffer, kReadBufferSize);
+    std::optional<size_t> read = file.ReadAtCurrentPos(buffer);
 
     // Treat EOF the same as any other error, stop reading and return the hash
     // of what we read. If there was a disk error or something we'll end up with
     // an invalid hash, same as if the file were truncated.
-    if (count <= 0) {
+    if (read.value_or(0) == 0) {
       break;
     }
-    ctx->Update(buffer, count);
+    ctx->Update(base::span(buffer).subspan(0, *read));
   }
 
-  uint8_t digest_bytes[crypto::kSHA256Length];
-  ctx->Finish(digest_bytes, crypto::kSHA256Length);
+  std::array<uint8_t, crypto::kSHA256Length> digest_bytes;
+  ctx->Finish(digest_bytes);
   return base::HexEncode(digest_bytes);
 }
 
diff --git a/chrome/browser/ash/growth/campaigns_manager_client_impl.cc b/chrome/browser/ash/growth/campaigns_manager_client_impl.cc
index d612115..d72a6179 100644
--- a/chrome/browser/ash/growth/campaigns_manager_client_impl.cc
+++ b/chrome/browser/ash/growth/campaigns_manager_client_impl.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <string_view>
 #include <variant>
 
 #include "ash/constants/ash_features.h"
@@ -15,6 +16,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/no_destructor.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/version.h"
 #include "chrome/browser/ash/growth/campaigns_manager_session.h"
@@ -50,8 +52,8 @@
 inline constexpr char kCampaignComponentName[] = "growth-campaigns";
 
 // A util function to add the `kGrowthCampaignsEventNamePrefix`.
-std::string AddEventPrefix(const std::string& event) {
-  return growth::GetGrowthCampaignsEventNamePrefix() + event;
+std::string AddEventPrefix(std::string_view event) {
+  return base::StrCat({growth::GetGrowthCampaignsEventNamePrefix(), event});
 }
 
 Profile* GetProfile() {
diff --git a/chrome/browser/ash/growth/campaigns_manager_session.cc b/chrome/browser/ash/growth/campaigns_manager_session.cc
index 11f7852..55e7955b 100644
--- a/chrome/browser/ash/growth/campaigns_manager_session.cc
+++ b/chrome/browser/ash/growth/campaigns_manager_session.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ash/growth/campaigns_manager_session.h"
 
 #include <optional>
+#include <string>
+#include <string_view>
 
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_switches.h"
@@ -46,19 +48,19 @@
 // The time to trigger delayed campaigns.
 constexpr base::TimeDelta kTimeToTriggerDelayedCampaigns = base::Minutes(5);
 
-bool IsWebBrowserAppId(const std::string& app_id) {
+bool IsWebBrowserAppId(std::string_view app_id) {
   return app_id == app_constants::kChromeAppId ||
          app_id == app_constants::kAshDebugBrowserAppId ||
          app_id == app_constants::kLacrosAppId;
 }
 
 bool IsAppVisible(const apps::InstanceUpdate& update) {
-  return (update.State() & apps::InstanceState::kVisible);
+  return update.State() & apps::InstanceState::kVisible;
 }
 
 bool IsAppActiveAndVisible(const apps::InstanceUpdate& update) {
-  return (IsAppVisible(update) &&
-          (update.State() & apps::InstanceState::kActive));
+  return IsAppVisible(update) &&
+         (update.State() & apps::InstanceState::kActive);
 }
 
 std::optional<growth::ActionType> GetActionTypeBySlot(growth::Slot slot) {
@@ -73,19 +75,14 @@
   return std::nullopt;
 }
 
-std::optional<std::string> GetAppGroupId() {
+std::string_view GetAppGroupId() {
   auto* campaigns_manager = growth::CampaignsManager::Get();
   CHECK(campaigns_manager);
 
-  auto app_id = campaigns_manager->GetOpenedAppId();
-  if (IsWebBrowserAppId(app_id)) {
-    // For web browser, get group id by active url.
-    auto active_url = campaigns_manager->GetActiveUrl();
-    return growth::GetAppGroupId(active_url);
-  }
-
-  // For non web browser, get group id by app id.
-  return growth::GetAppGroupId(app_id);
+  const auto app_id = campaigns_manager->GetOpenedAppId();
+  return IsWebBrowserAppId(app_id)
+             ? growth::GetAppGroupId(campaigns_manager->GetActiveUrl())
+             : growth::GetAppGroupId(app_id);
 }
 
 base::TimeDelta GetTimeToTriggerDelayedCampaigns() {
@@ -400,7 +397,7 @@
 }
 
 void CampaignsManagerSession::MaybeTriggerCampaignsOnEvent(
-    const std::string& event) {
+    std::string_view event) {
   if (!ash::features::IsGrowthCampaignsTriggerByEventEnabled()) {
     return;
   }
@@ -409,7 +406,7 @@
   CHECK(campaigns_manager);
 
   growth::Trigger trigger(growth::TriggerType::kEvent);
-  trigger.event = event;
+  trigger.event = std::string(event);
   campaigns_manager->SetTrigger(std::move(trigger));
 
   MaybeTriggerSlot(growth::Slot::kNudge);
@@ -630,15 +627,14 @@
   auto* campaigns_manager = growth::CampaignsManager::Get();
   CHECK(campaigns_manager);
 
-  auto app_group_id = GetAppGroupId();
-
   // If `app_group_id` is defined, record the `event` and trigger campaigns
   // based on the trigger `event`. An `app_group_id` is used to configurate how
   // often, i.e. the interval, to show the nudges.
-  if (app_group_id) {
+  if (const std::string_view app_group_id = GetAppGroupId();
+      !app_group_id.empty()) {
     campaigns_manager->RecordEvent(
-        GetEventName(growth::CampaignEvent::kEvent, app_group_id.value()));
-    MaybeTriggerCampaignsOnEvent(app_group_id.value());
+        GetEventName(growth::CampaignEvent::kEvent, app_group_id));
+    MaybeTriggerCampaignsOnEvent(app_group_id);
   }
 
   if (!ash::features::IsGrowthCampaignsTriggerByAppOpenEnabled()) {
diff --git a/chrome/browser/ash/growth/campaigns_manager_session.h b/chrome/browser/ash/growth/campaigns_manager_session.h
index e62ff90..57865810 100644
--- a/chrome/browser/ash/growth/campaigns_manager_session.h
+++ b/chrome/browser/ash/growth/campaigns_manager_session.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_ASH_GROWTH_CAMPAIGNS_MANAGER_SESSION_H_
 #define CHROME_BROWSER_ASH_GROWTH_CAMPAIGNS_MANAGER_SESSION_H_
 
+#include <string_view>
+
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/timer/timer.h"
@@ -43,7 +45,7 @@
 
   void PrimaryPageChanged(const content::WebContents* web_contents);
 
-  void MaybeTriggerCampaignsOnEvent(const std::string& event);
+  void MaybeTriggerCampaignsOnEvent(std::string_view event);
 
   aura::Window* GetOpenedWindow() { return opened_window_; }
 
diff --git a/chrome/browser/ash/input_device_settings/BUILD.gn b/chrome/browser/ash/input_device_settings/BUILD.gn
index daced55..07a0f43 100644
--- a/chrome/browser/ash/input_device_settings/BUILD.gn
+++ b/chrome/browser/ash/input_device_settings/BUILD.gn
@@ -31,3 +31,20 @@
     "//services/network/public/cpp",
   ]
 }
+
+source_set("browser_tests") {
+  testonly = true
+
+  sources = [ "peripherals_app_delegate_browsertest.cc" ]
+
+  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+  deps = [
+    ":input_device_settings",
+    "//base",
+    "//chrome/browser/apps/almanac_api_client",
+    "//chrome/test:test_support",
+    "//content/test:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/browser/ash/input_device_settings/peripherals_app_delegate_browsertest.cc b/chrome/browser/ash/input_device_settings/peripherals_app_delegate_browsertest.cc
new file mode 100644
index 0000000..80571efa
--- /dev/null
+++ b/chrome/browser/ash/input_device_settings/peripherals_app_delegate_browsertest.cc
@@ -0,0 +1,86 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_future.h"
+#include "chrome/browser/apps/almanac_api_client/almanac_app_icon_loader.h"
+#include "chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/services/app_service/public/cpp/app_types.h"
+#include "components/services/app_service/public/cpp/package_id.h"
+#include "content/public/test/browser_test.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+namespace {
+
+const apps::PackageId kTestPackageId(apps::PackageType::kWeb,
+                                     "test.package.name");
+constexpr char kAppName[] = "app_name";
+constexpr char kTestDeviceKey[] = "0000:0001";
+
+}  // namespace
+
+class PeripheralsAppDelegateImplTest : public InProcessBrowserTest {
+ public:
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    TestingProfile::Builder profile_builder;
+    profile_builder.SetSharedURLLoaderFactory(
+        url_loader_factory_.GetSafeWeakWrapper());
+    profile_ = profile_builder.Build();
+    delegate_ = std::make_unique<PeripheralsAppDelegateImpl>();
+    delegate()->set_profile_for_testing(profile_.get());
+    ASSERT_TRUE(embedded_test_server()->Start());
+    loader_ = std::make_unique<apps::AlmanacAppIconLoader>(*profile());
+  }
+
+  void TearDownOnMainThread() override {
+    InProcessBrowserTest::TearDownOnMainThread();
+    loader_.reset();
+    delegate_.reset();
+    profile_.reset();
+  }
+
+  TestingProfile* profile() { return profile_.get(); }
+
+  PeripheralsAppDelegateImpl* delegate() { return delegate_.get(); }
+
+  network::TestURLLoaderFactory url_loader_factory_;
+
+ private:
+  std::unique_ptr<TestingProfile> profile_;
+  std::unique_ptr<PeripheralsAppDelegateImpl> delegate_;
+  std::unique_ptr<apps::AlmanacAppIconLoader> loader_;
+};
+
+IN_PROC_BROWSER_TEST_F(PeripheralsAppDelegateImplTest,
+                       GetCompanionAppResponse_Valid) {
+  apps::proto::PeripheralsGetResponse response;
+  response.set_package_id(kTestPackageId.ToString());
+  response.set_name(kAppName);
+  url_loader_factory_.AddResponse(delegate()->GetServerUrl().spec(),
+                                  response.SerializeAsString(), net::HTTP_OK);
+  base::test::TestFuture<const std::optional<mojom::CompanionAppInfo>&>
+      app_info;
+  delegate()->GetCompanionAppInfo(kTestDeviceKey, app_info.GetCallback());
+  const auto info = app_info.Get();
+  EXPECT_EQ(kAppName, info->app_name);
+  EXPECT_EQ(kTestPackageId.ToString(), info->package_id);
+}
+
+IN_PROC_BROWSER_TEST_F(PeripheralsAppDelegateImplTest,
+                       GetCompanionAppResponse_Invalid) {
+  apps::proto::PeripheralsGetResponse response;
+  url_loader_factory_.AddResponse(delegate()->GetServerUrl().spec(),
+                                  response.SerializeAsString());
+  base::test::TestFuture<const std::optional<mojom::CompanionAppInfo>&>
+      app_info;
+  delegate()->GetCompanionAppInfo(kTestDeviceKey, app_info.GetCallback());
+  EXPECT_FALSE(app_info.Take().has_value());
+}
+
+}  // namespace ash
diff --git a/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.cc b/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.cc
index 25eaf7b..180fa4a 100644
--- a/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.cc
+++ b/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.cc
@@ -8,6 +8,7 @@
 #include "ash/system/input_device_settings/input_device_settings_metadata.h"
 #include "chrome/browser/apps/almanac_api_client/almanac_api_util.h"
 #include "chrome/browser/apps/almanac_api_client/almanac_app_icon_loader.h"
+#include "chrome/browser/apps/almanac_api_client/device_info_manager.h"
 #include "chrome/browser/apps/almanac_api_client/proto/client_context.pb.h"
 #include "chrome/browser/apps/app_service/app_install/app_install_types.h"
 #include "chrome/browser/apps/app_service/package_id_util.h"
@@ -65,34 +66,11 @@
       }
     )");
 
-// Creates an example ClientDeviceContext that is needed to form a well
-// structured request to the Almanac endpoint.
-static apps::proto::ClientDeviceContext GetExampleClientContext() {
-  apps::proto::ClientDeviceContext device_context;
-  device_context.set_board("board");
-  device_context.set_model("model");
-  device_context.set_channel(apps::proto::ClientDeviceContext::CHANNEL_DEV);
-  device_context.mutable_versions()->set_chrome_ash("124.0.12345.1");
-  device_context.mutable_versions()->set_chrome_os_platform("12345.0.1");
-  device_context.set_hardware_id("hardware_id");
-  return device_context;
-}
-
-// Creates an example ClientUserContext that is needed to form a request to the
-// Almanac endpoint. The data does not matter, the format just needs to be
-// right for Almanac to accept the request.
-static apps::proto::ClientUserContext GetExampleClientUserContext() {
-  apps::proto::ClientUserContext user_context;
-  user_context.set_language("en_US");
-  user_context.set_user_type(apps::proto::ClientUserContext::USERTYPE_MANAGED);
-  return user_context;
-}
-
-std::string BuildRequestBody(const std::string& device_key) {
+std::string BuildRequestBody(const std::string& device_key,
+                             const apps::DeviceInfo& info) {
   apps::proto::PeripheralsGetRequest peripherals_proto;
-
-  *peripherals_proto.mutable_device_context() = GetExampleClientContext();
-  *peripherals_proto.mutable_user_context() = GetExampleClientUserContext();
+  *peripherals_proto.mutable_device_context() = info.ToDeviceContext();
+  *peripherals_proto.mutable_user_context() = info.ToUserContext();
   *peripherals_proto.mutable_device() =
       GetDeviceKeyForMetadataRequest(device_key);
   return peripherals_proto.SerializeAsString();
@@ -103,22 +81,39 @@
 PeripheralsAppDelegateImpl::PeripheralsAppDelegateImpl() = default;
 PeripheralsAppDelegateImpl::~PeripheralsAppDelegateImpl() = default;
 
-void PeripheralsAppDelegateImpl::GetCompanionAppInfo(
+void PeripheralsAppDelegateImpl::OnDeviceInfoFetched(
+    base::WeakPtr<Profile> active_user_profile_weak_ptr,
+    GetCompanionAppInfoCallback callback,
     const std::string& device_key,
-    GetCompanionAppInfoCallback callback) {
-  Profile* active_user_profile = ProfileManager::GetActiveUserProfile();
-
+    apps::DeviceInfo device_info) {
+  Profile* profile = active_user_profile_weak_ptr.get();
+  if (!profile) {
+    std::move(callback).Run(std::nullopt);
+    return;
+  }
   QueryAlmanacApi<apps::proto::PeripheralsGetResponse>(
-      *active_user_profile->GetURLLoaderFactory().get(), kTrafficAnnotation,
-      BuildRequestBody(device_key), kPeripheralsAlmanacEndpoint,
+      *profile->GetURLLoaderFactory().get(), kTrafficAnnotation,
+      BuildRequestBody(device_key, device_info), kPeripheralsAlmanacEndpoint,
       kMaxResponseSizeInBytes,
       /*error_histogram_name=*/std::nullopt,
       base::BindOnce(
           &PeripheralsAppDelegateImpl::ConvertPeripheralsResponseProto,
-          weak_factory_.GetWeakPtr(), active_user_profile->GetWeakPtr(),
+          weak_factory_.GetWeakPtr(), profile->GetWeakPtr(),
           std::move(callback)));
 }
 
+void PeripheralsAppDelegateImpl::GetCompanionAppInfo(
+    const std::string& device_key,
+    GetCompanionAppInfoCallback callback) {
+  Profile* active_user_profile = GetActiveUserProfile();
+  device_info_manager_ =
+      std::make_unique<apps::DeviceInfoManager>(active_user_profile);
+  device_info_manager_->GetDeviceInfo(base::BindOnce(
+      &PeripheralsAppDelegateImpl::OnDeviceInfoFetched,
+      weak_factory_.GetWeakPtr(), active_user_profile->GetWeakPtr(),
+      std::move(callback), device_key));
+}
+
 void PeripheralsAppDelegateImpl::ConvertPeripheralsResponseProto(
     base::WeakPtr<Profile> active_user_profile_weak_ptr,
     GetCompanionAppInfoCallback callback,
@@ -180,4 +175,16 @@
   std::move(callback).Run(info);
 }
 
+Profile* PeripheralsAppDelegateImpl::GetActiveUserProfile() {
+  if (is_testing_) {
+    return profile_for_testing_;
+  }
+
+  return ProfileManager::GetActiveUserProfile();
+}
+
+GURL PeripheralsAppDelegateImpl::GetServerUrl() {
+  return apps::GetAlmanacEndpointUrl(kPeripheralsAlmanacEndpoint);
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.h b/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.h
index da4f6b1..bb4c350 100644
--- a/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.h
+++ b/chrome/browser/ash/input_device_settings/peripherals_app_delegate_impl.h
@@ -22,8 +22,11 @@
 namespace apps {
 class AlmanacAppIconLoader;
 struct QueryError;
+class DeviceInfoManager;
+struct DeviceInfo;
 }  // namespace apps
 
+class GURL;
 class Profile;
 
 namespace ash {
@@ -42,6 +45,14 @@
   void GetCompanionAppInfo(const std::string& device_key,
                            GetCompanionAppInfoCallback callback) override;
 
+  // Returns the GURL for the endpoint. Exposed for tests.
+  GURL GetServerUrl();
+
+  void set_profile_for_testing(Profile* profile) {
+    profile_for_testing_ = profile;
+    is_testing_ = true;
+  }
+
  private:
   void ConvertPeripheralsResponseProto(
       base::WeakPtr<Profile> active_user_profile_weak_ptr,
@@ -53,8 +64,23 @@
                        mojom::CompanionAppInfo info,
                        apps::IconValuePtr icon_value);
 
+  void OnDeviceInfoFetched(base::WeakPtr<Profile> active_user_profile_weak_ptr,
+                           GetCompanionAppInfoCallback callback,
+                           const std::string& device_key,
+                           apps::DeviceInfo device_info);
+
+  // Retrieves the active user profile, considering testing scenarios.
+  // Returns:
+  //   - A pointer to the active user profile.
+  //   - If 'is_testing_' is true, returns 'profile_for_testing_'.
+  //   - Otherwise, delegates to ProfileManager to get the active profile.
+  Profile* GetActiveUserProfile();
+
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   std::unique_ptr<apps::AlmanacAppIconLoader> icon_loader_;
+  std::unique_ptr<apps::DeviceInfoManager> device_info_manager_;
+  raw_ptr<Profile> profile_for_testing_ = nullptr;
+  bool is_testing_ = false;
   base::WeakPtrFactory<PeripheralsAppDelegateImpl> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.cc b/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.cc
index 8746b33..bce174f 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.cc
@@ -118,8 +118,7 @@
     PluginVmInstaller* plugin_vm_installer,
     Profile* profile)
     : plugin_vm_installer_(plugin_vm_installer),
-      secure_hash_service_(
-          crypto::SecureHash::Create(crypto::SecureHash::SHA256)) {
+      hasher_(crypto::SecureHash::Create(crypto::SecureHash::SHA256)) {
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
 
@@ -187,7 +186,7 @@
 }
 
 void PluginVmDriveImageDownloadService::ResetState() {
-  secure_hash_service_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
+  hasher_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
   total_bytes_downloaded_ = 0;
 }
 
@@ -225,7 +224,7 @@
   completion_info.path = download_file_path_;
   completion_info.bytes_downloaded = total_bytes_downloaded_;
   std::array<uint8_t, 32> sha256_hash;
-  secure_hash_service_->Finish(sha256_hash.data(), sha256_hash.size());
+  hasher_->Finish(sha256_hash);
   completion_info.hash256 = base::HexEncode(sha256_hash);
   plugin_vm_installer_->OnDownloadCompleted(completion_info);
 }
@@ -243,7 +242,7 @@
   if (first_chunk)
     ResetState();
 
-  secure_hash_service_->Update(content->c_str(), content->length());
+  hasher_->Update(base::as_byte_span(*content));
   total_bytes_downloaded_ += content->length();
 }
 
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.h b/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.h
index da239bb..b0b93f6 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.h
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.h
@@ -76,7 +76,7 @@
 
   raw_ptr<PluginVmInstaller> plugin_vm_installer_;
   std::unique_ptr<drive::DriveServiceInterface> drive_service_;
-  std::unique_ptr<crypto::SecureHash> secure_hash_service_;
+  std::unique_ptr<crypto::SecureHash> hasher_;
   std::string file_id_;
   int64_t total_bytes_downloaded_ = 0;
   base::FilePath download_directory_{kPluginVmDriveDownloadDirectory};
diff --git a/chrome/browser/ash/system_web_apps/apps/sanitize_app_integration_browsertest.cc b/chrome/browser/ash/system_web_apps/apps/sanitize_app_integration_browsertest.cc
index efea9ee..8e5bdb9 100644
--- a/chrome/browser/ash/system_web_apps/apps/sanitize_app_integration_browsertest.cc
+++ b/chrome/browser/ash/system_web_apps/apps/sanitize_app_integration_browsertest.cc
@@ -33,7 +33,7 @@
 IN_PROC_BROWSER_TEST_P(SanitizeAppIntegrationTest, SanitizeAppInLauncher) {
   const GURL url((ash::kChromeUISanitizeAppURL));
   EXPECT_NO_FATAL_FAILURE(ExpectSystemWebAppValid(
-      ash::SystemWebAppType::OS_SANITIZE, url, "Sanitize"));
+      ash::SystemWebAppType::OS_SANITIZE, url, "Safety reset"));
 
   histogram_tester_.ExpectBucketCount(
       "Webapp.InstallResult.System.Apps.Sanitize",
diff --git a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java
index d444c44..9fb5dee1 100644
--- a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java
+++ b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java
@@ -460,13 +460,21 @@
     }
 
     public static AutofillSuggestion createCreditCardSuggestion(
-            String label, String secondaryLabel, String subLabel, boolean applyDeactivatedStyle) {
-        return new AutofillSuggestion.Builder()
-                .setLabel(label)
-                .setSecondaryLabel(secondaryLabel)
-                .setSubLabel(subLabel)
-                .setApplyDeactivatedStyle(applyDeactivatedStyle)
-                .build();
+            String label,
+            String secondaryLabel,
+            String subLabel,
+            String secondarySubLabel,
+            boolean applyDeactivatedStyle) {
+        AutofillSuggestion.Builder builder =
+                new AutofillSuggestion.Builder()
+                        .setLabel(label)
+                        .setSecondaryLabel(secondaryLabel)
+                        .setSubLabel(subLabel)
+                        .setApplyDeactivatedStyle(applyDeactivatedStyle);
+        if (!secondarySubLabel.isEmpty()) {
+            builder.setSecondarySubLabel(secondarySubLabel);
+        }
+        return builder.build();
     }
 
     public static void addMaskedBankAccount(BankAccount bankAccount) {
diff --git a/chrome/browser/data_sharing/BUILD.gn b/chrome/browser/data_sharing/BUILD.gn
index 7b6ed7f..e31b55b 100644
--- a/chrome/browser/data_sharing/BUILD.gn
+++ b/chrome/browser/data_sharing/BUILD.gn
@@ -44,6 +44,7 @@
   android_library("tab_group_ui_java") {
     resources_package = "org.chromium.chrome.browser.data_sharing"
     sources = [
+      "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtils.java",
       "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java",
       "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabSwitcherDelegate.java",
       "android/java/src/org/chromium/chrome/browser/data_sharing/TabGridDialogShareBottomSheetContent.java",
@@ -61,6 +62,7 @@
       "//chrome/browser/tab_group:java",
       "//chrome/browser/tab_group_sync:factory_java",
       "//chrome/browser/tab_group_sync:java",
+      "//chrome/browser/tabmodel:java",
       "//chrome/browser/ui/android/strings:ui_strings_grd",
       "//components/browser_ui/bottomsheet/android:java",
       "//components/browser_ui/notifications/android:java",
@@ -184,6 +186,7 @@
   robolectric_library("junit") {
     sources = [
       "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingNotificationManagerUnitTest.java",
+      "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtilsUnitTest.java",
       "android/java/src/org/chromium/chrome/browser/data_sharing/ui/shared_image_tiles/SharedImageTilesCoordinatorUnitTest.java",
     ]
     deps = [
@@ -192,9 +195,16 @@
       "//base:base_java",
       "//base:base_junit_test_support",
       "//chrome/browser/notifications:java",
+      "//chrome/browser/profiles/android:java",
+      "//chrome/browser/tab:java",
+      "//chrome/browser/tab_group_sync:factory_java",
+      "//chrome/browser/tabmodel:java",
+      "//chrome/test/android:chrome_java_unit_test_support",
       "//components/browser_ui/notifications/android:java",
       "//components/data_sharing/public:public_java",
+      "//components/saved_tab_groups:java",
       "//third_party/android_deps:robolectric_all_java",
+      "//third_party/androidx:androidx_annotation_annotation_java",
       "//third_party/androidx:androidx_test_core_java",
       "//third_party/junit:junit",
       "//third_party/mockito:mockito_java",
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtils.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtils.java
new file mode 100644
index 0000000..4c298d0
--- /dev/null
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtils.java
@@ -0,0 +1,116 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.data_sharing;
+
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncServiceFactory;
+import org.chromium.chrome.browser.tabmodel.TabClosureParams;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabModelUtils;
+import org.chromium.components.tab_group_sync.LocalTabGroupId;
+import org.chromium.components.tab_group_sync.SavedTabGroup;
+import org.chromium.components.tab_group_sync.SavedTabGroupTab;
+import org.chromium.components.tab_group_sync.TabGroupSyncService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** Utilities related to tab groups in data sharing. */
+public class DataSharingTabGroupUtils {
+    /**
+     * Returns the list of local tab group IDs with collaborations that closing or ungrouping the
+     * list of tabs would destroy.
+     *
+     * @param tabModel The tab model to close or ungroup tabs in.
+     * @param tabsToRemove The list of tabs to remove.
+     * @return A list of the local tab groups IDs that would have collaborations destroyed, or an
+     *     empty list if none.
+     */
+    @NonNull
+    public static List<LocalTabGroupId> getCollaborationsDestroyedByTabRemoval(
+            @NonNull TabModel tabModel, @Nullable List<Tab> tabsToRemove) {
+        // TODO(crbug.com/345854441): Add feature flag checks.
+
+        // Collaborations are not possible in incognito branded mode.
+        if (tabsToRemove == null || tabsToRemove.isEmpty() || tabModel.isIncognitoBranded()) {
+            return Collections.emptyList();
+        }
+
+        List<LocalTabGroupId> groupIds = new ArrayList<>();
+        @Nullable
+        TabGroupSyncService tabGroupSyncService =
+                TabGroupSyncServiceFactory.getForProfile(tabModel.getProfile());
+        if (tabGroupSyncService == null) {
+            return Collections.emptyList();
+        }
+
+        for (String syncId : tabGroupSyncService.getAllGroupIds()) {
+            SavedTabGroup group = tabGroupSyncService.getGroup(syncId);
+
+            // Tab groups without collaborations are not of interest since there is no risk if they
+            // are destroyed. Tab groups without a local representation won't have local tabs that
+            // are being removed and can also be skipped.
+            if (group.localId == null || TextUtils.isEmpty(group.collaborationId)) continue;
+
+            if (willRemoveAllTabsInGroup(group.savedTabs, tabsToRemove)) {
+                groupIds.add(group.localId);
+            }
+        }
+        return groupIds;
+    }
+
+    /**
+     * Returns the list of local tab group IDs with collaborations that closing the tabs described
+     * by the closure params would destroy.
+     *
+     * @param tabModel The tab model to close tabs in.
+     * @param closureParams The params that would be used to close tabs.
+     * @return A list of the local tab group IDs that would have collaborations destroyed, or an
+     *     empty list if none.
+     */
+    public static @NonNull List<LocalTabGroupId> getCollaborationsDestroyedByTabClosure(
+            @NonNull TabModel tabModel, @NonNull TabClosureParams closureParams) {
+        // If tab groups are being hidden then they cannot be destroyed.
+        if (closureParams.hideTabGroups) return Collections.emptyList();
+
+        @Nullable
+        List<Tab> tabsToClose =
+                closureParams.isAllTabs
+                        ? TabModelUtils.convertTabListToListOfTabs(tabModel)
+                        : closureParams.tabs;
+        return getCollaborationsDestroyedByTabRemoval(tabModel, tabsToClose);
+    }
+
+    private static boolean willRemoveAllTabsInGroup(
+            List<SavedTabGroupTab> savedTabs, List<Tab> tabsToRemove) {
+        for (SavedTabGroupTab savedTab : savedTabs) {
+            // First check that we have local IDs for the tab. It is possible that we don't if the
+            // tab group is open in another window that hasn't been foregrounded yet as the tabs are
+            // loaded lazily and so won't be tracked yet. If this happens we won't destroy the
+            // collaboration as the tabs cannot be removed.
+            //
+            // If any of the tabs in the saved group are missing from the list of tabsToRemove we
+            // can assume the collaboration will not be destroyed and early out. This check is
+            // technically O(n^2) if every group is a collaboration and all tabs are closing. We
+            // could optimize this with sets, but then the average case performance is likely to
+            // be worse as realistically very few entries will be shared. We can revisit this if we
+            // start seeing ANRs or other issues.
+            if (savedTab.localId == null
+                    || !tabsToRemove.stream()
+                            .filter(tab -> tab.getId() == savedTab.localId)
+                            .findFirst()
+                            .isPresent()) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtilsUnitTest.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtilsUnitTest.java
new file mode 100644
index 0000000..9f6296c
--- /dev/null
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupUtilsUnitTest.java
@@ -0,0 +1,320 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.data_sharing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import androidx.annotation.Nullable;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.Token;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncServiceFactory;
+import org.chromium.chrome.browser.tabmodel.TabClosureParams;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.test.util.browser.tabmodel.MockTabModel;
+import org.chromium.components.tab_group_sync.LocalTabGroupId;
+import org.chromium.components.tab_group_sync.SavedTabGroup;
+import org.chromium.components.tab_group_sync.SavedTabGroupTab;
+import org.chromium.components.tab_group_sync.TabGroupSyncService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** Unit tests for {@link DataSharingTabGroupUtils}. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class DataSharingTabGroupUtilsUnitTest {
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private static final String SYNC_SUFFIX = "_sync";
+    private static final String COLLABORATION_SUFFIX = "_collaboration";
+
+    private static final int TAB_ID_1 = 123;
+    private static final int TAB_ID_2 = 456;
+    private static final int TAB_ID_3 = 789;
+    private static final int TAB_ID_4 = 433289;
+    private static final LocalTabGroupId LOCAL_TAB_GROUP_ID_1 =
+            new LocalTabGroupId(new Token(1L, 1L));
+    private static final LocalTabGroupId LOCAL_TAB_GROUP_ID_2 =
+            new LocalTabGroupId(new Token(2L, 2L));
+    private static final LocalTabGroupId LOCAL_TAB_GROUP_ID_3 =
+            new LocalTabGroupId(new Token(3L, 3L));
+
+    @Mock private Profile mRegularProfile;
+    @Mock private Profile mOtrProfile;
+    @Mock private TabGroupSyncService mTabGroupSyncService;
+
+    @Before
+    public void setUp() {
+        when(mRegularProfile.isOffTheRecord()).thenReturn(false);
+        when(mOtrProfile.isOffTheRecord()).thenReturn(true);
+
+        TabGroupSyncServiceFactory.setForTesting(mTabGroupSyncService);
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_NullList() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel, /* tabsToRemove= */ null);
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_EmptyList() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel, /* tabsToRemove= */ Collections.emptyList());
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_IncognitoTabModel() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ true);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel, List.of(tabModel.getTabById(TAB_ID_1)));
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_NoLocalGroup() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        /* localTabGroupId= */ null,
+                        List.of(TAB_ID_1),
+                        /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel, List.of(tabModel.getTabById(TAB_ID_1)));
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_NoCollaboration() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ false));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel, List.of(tabModel.getTabById(TAB_ID_1)));
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_NotAllClosing() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1,
+                        List.of(TAB_ID_1, TAB_ID_2),
+                        /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel, List.of(tabModel.getTabById(TAB_ID_1)));
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_AllClosing_1Tab() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel, List.of(tabModel.getTabById(TAB_ID_1)));
+        assertEquals(LOCAL_TAB_GROUP_ID_1, result.get(0));
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabRemoval_AllClosing_2Tab() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1,
+                        List.of(TAB_ID_1, TAB_ID_2),
+                        /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabRemoval(
+                        tabModel,
+                        List.of(tabModel.getTabById(TAB_ID_1), tabModel.getTabById(TAB_ID_2)));
+        assertEquals(LOCAL_TAB_GROUP_ID_1, result.get(0));
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabClosure_NoTabs() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+        var params = TabClosureParams.closeTabs(Collections.emptyList()).build();
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabClosure(tabModel, params);
+
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabClosure_SomeTabs_NotHiding() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+        var params = TabClosureParams.closeTabs(List.of(tabModel.getTabById(TAB_ID_1))).build();
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabClosure(tabModel, params);
+
+        assertEquals(LOCAL_TAB_GROUP_ID_1, result.get(0));
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabClosure_SomeTabs_Hiding() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1, List.of(TAB_ID_1), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+        var params =
+                TabClosureParams.closeTabs(List.of(tabModel.getTabById(TAB_ID_1)))
+                        .hideTabGroups(true)
+                        .build();
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabClosure(tabModel, params);
+
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetCollaborationsDestroyedByTabClosure_AllTabs() {
+        List<TabGroupData> tabGroups = new ArrayList<>();
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_1,
+                        List.of(TAB_ID_1, TAB_ID_2),
+                        /* isCollaboration= */ true));
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_2, List.of(TAB_ID_3), /* isCollaboration= */ false));
+        tabGroups.add(
+                new TabGroupData(
+                        LOCAL_TAB_GROUP_ID_3, List.of(TAB_ID_4), /* isCollaboration= */ true));
+        var tabModel = createTabGroups(tabGroups, /* isIncognito= */ false);
+        var params = TabClosureParams.closeAllTabs().build();
+
+        List<LocalTabGroupId> result =
+                DataSharingTabGroupUtils.getCollaborationsDestroyedByTabClosure(tabModel, params);
+
+        assertEquals(LOCAL_TAB_GROUP_ID_1, result.get(0));
+        assertEquals(LOCAL_TAB_GROUP_ID_3, result.get(1));
+    }
+
+    private static class TabGroupData {
+        public final @Nullable LocalTabGroupId localTabGroupId;
+        public final List<Integer> tabIds;
+        public final boolean isCollaboration;
+
+        TabGroupData(
+                @Nullable LocalTabGroupId localTabGroupId,
+                List<Integer> tabIds,
+                boolean isCollaboration) {
+            this.localTabGroupId = localTabGroupId;
+            this.tabIds = tabIds;
+            this.isCollaboration = isCollaboration;
+        }
+    }
+
+    private TabModel createTabGroups(List<TabGroupData> groups, boolean isIncognito) {
+        MockTabModel mockTabModel =
+                new MockTabModel(isIncognito ? mOtrProfile : mRegularProfile, /* delegate= */ null);
+
+        List<SavedTabGroup> savedGroups = new ArrayList<>();
+        List<String> savedGroupSyncIds = new ArrayList<>();
+        for (TabGroupData group : groups) {
+            List<SavedTabGroupTab> savedTabs = new ArrayList<>();
+            for (int tabId : group.tabIds) {
+                mockTabModel.addTab(tabId);
+
+                SavedTabGroupTab savedTab = new SavedTabGroupTab();
+                savedTab.localId = tabId;
+                savedTabs.add(savedTab);
+            }
+
+            SavedTabGroup savedGroup = new SavedTabGroup();
+            // Use hashcode as unique placeholder if non-local group.
+            String groupIdString =
+                    group.localTabGroupId != null
+                            ? group.localTabGroupId.tabGroupId.toString()
+                            : String.valueOf(group.hashCode());
+            savedGroup.syncId = groupIdString + SYNC_SUFFIX;
+            savedGroup.localId = group.localTabGroupId;
+            savedGroup.savedTabs = savedTabs;
+            if (group.isCollaboration) {
+                savedGroup.collaborationId = groupIdString + COLLABORATION_SUFFIX;
+            }
+
+            savedGroupSyncIds.add(savedGroup.syncId);
+            savedGroups.add(savedGroup);
+        }
+
+        if (!isIncognito) {
+            when(mTabGroupSyncService.getAllGroupIds())
+                    .thenReturn(savedGroupSyncIds.toArray(new String[0]));
+            for (int i = 0; i < savedGroupSyncIds.size(); i++) {
+                when(mTabGroupSyncService.getGroup(savedGroupSyncIds.get(i)))
+                        .thenReturn(savedGroups.get(i));
+            }
+        } else {
+            when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {});
+        }
+
+        return mockTabModel;
+    }
+}
diff --git a/chrome/browser/educational_tip/BUILD.gn b/chrome/browser/educational_tip/BUILD.gn
index 70a837b..043ccb37 100644
--- a/chrome/browser/educational_tip/BUILD.gn
+++ b/chrome/browser/educational_tip/BUILD.gn
@@ -17,6 +17,7 @@
     "java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoBottomSheetContent.java",
     "java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoCoordinator.java",
     "java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java",
+    "java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java",
   ]
   deps = [
     ":java_resources",
@@ -24,6 +25,7 @@
     "//base:base_java",
     "//base:base_shared_preferences_java",
     "//chrome/browser/flags:java",
+    "//chrome/browser/hub:java",
     "//chrome/browser/magic_stack/android:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab_ui/android:java",
@@ -41,6 +43,7 @@
     "java/res/drawable/default_browser_promo_logo.xml",
     "java/res/drawable/educational_tip_module_content_image_background.xml",
     "java/res/drawable/tab_group_promo_logo.xml",
+    "java/res/drawable/tab_group_sync_promo_logo.xml",
     "java/res/layout/educational_tip_default_browser_bottom_sheet.xml",
     "java/res/layout/educational_tip_module_layout.xml",
     "java/res/values/dimens.xml",
@@ -61,6 +64,7 @@
     "junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java",
     "junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleViewBinderUnitTest.java",
     "junit/src/org/chromium/chrome/browser/educational_tip/TabGroupPromoCoordinatorUnitTest.java",
+    "junit/src/org/chromium/chrome/browser/educational_tip/TabGroupSyncPromoCoordinatorUnitTest.java",
   ]
 
   deps = [
@@ -70,6 +74,7 @@
     "//base:base_java_test_support",
     "//base:base_junit_test_support",
     "//chrome/browser/flags:java",
+    "//chrome/browser/hub:java",
     "//chrome/browser/magic_stack/android:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab_ui/android:java",
diff --git a/chrome/browser/educational_tip/java/res/drawable/tab_group_promo_logo.xml b/chrome/browser/educational_tip/java/res/drawable/tab_group_promo_logo.xml
index 3640dd9..e0865ae5 100644
--- a/chrome/browser/educational_tip/java/res/drawable/tab_group_promo_logo.xml
+++ b/chrome/browser/educational_tip/java/res/drawable/tab_group_promo_logo.xml
@@ -14,11 +14,11 @@
 
     <path android:fillAlpha="0.05" android:fillColor="@color/gm3_baseline_surface_tint_light" android:pathData="M11.31,0L60.69,0A11.31,11.31 0,0 1,72 11.31L72,60.69A11.31,11.31 0,0 1,60.69 72L11.31,72A11.31,11.31 0,0 1,0 60.69L0,11.31A11.31,11.31 0,0 1,11.31 0z"/>
 
-    <path android:fillColor="#00000000"
+    <path android:fillColor="@android:color/transparent"
         android:pathData="M17.603,25C18.666,23.542 19.866,22.134 21.201,20.799C31.505,10.495 46.155,8.214 55,15.174M55,48.906C54.176,49.941 53.28,50.945 52.314,51.912C43.516,60.71 31.549,63.659 22.734,60"
         android:strokeColor="#1B6EF3" android:strokeLineCap="round" android:strokeWidth="2"/>
 
-    <path android:fillColor="#00000000"
+    <path android:fillColor="@android:color/transparent"
         android:pathData="M55,15.174C49.207,10.615 40.922,10.021 33,13.05M43.175,58.5C35.948,62.057 28.134,62.54 22,59.677"
         android:strokeColor="#1B6EF3" android:strokeLineCap="round" android:strokeWidth="2"/>
 
diff --git a/chrome/browser/educational_tip/java/res/drawable/tab_group_sync_promo_logo.xml b/chrome/browser/educational_tip/java/res/drawable/tab_group_sync_promo_logo.xml
new file mode 100644
index 0000000..572fa9a
--- /dev/null
+++ b/chrome/browser/educational_tip/java/res/drawable/tab_group_sync_promo_logo.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<vector android:autoMirrored="true" android:height="72dp"
+    android:viewportHeight="72" android:viewportWidth="72"
+    android:width="72dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@color/material_primary_95"
+        android:fillAlpha="0.05"
+        android:pathData="M11.31,0L60.69,0A11.31,11.31 0,0 1,72 11.31L72,60.69A11.31,11.31 0,0 1,60.69 72L11.31,72A11.31,11.31 0,0 1,0 60.69L0,11.31A11.31,11.31 0,0 1,11.31 0z"/>
+
+    <path android:fillAlpha="0.05" android:fillColor="@color/gm3_baseline_surface_tint_light" android:pathData="M11.31,0L60.69,0A11.31,11.31 0,0 1,72 11.31L72,60.69A11.31,11.31 0,0 1,60.69 72L11.31,72A11.31,11.31 0,0 1,0 60.69L0,11.31A11.31,11.31 0,0 1,11.31 0z"/>
+    <path android:fillColor="@color/material_primary_90" android:pathData="M19,10L53,10A4,4 0,0 1,57 14L57,58A4,4 0,0 1,53 62L19,62A4,4 0,0 1,15 58L15,14A4,4 0,0 1,19 10z"/>
+
+    <path android:fillColor="@android:color/transparent"
+        android:pathData="M19,41L33,41A1,1 0,0 1,34 42L34,58A1,1 0,0 1,33 59L19,59A1,1 0,0 1,18 58L18,42A1,1 0,0 1,19 41z"
+        android:strokeColor="@color/material_primary_80" android:strokeWidth="2"/>
+    <path android:fillColor="@color/material_primary_80" android:pathData="M39,40L53,40A2,2 0,0 1,55 42L55,58A2,2 0,0 1,53 60L39,60A2,2 0,0 1,37 58L37,42A2,2 0,0 1,39 40z"/>
+
+    <path android:fillColor="@android:color/transparent"
+        android:pathData="M39,19L53,19A1,1 0,0 1,54 20L54,36A1,1 0,0 1,53 37L39,37A1,1 0,0 1,38 36L38,20A1,1 0,0 1,39 19z"
+        android:strokeColor="@color/material_primary_80" android:strokeWidth="2"/>
+
+    <path android:fillColor="@color/material_primary_80" android:pathData="M19,18L33,18A2,2 0,0 1,35 20L35,36A2,2 0,0 1,33 38L19,38A2,2 0,0 1,17 36L17,20A2,2 0,0 1,19 18z"/>
+    <path android:fillColor="@color/material_primary_40" android:pathData="M16,15L30,15A2,2 0,0 1,32 17L32,33A2,2 0,0 1,30 35L16,35A2,2 0,0 1,14 33L14,17A2,2 0,0 1,16 15z"/>
+    <path android:fillColor="@color/material_primary_40" android:pathData="M36,37L50,37A2,2 0,0 1,52 39L52,55A2,2 0,0 1,50 57L36,57A2,2 0,0 1,34 55L34,39A2,2 0,0 1,36 37z"/>
+</vector>
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java
index b997dcd..7057359 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java
@@ -7,11 +7,19 @@
 import androidx.annotation.DrawableRes;
 import androidx.annotation.IntDef;
 
+import org.chromium.chrome.browser.hub.PaneId;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /** The interface for a card which is shown in the educational tip module. */
 public interface EducationalTipCardProvider {
+    // A callback to open the provided pane Id of the Hub layout.
+    @FunctionalInterface
+    interface ShowHubPaneCallback {
+        void onClick(@PaneId int paneId);
+    }
+
     /** Card types that are shown in the educational tip module on the magic stack. */
     @IntDef({
         EducationalTipCardType.DEFAULT_BROWSER_PROMO,
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java
index b93cffd..36b2769 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java
@@ -9,11 +9,14 @@
 
 import androidx.annotation.NonNull;
 
+import org.chromium.base.CallbackController;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.EducationalTipCardType;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.ShowHubPaneCallback;
 import org.chromium.chrome.browser.educational_tip.cards.DefaultBrowserPromoCoordinator;
 import org.chromium.chrome.browser.educational_tip.cards.TabGroupPromoCoordinator;
+import org.chromium.chrome.browser.educational_tip.cards.TabGroupSyncPromoCoordinator;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -42,14 +45,28 @@
     static TabGroupPromoCoordinator createInstance(
             @NonNull Context context,
             @NonNull Runnable onModuleClickedCallback,
+            @NonNull CallbackController callbackController,
             @NonNull ObservableSupplier<ModalDialogManager> modalDialogManagerSupplier,
-            @NonNull Runnable showTabSwitcherRunnable,
+            @NonNull ShowHubPaneCallback showHubPaneCallback,
             @NonNull Supplier<ViewGroup> parentViewSupplier) {
         return new TabGroupPromoCoordinator(
                 context,
                 onModuleClickedCallback,
+                callbackController,
                 modalDialogManagerSupplier,
-                showTabSwitcherRunnable,
+                showHubPaneCallback,
                 parentViewSupplier);
     }
+
+    /**
+     * @return An instance of TabGroupPromoSyncCoordinator.
+     */
+    static TabGroupSyncPromoCoordinator createInstance(
+            @NonNull Context context,
+            @NonNull Runnable onModuleClickedCallback,
+            @NonNull CallbackController callbackController,
+            @NonNull ShowHubPaneCallback showHubPaneCallback) {
+        return new TabGroupSyncPromoCoordinator(
+                context, onModuleClickedCallback, callbackController, showHubPaneCallback);
+    }
 }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java
index 0712b86f..7e1fe066 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java
@@ -13,12 +13,12 @@
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.ShowHubPaneCallback;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.magic_stack.ModuleConfigChecker;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 import org.chromium.chrome.browser.magic_stack.ModuleProvider;
 import org.chromium.chrome.browser.magic_stack.ModuleProviderBuilder;
-import org.chromium.chrome.browser.tab_ui.TabGridIphDialogCoordinator;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.PropertyKey;
@@ -28,22 +28,20 @@
     private final Context mContext;
     private final BottomSheetController mBottomSheetController;
     private final ObservableSupplier<ModalDialogManager> mModalDialogManagerSupplier;
-    private final Runnable mShowTabSwitcher;
+    private final ShowHubPaneCallback mShowHubPaneCallback;
     private final Supplier<ViewGroup> mParentViewSupplier;
 
-    private TabGridIphDialogCoordinator mTabGridIphDialogCoordinator;
-
     /** Pass in the dependencies needed to build {@link EducationalTipModuleCoordinator}. */
     public EducationalTipModuleBuilder(
             @NonNull Context context,
             @NonNull BottomSheetController bottomSheetController,
             @NonNull ObservableSupplier<ModalDialogManager> modalDialogManagerSupplier,
-            @NonNull Runnable showTabSwitcherRunnable,
+            @NonNull ShowHubPaneCallback showHubPaneCallback,
             @NonNull Supplier<ViewGroup> parentViewSupplier) {
         mContext = context;
         mBottomSheetController = bottomSheetController;
         mModalDialogManagerSupplier = modalDialogManagerSupplier;
-        mShowTabSwitcher = showTabSwitcherRunnable;
+        mShowHubPaneCallback = showHubPaneCallback;
         mParentViewSupplier = parentViewSupplier;
     }
 
@@ -62,7 +60,7 @@
                         moduleDelegate,
                         mBottomSheetController,
                         mModalDialogManagerSupplier,
-                        mShowTabSwitcher,
+                        mShowHubPaneCallback,
                         mParentViewSupplier);
         onModuleBuiltCallback.onResult(coordinator);
         return true;
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java
index e7034908..f657193 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java
@@ -11,6 +11,7 @@
 
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.ShowHubPaneCallback;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 import org.chromium.chrome.browser.magic_stack.ModuleProvider;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
@@ -26,7 +27,7 @@
             @NonNull ModuleDelegate moduleDelegate,
             @NonNull BottomSheetController bottomSheetController,
             @NonNull ObservableSupplier<ModalDialogManager> modalDialogManagerSupplier,
-            @NonNull Runnable showTabSwitcherRunnable,
+            @NonNull ShowHubPaneCallback showHubPaneCallback,
             @NonNull Supplier<ViewGroup> parentViewSupplier) {
         PropertyModel model = new PropertyModel(EducationalTipModuleProperties.ALL_KEYS);
         mMediator =
@@ -36,7 +37,7 @@
                         moduleDelegate,
                         bottomSheetController,
                         modalDialogManagerSupplier,
-                        showTabSwitcherRunnable,
+                        showHubPaneCallback,
                         parentViewSupplier);
     }
 
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java
index 500e834..f5c5d82 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java
@@ -9,9 +9,11 @@
 
 import androidx.annotation.NonNull;
 
+import org.chromium.base.CallbackController;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.EducationalTipCardType;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.ShowHubPaneCallback;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType;
@@ -22,6 +24,7 @@
 /** Mediator for the educational tip module. */
 public class EducationalTipModuleMediator {
     private static final String FORCE_TAB_GROUP = "force_tab_group";
+    private static final String FORCE_TAB_GROUP_SYNC = "force_tab_group_sync";
 
     private final Context mContext;
     private final @ModuleType int mModuleType;
@@ -29,8 +32,9 @@
     private final ModuleDelegate mModuleDelegate;
     private final BottomSheetController mBottomSheetController;
     private final ObservableSupplier<ModalDialogManager> mModalDialogManagerSupplier;
-    private final Runnable mShowTabSwitcherRunnable;
+    private final ShowHubPaneCallback mShowHubPaneCallback;
     private final Supplier<ViewGroup> mParentViewSupplier;
+    private final CallbackController mCallbackController;
 
     private EducationalTipCardProvider mEducationalTipCardProvider;
 
@@ -40,7 +44,7 @@
             @NonNull ModuleDelegate moduleDelegate,
             @NonNull BottomSheetController bottomSheetController,
             @NonNull ObservableSupplier<ModalDialogManager> modalDialogManagerSupplier,
-            @NonNull Runnable showTabSwitcherRunnable,
+            @NonNull ShowHubPaneCallback showHubPaneCallback,
             @NonNull Supplier<ViewGroup> parentViewSupplier) {
         mContext = context;
         mModuleType = ModuleType.EDUCATIONAL_TIP;
@@ -48,8 +52,10 @@
         mModuleDelegate = moduleDelegate;
         mBottomSheetController = bottomSheetController;
         mModalDialogManagerSupplier = modalDialogManagerSupplier;
-        mShowTabSwitcherRunnable = showTabSwitcherRunnable;
+        mShowHubPaneCallback = showHubPaneCallback;
         mParentViewSupplier = parentViewSupplier;
+
+        mCallbackController = new CallbackController();
     }
 
     /** Show the educational tip module. */
@@ -61,10 +67,17 @@
                     EducationalTipCardProviderFactory.createInstance(
                             mContext,
                             this::removeModule,
+                            mCallbackController,
                             mModalDialogManagerSupplier,
-                            mShowTabSwitcherRunnable,
+                            mShowHubPaneCallback,
                             mParentViewSupplier);
-
+        } else if (type == EducationalTipCardType.TAB_GROUP_SYNC) {
+            mEducationalTipCardProvider =
+                    EducationalTipCardProviderFactory.createInstance(
+                            mContext,
+                            this::removeModule,
+                            mCallbackController,
+                            mShowHubPaneCallback);
         } else {
             mEducationalTipCardProvider =
                     EducationalTipCardProviderFactory.createInstance(
@@ -95,6 +108,9 @@
         if (ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
                 ChromeFeatureList.EDUCATIONAL_TIP_MODULE, FORCE_TAB_GROUP, false)) {
             return EducationalTipCardType.TAB_GROUPS;
+        } else if (ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                ChromeFeatureList.EDUCATIONAL_TIP_MODULE, FORCE_TAB_GROUP_SYNC, false)) {
+            return EducationalTipCardType.TAB_GROUP_SYNC;
         }
         return EducationalTipCardType.DEFAULT_BROWSER_PROMO;
     }
@@ -109,6 +125,7 @@
             mEducationalTipCardProvider.destroy();
             mEducationalTipCardProvider = null;
         }
+        mCallbackController.destroy();
     }
 
     /**
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java
index 4cace2a2..2a3a625 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java
@@ -16,6 +16,7 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider;
 import org.chromium.chrome.browser.educational_tip.R;
+import org.chromium.chrome.browser.hub.PaneId;
 import org.chromium.chrome.browser.tab_ui.TabGridIphDialogCoordinator;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -24,7 +25,7 @@
     private final Context mContext;
 
     private final ObservableSupplier<ModalDialogManager> mModalDialogManagerSupplier;
-    private final Runnable mShowTabSwitcherRunnable;
+    private final ShowHubPaneCallback mShowHubPaneCallback;
     private final Supplier<ViewGroup> mParentViewSupplier;
     private final Runnable mOnClickedRunnable;
     private CallbackController mCallbackController;
@@ -34,21 +35,22 @@
      * @param context The Context of the application.
      * @param onModuleClickedCallback The callback to be called when the module is clicked.
      * @param modalDialogManagerSupplier The supplier of {@link ModalDialogManager} instance.
-     * @param showTabSwitcherRunnable The runnable to open the tab switcher.
+     * @param showHubPaneCallback The callback to open a Hub pane.
      * @param parentViewSupplier The supplier of the parent view.
      */
     public TabGroupPromoCoordinator(
             @NonNull Context context,
             @NonNull Runnable onModuleClickedCallback,
+            @NonNull CallbackController callbackController,
             @NonNull ObservableSupplier<ModalDialogManager> modalDialogManagerSupplier,
-            @NonNull Runnable showTabSwitcherRunnable,
+            @NonNull ShowHubPaneCallback showHubPaneCallback,
             @NonNull Supplier<ViewGroup> parentViewSupplier) {
         mContext = context;
+        mCallbackController = callbackController;
         mModalDialogManagerSupplier = modalDialogManagerSupplier;
-        mShowTabSwitcherRunnable = showTabSwitcherRunnable;
+        mShowHubPaneCallback = showHubPaneCallback;
         mParentViewSupplier = parentViewSupplier;
 
-        mCallbackController = new CallbackController();
         mOnClickedRunnable =
                 mCallbackController.makeCancelable(
                         () -> {
@@ -59,7 +61,7 @@
                                 mTabGridIphDialogCoordinator.setParentView(
                                         mParentViewSupplier.get());
                             }
-                            mShowTabSwitcherRunnable.run();
+                            mShowHubPaneCallback.onClick(PaneId.TAB_SWITCHER);
                             mTabGridIphDialogCoordinator.showIph();
                             onModuleClickedCallback.run();
                         });
@@ -91,7 +93,6 @@
         if (mTabGridIphDialogCoordinator != null) {
             mTabGridIphDialogCoordinator.setParentView(null);
         }
-        mCallbackController.destroy();
     }
 
     public void setTabGridIphDialogCoordinatorForTesting(
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java
new file mode 100644
index 0000000..2e0a71fd
--- /dev/null
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java
@@ -0,0 +1,69 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.educational_tip.cards;
+
+import android.content.Context;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+
+import org.chromium.base.CallbackController;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider;
+import org.chromium.chrome.browser.educational_tip.R;
+import org.chromium.chrome.browser.hub.PaneId;
+
+/** Coordinator for the Tab group sync promo card. */
+public class TabGroupSyncPromoCoordinator implements EducationalTipCardProvider {
+
+    private final Context mContext;
+    private final ShowHubPaneCallback mShowHubPaneRunnable;
+    private final Runnable mOnClickedRunnable;
+    private CallbackController mCallbackController;
+
+    /**
+     * @param context The Context of the application.
+     * @param onModuleClickedCallback The callback to be called when the module is clicked.
+     * @param callbackController The instance of {@link CallbackController}.
+     * @param showHubPaneCallback The callback to open a Hub Pane.
+     */
+    public TabGroupSyncPromoCoordinator(
+            @NonNull Context context,
+            @NonNull Runnable onModuleClickedCallback,
+            @NonNull CallbackController callbackController,
+            @NonNull ShowHubPaneCallback showHubPaneCallback) {
+        mContext = context;
+        mShowHubPaneRunnable = showHubPaneCallback;
+        mCallbackController = callbackController;
+
+        mOnClickedRunnable =
+                mCallbackController.makeCancelable(
+                        () -> {
+                            mShowHubPaneRunnable.onClick(PaneId.TAB_GROUPS);
+                            onModuleClickedCallback.run();
+                        });
+    }
+
+    // EducationalTipCardProvider implementation.
+
+    @Override
+    public String getCardTitle() {
+        return mContext.getString(R.string.educational_tip_tab_group_sync_title);
+    }
+
+    @Override
+    public String getCardDescription() {
+        return mContext.getString(R.string.educational_tip_tab_group_sync_description);
+    }
+
+    @Override
+    public @DrawableRes int getCardImage() {
+        return R.drawable.tab_group_sync_promo_logo;
+    }
+
+    @Override
+    public void onCardClicked() {
+        mOnClickedRunnable.run();
+    }
+}
diff --git a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java
index c83dc67a..dc27a5b 100644
--- a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java
+++ b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java
@@ -29,6 +29,7 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.ShowHubPaneCallback;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 import org.chromium.chrome.browser.magic_stack.ModuleProvider;
@@ -47,7 +48,7 @@
     @Mock private Callback<ModuleProvider> mBuildCallback;
     @Mock private BottomSheetController mBottomSheetController;
     @Mock private ViewGroup mParentView;
-    @Mock private Runnable mShowTabSwitcherRunnable;
+    @Mock private ShowHubPaneCallback mShowHubPaneCallback;
 
     private EducationalTipModuleBuilder mModuleBuilder;
     private ObservableSupplierImpl<ViewGroup> mParentViewSupplier;
@@ -62,7 +63,7 @@
                         RuntimeEnvironment.application,
                         mBottomSheetController,
                         new ObservableSupplierImpl<>(),
-                        mShowTabSwitcherRunnable,
+                        mShowHubPaneCallback,
                         mParentViewSupplier);
     }
 
diff --git a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/TabGroupPromoCoordinatorUnitTest.java b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/TabGroupPromoCoordinatorUnitTest.java
index 2b4040f..b28ea0b 100644
--- a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/TabGroupPromoCoordinatorUnitTest.java
+++ b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/TabGroupPromoCoordinatorUnitTest.java
@@ -23,12 +23,15 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.CallbackController;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.ShowHubPaneCallback;
 import org.chromium.chrome.browser.educational_tip.cards.TabGroupPromoCoordinator;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.hub.PaneId;
 import org.chromium.chrome.browser.tab_ui.TabGridIphDialogCoordinator;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.shadows.ShadowAppCompatResources;
@@ -43,7 +46,7 @@
     @Mock private Context mContext;
     @Mock private ModalDialogManager mModalDialogManager;
     @Mock private Runnable mOnModuleClickedCallback;
-    @Mock private Runnable mShowTabSwitcherRunnable;
+    @Mock private ShowHubPaneCallback mShowHubPaneCallback;
     @Mock private Supplier<ViewGroup> mParentViewSupplier;
     @Mock private ViewGroup mParentView;
     @Mock private TabGridIphDialogCoordinator mTabGridIphDialogCoordinator;
@@ -51,6 +54,7 @@
     private ObservableSupplierImpl<ModalDialogManager> mModalDialogManagerSupplier;
 
     private TabGroupPromoCoordinator mTabGroupPromoCoordinator;
+    private CallbackController mCallbackController;
 
     @Before
     public void setUp() {
@@ -58,13 +62,15 @@
         mModalDialogManagerSupplier.set(mModalDialogManager);
 
         when(mParentViewSupplier.get()).thenReturn(mParentView);
+        mCallbackController = new CallbackController();
 
         mTabGroupPromoCoordinator =
                 new TabGroupPromoCoordinator(
                         mContext,
                         mOnModuleClickedCallback,
+                        mCallbackController,
                         mModalDialogManagerSupplier,
-                        mShowTabSwitcherRunnable,
+                        mShowHubPaneCallback,
                         mParentViewSupplier);
         mTabGroupPromoCoordinator.setTabGridIphDialogCoordinatorForTesting(
                 mTabGridIphDialogCoordinator);
@@ -78,7 +84,7 @@
 
         mTabGroupPromoCoordinator.onCardClicked();
         verify(mTabGridIphDialogCoordinator).showIph();
-        verify(mShowTabSwitcherRunnable).run();
+        verify(mShowHubPaneCallback).onClick(eq(PaneId.TAB_SWITCHER));
         verify(mOnModuleClickedCallback).run();
     }
 
diff --git a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/TabGroupSyncPromoCoordinatorUnitTest.java b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/TabGroupSyncPromoCoordinatorUnitTest.java
new file mode 100644
index 0000000..1b529f1
--- /dev/null
+++ b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/TabGroupSyncPromoCoordinatorUnitTest.java
@@ -0,0 +1,69 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.educational_tip;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.CallbackController;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.ShowHubPaneCallback;
+import org.chromium.chrome.browser.educational_tip.cards.TabGroupSyncPromoCoordinator;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.hub.PaneId;
+import org.chromium.ui.shadows.ShadowAppCompatResources;
+
+/** Test relating to {@link TabGroupSyncPromoCoordinator} */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(
+        manifest = Config.NONE,
+        shadows = {ShadowAppCompatResources.class})
+public class TabGroupSyncPromoCoordinatorUnitTest {
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock private Context mContext;
+    @Mock private Runnable mOnModuleClickedCallback;
+    @Mock private ShowHubPaneCallback mShowHubPaneCallback;
+
+    private TabGroupSyncPromoCoordinator mTabGroupSyncPromoCoordinator;
+    private CallbackController mCallbackController;
+
+    @Before
+    public void setUp() {
+        mCallbackController = new CallbackController();
+
+        mTabGroupSyncPromoCoordinator =
+                new TabGroupSyncPromoCoordinator(
+                        mContext,
+                        mOnModuleClickedCallback,
+                        mCallbackController,
+                        mShowHubPaneCallback);
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.EDUCATIONAL_TIP_MODULE})
+    public void testClickTabGroupPromoCard() {
+        assertTrue(ChromeFeatureList.sEducationalTipModule.isEnabled());
+
+        mTabGroupSyncPromoCoordinator.onCardClicked();
+        verify(mShowHubPaneCallback).onClick(eq(PaneId.TAB_GROUPS));
+        verify(mOnModuleClickedCallback).run();
+    }
+}
diff --git a/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.cc b/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.cc
index aabcdf23..e4c21c4 100644
--- a/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.cc
+++ b/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.cc
@@ -10,20 +10,19 @@
 
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
 #include "chrome/browser/enterprise/data_controls/chrome_rules_service.h"
-#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog.h"
-#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog_factory.h"
 #include "chrome/browser/enterprise/data_controls/reporting_service.h"
 #include "chrome/browser/enterprise/data_protection/paste_allowed_request.h"
 #include "components/enterprise/common/files_scan_data.h"
 #include "components/enterprise/connectors/core/connectors_prefs.h"
 #include "components/enterprise/content/clipboard_restriction_service.h"
 #include "components/enterprise/data_controls/content/browser/last_replaced_clipboard_data.h"
+#include "components/enterprise/data_controls/core/browser/data_controls_dialog_factory.h"
 #include "components/enterprise/data_controls/core/browser/prefs.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/clipboard_types.h"
+#include "content/public/browser/web_contents.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/clipboard/clipboard_observer.h"
@@ -32,10 +31,37 @@
 #include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
+#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
+#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog.h"
+#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog_factory.h"
+#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
+
 namespace enterprise_data_protection {
 
 namespace {
 
+bool SkipDataControlOrContentAnalysisChecks(
+    const content::ClipboardEndpoint& main_endpoint) {
+  // Data Controls and content analysis copy/paste checks require an active tab
+  // to be meaningful, so if it's gone they can be skipped.
+  auto* web_contents = main_endpoint.web_contents();
+  if (!web_contents) {
+    return true;
+  }
+
+  // Data Controls and content analysis copy/paste checks are only meaningful in
+  // Chrome tabs, so they should always be skipped for source-only checks (ex.
+  // copy prevention checks).
+  if (!main_endpoint.data_transfer_endpoint().has_value() ||
+      !main_endpoint.data_transfer_endpoint()->IsUrlType()) {
+    return true;
+  }
+
+  return false;
+}
+
+#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
 void HandleFileData(
     content::WebContents* web_contents,
     enterprise_connectors::ContentAnalysisDelegate::Data dialog_data,
@@ -108,26 +134,6 @@
       safe_browsing::DeepScanAccessPoint::PASTE);
 }
 
-bool SkipDataControlOrContentAnalysisChecks(
-    const content::ClipboardEndpoint& main_endpoint) {
-  // Data Controls and content analysis copy/paste checks require an active tab
-  // to be meaningful, so if it's gone they can be skipped.
-  auto* web_contents = main_endpoint.web_contents();
-  if (!web_contents) {
-    return true;
-  }
-
-  // Data Controls and content analysis copy/paste checks are only meaningful in
-  // Chrome tabs, so they should always be skipped for source-only checks (ex.
-  // copy prevention checks).
-  if (!main_endpoint.data_transfer_endpoint().has_value() ||
-      !main_endpoint.data_transfer_endpoint()->IsUrlType()) {
-    return true;
-  }
-
-  return false;
-}
-
 void PasteIfAllowedByContentAnalysis(
     content::WebContents* web_contents,
     const content::ClipboardEndpoint& source,
@@ -183,12 +189,22 @@
                      std::move(dialog_data), std::move(callback));
   }
 }
+#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
+
+data_controls::DataControlsDialogFactory* GetDialogFactory() {
+#if BUILDFLAG(IS_ANDROID)
+  return nullptr;
+#else
+  return data_controls::DesktopDataControlsDialogFactory::GetInstance();
+#endif
+}
 
 void MaybeReportDataControlsPaste(const content::ClipboardEndpoint& source,
                                   const content::ClipboardEndpoint& destination,
                                   const content::ClipboardMetadata& metadata,
                                   const data_controls::Verdict& verdict,
                                   bool bypassed = false) {
+#if !BUILDFLAG(IS_ANDROID)
   auto* reporting_service =
       data_controls::ReportingServiceFactory::GetInstance()
           ->GetForBrowserContext(destination.browser_context());
@@ -205,12 +221,14 @@
   } else {
     reporting_service->ReportPaste(source, destination, metadata, verdict);
   }
+#endif  // !BUILDFLAG(IS_ANDROID)
 }
 
 void MaybeReportDataControlsCopy(const content::ClipboardEndpoint& source,
                                  const content::ClipboardMetadata& metadata,
                                  const data_controls::Verdict& verdict,
                                  bool bypassed = false) {
+#if !BUILDFLAG(IS_ANDROID)
   auto* reporting_service =
       data_controls::ReportingServiceFactory::GetInstance()
           ->GetForBrowserContext(source.browser_context());
@@ -226,6 +244,7 @@
   } else {
     reporting_service->ReportCopy(source, metadata, verdict);
   }
+#endif  // !BUILDFLAG(IS_ANDROID)
 }
 
 void OnDataControlsPasteWarning(
@@ -246,9 +265,13 @@
                                  /*bypassed=*/true);
   }
 
+#if BUILDFLAG(IS_ANDROID)
+  std::move(callback).Run(std::move(clipboard_paste_data));
+#else
   PasteIfAllowedByContentAnalysis(
       destination.web_contents(), source, destination, metadata,
       std::move(clipboard_paste_data), std::move(callback));
+#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 void PasteIfAllowedByDataControls(
@@ -271,28 +294,28 @@
         std::move(verdict));
   }
 
+  auto* factory = GetDialogFactory();
   if (verdict.level() == data_controls::Rule::Level::kBlock) {
     MaybeReportDataControlsPaste(source, destination, metadata, verdict);
-    // TODO(b/351342878): Replace this with a factory method call on an object
-    // passed to the function.
-    data_controls::DesktopDataControlsDialogFactory::GetInstance()
-        ->ShowDialogIfNeeded(
-            destination.web_contents(),
-            data_controls::DataControlsDialog::Type::kClipboardPasteBlock);
+    if (factory) {
+      factory->ShowDialogIfNeeded(
+          destination.web_contents(),
+          data_controls::DataControlsDialog::Type::kClipboardPasteBlock);
+    }
     std::move(callback).Run(std::nullopt);
     return;
   } else if (verdict.level() == data_controls::Rule::Level::kWarn) {
     MaybeReportDataControlsPaste(source, destination, metadata, verdict);
-    // TODO(b/351342878): Replace this with a factory method call on an object
-    // passed to the function.
-    data_controls::DesktopDataControlsDialogFactory::GetInstance()
-        ->ShowDialogIfNeeded(
-            destination.web_contents(),
-            data_controls::DataControlsDialog::Type::kClipboardPasteWarn,
-            base::BindOnce(&OnDataControlsPasteWarning, source, destination,
-                           metadata, std::move(verdict),
-                           std::move(clipboard_paste_data),
-                           std::move(callback)));
+    if (factory) {
+      factory->ShowDialogIfNeeded(
+          destination.web_contents(),
+          data_controls::DataControlsDialog::Type::kClipboardPasteWarn,
+          base::BindOnce(&OnDataControlsPasteWarning, source, destination,
+                         metadata, std::move(verdict),
+                         std::move(clipboard_paste_data), std::move(callback)));
+    } else {
+      std::move(callback).Run(std::nullopt);
+    }
     return;
   } else if (verdict.level() == data_controls::Rule::Level::kReport) {
     MaybeReportDataControlsPaste(source, destination, metadata, verdict);
@@ -309,9 +332,13 @@
         data_controls::GetLastReplacedClipboardData().clipboard_paste_data;
   }
 
+#if BUILDFLAG(IS_ANDROID)
+  std::move(callback).Run(std::move(clipboard_paste_data));
+#else
   PasteIfAllowedByContentAnalysis(
       destination.web_contents(), source, destination, metadata,
       std::move(clipboard_paste_data), std::move(callback));
+#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 void OnDlpRulesCheckDone(
@@ -396,14 +423,14 @@
           ->GetCopyRestrictedBySourceVerdict(
               *source.data_transfer_endpoint()->GetURL());
 
+  auto* factory = GetDialogFactory();
   if (source_only_verdict.level() == data_controls::Rule::Level::kBlock) {
     MaybeReportDataControlsCopy(source, metadata, source_only_verdict);
-    // TODO(b/351342878): Replace this with a factory method call on an object
-    // passed to the function.
-    data_controls::DesktopDataControlsDialogFactory::GetInstance()
-        ->ShowDialogIfNeeded(
-            source.web_contents(),
-            data_controls::DataControlsDialog::Type::kClipboardCopyBlock);
+    if (factory) {
+      factory->ShowDialogIfNeeded(
+          source.web_contents(),
+          data_controls::DataControlsDialog::Type::kClipboardCopyBlock);
+    }
     return;
   }
 
@@ -420,14 +447,13 @@
     auto verdict = data_controls::Verdict::MergeCopyWarningVerdicts(
         std::move(source_only_verdict), std::move(os_clipboard_verdict));
     MaybeReportDataControlsCopy(source, metadata, verdict);
-    // TODO(b/351342878): Replace this with a factory method call on an object
-    // passed to the function.
-    data_controls::DesktopDataControlsDialogFactory::GetInstance()
-        ->ShowDialogIfNeeded(
-            source.web_contents(),
-            data_controls::DataControlsDialog::Type::kClipboardCopyWarn,
-            base::BindOnce(&OnDataControlsCopyWarning, source, metadata, data,
-                           std::move(verdict), std::move(callback)));
+    if (factory) {
+      factory->ShowDialogIfNeeded(
+          source.web_contents(),
+          data_controls::DataControlsDialog::Type::kClipboardCopyWarn,
+          base::BindOnce(&OnDataControlsCopyWarning, source, metadata, data,
+                         std::move(verdict), std::move(callback)));
+    }
     return;
   }
 
@@ -487,11 +513,12 @@
     std::move(callback).Run(metadata.format_type, data, std::nullopt);
     return;
   }
-
   DCHECK(source.web_contents());
   DCHECK(source.browser_context());
   DCHECK(source.data_transfer_endpoint());
   DCHECK(source.data_transfer_endpoint()->IsUrlType());
+
+#if !BUILDFLAG(IS_ANDROID)
   const GURL& url = *source.data_transfer_endpoint()->GetURL();
 
   std::u16string replacement_data;
@@ -504,6 +531,7 @@
                             std::move(replacement_data));
     return;
   }
+#endif  // !BUILDFLAG(IS_ANDROID)
 
   IsCopyRestrictedByDialog(source, metadata, data, std::move(callback));
 }
diff --git a/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h b/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h
index 9a78ba6..c0a32a9e 100644
--- a/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h
+++ b/chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_ENTERPRISE_DATA_PROTECTION_DATA_PROTECTION_CLIPBOARD_UTILS_H_
 
 #include "base/feature_list.h"
-#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
+#include "components/enterprise/buildflags/buildflags.h"
 #include "components/enterprise/common/files_scan_data.h"
 #include "content/public/browser/content_browser_client.h"
 
diff --git a/chrome/browser/enterprise/data_protection/paste_allowed_request.cc b/chrome/browser/enterprise/data_protection/paste_allowed_request.cc
index 325544d..cc79647 100644
--- a/chrome/browser/enterprise/data_protection/paste_allowed_request.cc
+++ b/chrome/browser/enterprise/data_protection/paste_allowed_request.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h"
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
 
 namespace enterprise_data_protection {
 
diff --git a/chrome/browser/enterprise/data_protection/paste_allowed_request_unittest.cc b/chrome/browser/enterprise/data_protection/paste_allowed_request_unittest.cc
index 5c11719..55683d17 100644
--- a/chrome/browser/enterprise/data_protection/paste_allowed_request_unittest.cc
+++ b/chrome/browser/enterprise/data_protection/paste_allowed_request_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/test/bind.h"
 #include "base/test/test_future.h"
+#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
 #include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_base.h"
 #include "chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h"
 #include "chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h"
diff --git a/chrome/browser/enterprise/signals/context_info_fetcher.cc b/chrome/browser/enterprise/signals/context_info_fetcher.cc
index 468feb2d..265a56e 100644
--- a/chrome/browser/enterprise/signals/context_info_fetcher.cc
+++ b/chrome/browser/enterprise/signals/context_info_fetcher.cc
@@ -153,7 +153,11 @@
     return SettingValue::UNKNOWN;
   }
 
-  if (output.find("(State = 1)") != std::string::npos) {
+  // State 1 is when the Firewall is simply enabled.
+  // State 2 is when the Firewall is enabled and all incoming connections are
+  // blocked.
+  if (output.find("(State = 1)") != std::string::npos ||
+      output.find("(State = 2)") != std::string::npos) {
     return SettingValue::ENABLED;
   }
   if (output.find("(State = 0)") != std::string::npos) {
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 06e47bd..3c98854 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -1009,8 +1009,10 @@
     return api::tabs::TabStatus::kLoading;
   }
 
-  // Anything that isn't backed by a process is considered unloaded.
-  if (!HasValidMainFrameProcess(contents)) {
+  // Anything that isn't backed by a process is considered unloaded. Discarded
+  // tabs should also be considered unloaded as the tab itself may be retained
+  // but the hosted document discarded to reclaim resources.
+  if (!HasValidMainFrameProcess(contents) || contents->WasDiscarded()) {
     return api::tabs::TabStatus::kUnloaded;
   }
 
diff --git a/chrome/browser/extensions/install_signer.cc b/chrome/browser/extensions/install_signer.cc
index 88ef326..b4eeb09 100644
--- a/chrome/browser/extensions/install_signer.cc
+++ b/chrome/browser/extensions/install_signer.cc
@@ -95,11 +95,11 @@
   std::unique_ptr<crypto::SecureHash> hash(
       crypto::SecureHash::Create(crypto::SecureHash::SHA256));
 
-  hash->Update(machine_id.data(), machine_id.size());
-  hash->Update(salt.data(), salt.size());
+  hash->Update(base::as_byte_span(machine_id));
+  hash->Update(base::as_byte_span(salt));
 
-  std::string result_bytes(crypto::kSHA256Length, 0);
-  hash->Finish(std::data(result_bytes), result_bytes.size());
+  std::array<uint8_t, crypto::kSHA256Length> result_bytes;
+  hash->Finish(result_bytes);
 
   *result = base::Base64Encode(result_bytes);
   return true;
diff --git a/chrome/browser/extensions/updater/local_extension_cache_unittest.cc b/chrome/browser/extensions/updater/local_extension_cache_unittest.cc
index 90018fa..f1c3acc 100644
--- a/chrome/browser/extensions/updater/local_extension_cache_unittest.cc
+++ b/chrome/browser/extensions/updater/local_extension_cache_unittest.cc
@@ -21,7 +21,6 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
-#include "crypto/secure_hash.h"
 #include "crypto/sha2.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -82,13 +81,8 @@
                                         const base::Time& timestamp,
                                         base::FilePath* filename) {
     std::string data(size, 0);
-
-    std::unique_ptr<crypto::SecureHash> hash =
-        crypto::SecureHash::Create(crypto::SecureHash::SHA256);
-    hash->Update(data.c_str(), size);
-    uint8_t output[crypto::kSHA256Length];
-    hash->Finish(output, sizeof(output));
-    const std::string hex_hash = base::ToLowerASCII(base::HexEncode(output));
+    const std::string hex_hash = base::ToLowerASCII(
+        base::HexEncode(crypto::SHA256Hash(base::as_byte_span(data))));
 
     const base::FilePath file =
         GetExtensionFileName(dir, id, version, hex_hash);
diff --git a/chrome/browser/extensions/web_accessible_resources_browsertest.cc b/chrome/browser/extensions/web_accessible_resources_browsertest.cc
index 08820e1..f88cac2 100644
--- a/chrome/browser/extensions/web_accessible_resources_browsertest.cc
+++ b/chrome/browser/extensions/web_accessible_resources_browsertest.cc
@@ -4,8 +4,11 @@
 
 #include "base/files/file_path.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/version_info/channel.h"
@@ -13,6 +16,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
+#include "extensions/browser/background_script_executor.h"
 #include "extensions/common/extension_features.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/test_extension_dir.h"
@@ -352,5 +356,75 @@
   EXPECT_EQ("dnr redirect success", result.ExtractString());
 }
 
+class WebAccessibleResourcesBrowserRedirectTest
+    : public WebAccessibleResourcesBrowserTest {
+ protected:
+  void TestBrowserRedirect(const char* kManifest, const char* kHistogramName) {
+    // Load extension.
+    TestExtensionDir test_dir;
+    test_dir.WriteManifest(kManifest);
+    test_dir.WriteFile(FILE_PATH_LITERAL("resource.html"), "resource.html");
+    test_dir.WriteFile(FILE_PATH_LITERAL("web_accessible_resource.html"),
+                       "web_accessible_resource.html");
+    const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+
+    base::HistogramTester histogram_tester;
+
+    // Test extension resource accessibility.
+    auto server_redirect = [&](int expect_net_error, const char* resource,
+                               int histogram_count) {
+      GURL gurl = embedded_test_server()->GetURL(
+          "example.com",
+          base::StringPrintf(
+              "/server-redirect?%s",
+              extension->GetResourceURL(resource).spec().c_str()));
+      auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+      content::TestNavigationObserver observer(web_contents);
+      EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
+      observer.WaitForNavigationFinished();
+      EXPECT_EQ(extension->GetResourceURL(resource),
+                observer.last_navigation_url());
+      EXPECT_EQ(expect_net_error == net::OK,
+                observer.last_navigation_succeeded());
+      EXPECT_EQ(expect_net_error, observer.last_net_error_code());
+      histogram_tester.ExpectBucketCount(kHistogramName, false,
+                                         histogram_count);
+    };
+
+    // Test cases.
+    server_redirect(net::OK, "web_accessible_resource.html", 0);
+    server_redirect(net::OK, "resource.html", 1);
+  }
+};
+
+// Test server redirect to a web accessible or extension resource.
+IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserRedirectTest, MV2) {
+  TestBrowserRedirect(
+      R"({
+      "name": "Test browser redirect",
+      "version": "0.1",
+      "manifest_version": 2,
+      "web_accessible_resources": ["web_accessible_resource.html"]
+    })",
+      "Extensions.WAR.XOriginWebAccessible.MV2");
+}
+
+// Test server redirect to a web accessible or extension resource.
+IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserRedirectTest, MV3) {
+  TestBrowserRedirect(
+      R"({
+      "name": "Redirect Test",
+      "version": "0.1",
+      "manifest_version": 3,
+      "web_accessible_resources": [
+        {
+          "resources": ["web_accessible_resource.html"],
+          "matches": ["http://example.com/*"]
+        }
+      ]
+    })",
+      "Extensions.WAR.XOriginWebAccessible.MV3");
+}
+
 }  // namespace
 }  // namespace extensions
diff --git a/chrome/browser/feedback/android/process_id_feedback_source.cc b/chrome/browser/feedback/android/process_id_feedback_source.cc
index 9fa1b48..4b142060 100644
--- a/chrome/browser/feedback/android/process_id_feedback_source.cc
+++ b/chrome/browser/feedback/android/process_id_feedback_source.cc
@@ -90,7 +90,7 @@
   for (size_t i = 0; i < size; i++)
     pids[i] = process_ids_[process_type][i];
 
-  return base::android::ToJavaLongArray(env, pids.data(), size);
+  return base::android::ToJavaLongArray(env, pids);
 }
 
 }  // namespace android
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 6508cb9..c450856 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1886,7 +1886,7 @@
   {
     "name": "crostini-qt-ime-support",
     "owners": [ "timloh@chromium.org", "sophialin@google.com" ],
-    "expiry_milestone": 130
+    "expiry_milestone": 150
   },
   {
     "name": "crostini-reset-lxd-db",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 97ee4f0..d092423 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4980,17 +4980,6 @@
 const char kVideoTutorialsName[] = "Enable video tutorials";
 const char kVideoTutorialsDescription[] = "Show video tutorials in Chrome";
 
-const char kAdaptiveButtonInTopToolbarTranslateName[] =
-    "Adaptive button in top toolbar - Translate button";
-const char kAdaptiveButtonInTopToolbarTranslateDescription[] =
-    "Enables a translate button in the top toolbar. Must be selected in "
-    "Settings > Toolbar Shortcut.";
-const char kAdaptiveButtonInTopToolbarAddToBookmarksName[] =
-    "Adaptive button in top toolbar - Add to bookmarks button";
-const char kAdaptiveButtonInTopToolbarAddToBookmarksDescription[] =
-    "Enables an add to bookmarks button in the top toolbar. Must be selected "
-    "in "
-    "Settings > Toolbar Shortcut.";
 const char kAdaptiveButtonInTopToolbarPageSummaryName[] =
     "Adaptive button in top toolbar - Page Summary";
 const char kAdaptiveButtonInTopToolbarPageSummaryDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index df1b030..8ed8a69c 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2451,10 +2451,6 @@
 extern const char kAccountPasswordsOnSigninName[];
 extern const char kAccountPasswordsOnSigninDescription[];
 
-extern const char kAdaptiveButtonInTopToolbarTranslateName[];
-extern const char kAdaptiveButtonInTopToolbarTranslateDescription[];
-extern const char kAdaptiveButtonInTopToolbarAddToBookmarksName[];
-extern const char kAdaptiveButtonInTopToolbarAddToBookmarksDescription[];
 extern const char kAdaptiveButtonInTopToolbarCustomizationName[];
 extern const char kAdaptiveButtonInTopToolbarCustomizationDescription[];
 extern const char kAdaptiveButtonInTopToolbarPageSummaryName[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index f89c9c3..074f1af 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -167,8 +167,6 @@
     &history::kOrganicRepeatableQueries,
     &history_clusters::internal::kJourneys,
     &history_clusters::internal::kOmniboxAction,
-    &kAdaptiveButtonInTopToolbarTranslate,
-    &kAdaptiveButtonInTopToolbarAddToBookmarks,
     &kAdaptiveButtonInTopToolbarCustomizationV2,
     &kAdaptiveButtonInTopToolbarPageSummary,
     &kRedirectExplicitCTAIntentsToExistingActivity,
@@ -411,14 +409,6 @@
 
 // Alphabetical:
 
-BASE_FEATURE(kAdaptiveButtonInTopToolbarTranslate,
-             "AdaptiveButtonInTopToolbarTranslate",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-BASE_FEATURE(kAdaptiveButtonInTopToolbarAddToBookmarks,
-             "AdaptiveButtonInTopToolbarAddToBookmarks",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kAdaptiveButtonInTopToolbarCustomizationV2,
              "AdaptiveButtonInTopToolbarCustomizationV2",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 581e4e3..5e1343f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -14,8 +14,6 @@
 namespace android {
 
 // Alphabetical:
-BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarTranslate);
-BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarAddToBookmarks);
 BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarCustomizationV2);
 BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarPageSummary);
 BASE_DECLARE_FEATURE(kAllowNewIncognitoTabIntents);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index d346876..0727c9962 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -155,10 +155,6 @@
     /* Alphabetical: */
     public static final String ACCOUNT_REAUTHENTICATION_RECENT_TIME_WINDOW =
             "AccountReauthenticationRecentTimeWindow";
-    public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE =
-            "AdaptiveButtonInTopToolbarTranslate";
-    public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS =
-            "AdaptiveButtonInTopToolbarAddToBookmarks";
     public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_PAGE_SUMMARY =
             "AdaptiveButtonInTopToolbarPageSummary";
     public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2 =
diff --git a/chrome/browser/google/google_brand_code_map_chromeos.cc b/chrome/browser/google/google_brand_code_map_chromeos.cc
index 94161390..57cd6b9 100644
--- a/chrome/browser/google/google_brand_code_map_chromeos.cc
+++ b/chrome/browser/google/google_brand_code_map_chromeos.cc
@@ -447,6 +447,7 @@
                      {"NTBE", {"ARRB", "AELU", "HGEA"}},
                      {"NZRH", {"NOUG", "UDYG", "ZGAU"}},
                      {"ODVK", {"VIOP", "MIHJ", "VXFY"}},
+                     {"OEER", {"TQAV", "TGPB", "AYYR"}},
                      {"OFPE", {"YFOO", "UIGY", "PFGZ"}},
                      {"OFPO", {"TSWQ", "EBUR", "JASZ"}},
                      {"OFRL", {"WFXP", "RTOK", "YKGH"}},
diff --git a/chrome/browser/importer/profile_writer_unittest.cc b/chrome/browser/importer/profile_writer_unittest.cc
index 13e8cba..9bebea2 100644
--- a/chrome/browser/importer/profile_writer_unittest.cc
+++ b/chrome/browser/importer/profile_writer_unittest.cc
@@ -265,8 +265,6 @@
   // keyword.
   keywords.push_back(CreateTemplateURL("key1", "http://key1_1.com", "n1_1"));
   keywords.push_back(CreateTemplateURL("key2", "http://key2.com", "n2"));
-  // This entry will not be added since the keyword contains spaces.
-  keywords.push_back(CreateTemplateURL("key 3", "http://key3.com", "n3"));
 
   auto profile_writer = base::MakeRefCounted<TestProfileWriter>(profile());
   profile_writer->AddKeywords(std::move(keywords), false);
diff --git a/chrome/browser/language/android/BUILD.gn b/chrome/browser/language/android/BUILD.gn
index fda5118..6dfcdff 100644
--- a/chrome/browser/language/android/BUILD.gn
+++ b/chrome/browser/language/android/BUILD.gn
@@ -15,6 +15,7 @@
   deps = [
     "$google_play_services_package:google_play_services_tasks_java",
     "//base:base_java",
+    "//build/android:build_java",
     "//chrome/browser/preferences:java",
     "//components/language/android:java",
     "//components/language/android:ulp_delegate_java",
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java
index cd3c34dc..2e74a67 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java
@@ -14,8 +14,8 @@
 import androidx.annotation.RequiresApi;
 
 import org.chromium.base.BuildInfo;
-import org.chromium.base.BundleUtils;
 import org.chromium.base.LocaleUtils;
+import org.chromium.build.BuildConfig;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 import org.chromium.components.language.LocaleManagerDelegate;
@@ -28,8 +28,8 @@
 import java.util.Locale;
 
 /**
- * Provides utility functions to assist with overriding the application language.
- * This class manages the AppLanguagePref.
+ * Provides utility functions to assist with overriding the application language. This class manages
+ * the AppLanguagePref.
  */
 public class AppLocaleUtils {
     private AppLocaleUtils() {}
@@ -159,7 +159,7 @@
         // If this is not a bundle build or the default system language is being used the language
         // split should not be installed. Instead indicate that the listener completed successfully
         // since the language resources will already be present.
-        if (!BundleUtils.isBundle() || isFollowSystemLanguage(languageName)) {
+        if (!BuildConfig.IS_BUNDLE || isFollowSystemLanguage(languageName)) {
             wrappedListener.onComplete(true);
         } else {
             LanguageSplitInstaller.getInstance().installLanguage(languageName, wrappedListener);
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageSplitInstaller.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageSplitInstaller.java
index a43c0eaf..c9a503c3 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageSplitInstaller.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageSplitInstaller.java
@@ -12,10 +12,10 @@
 import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener;
 import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus;
 
-import org.chromium.base.BundleUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.BuildConfig;
 import org.chromium.ui.base.ResourceBundle;
 
 import java.lang.annotation.Retention;
@@ -77,11 +77,12 @@
 
     /**
      * Get the set of installed languages as language code strings.
+     *
      * @return Set<String> of installed languages code strings.
      */
     public Set<String> getInstalledLanguages() {
         // On non-bundle builds return all packaged locales.
-        if (!BundleUtils.isBundle()) {
+        if (!BuildConfig.IS_BUNDLE) {
             return new HashSet<String>(Arrays.asList(ResourceBundle.getAvailableLocales()));
         }
         return mSplitInstallManager.getInstalledLanguages();
diff --git a/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
index de5dfef..9e66874 100644
--- a/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
+++ b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
@@ -42,7 +42,8 @@
 
   if (quarantine_remote) {
     quarantine_remote->QuarantineFile(
-        dest_platform_path, GURL(), GURL(), std::string(),
+        dest_platform_path, GURL(), GURL(), /*request_initiator=*/std::nullopt,
+        std::string(),
         base::BindOnce(&OnFileQuarantined, std::move(result_callback)));
   } else {
     std::move(result_callback).Run(base::File::FILE_OK);
diff --git a/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc b/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc
index e37a46b..d3747ad 100644
--- a/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc
+++ b/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc
@@ -89,10 +89,10 @@
   std::unique_ptr<crypto::SecureHash> hasher =
       crypto::SecureHash::Create(crypto::SecureHash::Algorithm::SHA256);
   for (const std::string& serialized_contact : serialized_contacts_set) {
-    hasher->Update(serialized_contact.data(), serialized_contact.size());
+    hasher->Update(base::as_byte_span(serialized_contact));
   }
   std::vector<uint8_t> hash(hasher->GetHashLength());
-  hasher->Finish(hash.data(), hash.size());
+  hasher->Finish(hash);
 
   return base::HexEncode(hash);
 }
diff --git a/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.cc
index 29a86927..dbf7f13 100644
--- a/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.cc
@@ -8,8 +8,6 @@
 
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/web_contents.h"
 #include "services/metrics/public/cpp/metrics_utils.h"
 #include "services/network/public/cpp/network_quality_tracker.h"
 
@@ -19,8 +17,6 @@
 const char kSuffixRTTBelow200[] = ".RTTBelow200";
 const char kSuffixRTT200to450[] = ".RTT200To450";
 const char kSuffixRTTAbove450[] = ".RTTAbove450";
-const char kIncognito[] = ".Incognito";
-const char kNoIncognito[] = ".NoIncognito";
 
 }  // namespace internal
 
@@ -47,21 +43,14 @@
 
 std::vector<std::string>
 ChromeGWSAbandonedPageLoadMetricsObserver::GetAdditionalSuffixes() const {
-  std::vector<std::string> suffixes;
-  // Add the incognito suffix if the current profile is incognito mode.
-  for (std::string& suffix :
-       GWSAbandonedPageLoadMetricsObserver::GetAdditionalSuffixes()) {
-    suffixes.push_back(suffix);
-    suffixes.push_back(suffix + (IsIncognitoProfile()
-                                     ? internal::kIncognito
-                                     : internal::kNoIncognito));
-  }
+  std::vector<std::string> base_suffixes =
+      GWSAbandonedPageLoadMetricsObserver::GetAdditionalSuffixes();
   // Make sure each histogram logged will log a version without connection type,
   // and a version with the connection type, to allow filtering if needed.
   // TODO(https://crbug.com/347706997): Consider doing this for the WebView
   // version as well.
   std::vector<std::string> suffixes_with_rtt;
-  for (std::string& base_suffix : suffixes) {
+  for (std::string& base_suffix : base_suffixes) {
     suffixes_with_rtt.push_back(base_suffix);
     suffixes_with_rtt.push_back(
         base_suffix +
@@ -81,11 +70,3 @@
         rtt.value().InMilliseconds()));
   }
 }
-
-bool ChromeGWSAbandonedPageLoadMetricsObserver::IsIncognitoProfile() const {
-  if (Profile* profile = Profile::FromBrowserContext(
-          GetDelegate().GetWebContents()->GetBrowserContext())) {
-    return profile->IsIncognitoProfile();
-  }
-  return false;
-}
diff --git a/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.h
index 76989f3..c3da711 100644
--- a/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.h
@@ -26,7 +26,6 @@
   std::vector<std::string> GetAdditionalSuffixes() const override;
   void AddSRPMetricsToUKMIfNeeded(
       ukm::builders::AbandonedSRPNavigation& ukm) override;
-  bool IsIncognitoProfile() const;
 };
 
 #endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CHROME_GWS_ABANDONED_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/gws_abandoned_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/gws_abandoned_page_load_metrics_observer_browsertest.cc
index eee5830..f1679451 100644
--- a/chrome/browser/page_load_metrics/observers/gws_abandoned_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/gws_abandoned_page_load_metrics_observer_browsertest.cc
@@ -12,8 +12,6 @@
 #include "chrome/browser/page_load_metrics/integration_tests/metric_integration_test.h"
 #include "chrome/browser/page_load_metrics/observers/chrome_gws_abandoned_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ssl/https_upgrades_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -289,16 +287,9 @@
   // additional suffixes, and one with a RTT suffix, since both versions will be
   // recorded for all logged histograms.
   std::vector<std::pair<std::string, int>> ExpandHistograms(
-      std::vector<std::string> histogram_names,
-      bool is_incognito = false) {
-    std::vector<std::string> with_incognito;
-    for (std::string& histogram_name : histogram_names) {
-      with_incognito.push_back(histogram_name);
-      with_incognito.push_back(histogram_name +
-                               (is_incognito ? ".Incognito" : ".NoIncognito"));
-    }
+      std::vector<std::string> histogram_names) {
     std::vector<std::pair<std::string, int>> histogram_names_expanded;
-    for (std::string& histogram_name : with_incognito) {
+    for (std::string& histogram_name : histogram_names) {
       histogram_names_expanded.push_back(std::pair(histogram_name, 1));
       histogram_names_expanded.push_back(std::pair(
           histogram_name +
@@ -1222,25 +1213,4 @@
   ExpectTotalCountForAllNavigationMilestones(/*include_redirect=*/false, 1);
 }
 
-IN_PROC_BROWSER_TEST_F(GWSAbandonedPageLoadMetricsObserverBrowserTest,
-                       SearchIncognitoMode) {
-  // Explicitly allow http access for the incognito mode. Otherwise the
-  // incognito mode cannot reach to the SRP domain.
-  ScopedAllowHttpForHostnamesForTesting allow_http(
-      {kSRPDomain}, browser()->profile()->GetPrefs());
-
-  // Navigate to SRP with incognito mode.
-  Browser* incognito = CreateIncognitoBrowser();
-  content::WebContents* web_contents =
-      incognito->tab_strip_model()->GetActiveWebContents();
-  EXPECT_TRUE(content::NavigateToURL(web_contents, url_srp()));
-
-  // Navigate to a non-SRP page to flush the metrics.
-  EXPECT_TRUE(content::NavigateToURL(web_contents, url_non_srp()));
-
-  // There should be a new entry for all the navigation milestones metrics.
-  ExpectTotalCountForAllNavigationMilestones(/*include_redirect=*/false, 1,
-                                             ".Incognito");
-}
-
 // TODO(https://crbug.com/347706997): Test backgrounded case.
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 578cc57..04c8ab1 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/policy/drive_file_sync_available_policy_handler.h"
 #include "chrome/browser/policy/extension_developer_mode_policy_handler.h"
 #include "chrome/browser/policy/file_selection_dialogs_policy_handler.h"
+#include "chrome/browser/policy/gen_ai_default_settings_policy_handler.h"
 #include "chrome/browser/policy/homepage_location_policy_handler.h"
 #include "chrome/browser/policy/javascript_policy_handler.h"
 #include "chrome/browser/policy/webhid_device_policy_handler.h"
@@ -279,7 +280,6 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS)
-#include "chrome/browser/policy/gen_ai_default_settings_policy_handler.h"
 #include "components/search_engines/enterprise/site_search_policy_handler.h"
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS)
@@ -2409,34 +2409,6 @@
           optimization_guide::model_execution::prefs::
               GenAILocalFoundationalModelEnterprisePolicySettings::kMaxValue),
       false));
-
-  std::vector<GenAiDefaultSettingsPolicyHandler::GenAiPolicyDetails>
-      gen_ai_default_policies;
-  gen_ai_default_policies.emplace_back(
-      key::kHelpMeWriteSettings,
-      optimization_guide::prefs::kComposeEnterprisePolicyAllowed);
-  gen_ai_default_policies.emplace_back(
-      key::kTabOrganizerSettings,
-      optimization_guide::prefs::kTabOrganizationEnterprisePolicyAllowed);
-  gen_ai_default_policies.emplace_back(
-      key::kCreateThemesSettings,
-      optimization_guide::prefs::kWallpaperSearchEnterprisePolicyAllowed);
-  gen_ai_default_policies.emplace_back(key::kDevToolsGenAiSettings,
-                                       prefs::kDevToolsGenAiSettings);
-  gen_ai_default_policies.emplace_back(
-      key::kHistorySearchSettings,
-      optimization_guide::prefs::kHistorySearchEnterprisePolicyAllowed);
-  gen_ai_default_policies.emplace_back(
-      key::kTabCompareSettings,
-      optimization_guide::prefs::kProductSpecificationsEnterprisePolicyAllowed);
-#if BUILDFLAG(IS_CHROMEOS)
-  gen_ai_default_policies.emplace_back(key::kGenAIWallpaperSettings,
-                                       ash::prefs::kGenAIWallpaperSettings);
-  gen_ai_default_policies.emplace_back(key::kGenAIVcBackgroundSettings,
-                                       ash::prefs::kGenAIVcBackgroundSettings);
-#endif  // BUILDFLAG(IS_CHROMEOS)
-  handlers->AddHandler(std::make_unique<GenAiDefaultSettingsPolicyHandler>(
-      std::move(gen_ai_default_policies)));
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS)
 
@@ -3214,6 +3186,38 @@
                                               /*clamp=*/false)));
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+  std::vector<GenAiDefaultSettingsPolicyHandler::GenAiPolicyDetails>
+      gen_ai_default_policies;
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS_ASH)
+  gen_ai_default_policies.emplace_back(
+      key::kHelpMeWriteSettings,
+      optimization_guide::prefs::kComposeEnterprisePolicyAllowed);
+  gen_ai_default_policies.emplace_back(
+      key::kTabOrganizerSettings,
+      optimization_guide::prefs::kTabOrganizationEnterprisePolicyAllowed);
+  gen_ai_default_policies.emplace_back(
+      key::kCreateThemesSettings,
+      optimization_guide::prefs::kWallpaperSearchEnterprisePolicyAllowed);
+  gen_ai_default_policies.emplace_back(key::kDevToolsGenAiSettings,
+                                       prefs::kDevToolsGenAiSettings);
+  gen_ai_default_policies.emplace_back(
+      key::kHistorySearchSettings,
+      optimization_guide::prefs::kHistorySearchEnterprisePolicyAllowed);
+  gen_ai_default_policies.emplace_back(
+      key::kTabCompareSettings,
+      optimization_guide::prefs::kProductSpecificationsEnterprisePolicyAllowed);
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
+        // BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
+  gen_ai_default_policies.emplace_back(key::kGenAIWallpaperSettings,
+                                       ash::prefs::kGenAIWallpaperSettings);
+  gen_ai_default_policies.emplace_back(key::kGenAIVcBackgroundSettings,
+                                       ash::prefs::kGenAIVcBackgroundSettings);
+#endif  // BUILDFLAG(IS_CHROMEOS)
+  handlers->AddHandler(std::make_unique<GenAiDefaultSettingsPolicyHandler>(
+      std::move(gen_ai_default_policies)));
+
   return handlers;
 }
 
diff --git a/chrome/browser/policy/gen_ai_default_settings_policy_handler_unittest.cc b/chrome/browser/policy/gen_ai_default_settings_policy_handler_unittest.cc
index c2f2a38c..66ed42c 100644
--- a/chrome/browser/policy/gen_ai_default_settings_policy_handler_unittest.cc
+++ b/chrome/browser/policy/gen_ai_default_settings_policy_handler_unittest.cc
@@ -22,11 +22,15 @@
 
 namespace {
 
-constexpr char kHelpMeWriteSettingsPrefs[] = "HelpMeWriteSettings";
-constexpr char kTabOrganizerSettingsPrefs[] = "TabOrganizerSettings";
-constexpr char kCreateThemesSettingsPrefs[] = "CreateThemesSettings";
-constexpr char kDevToolsGenAiSettingsPrefs[] = "DevToolsGenAiSettings";
-constexpr char kHistorySearchSettingsPrefs[] = "HistorySearchSettings";
+constexpr char kGenAiPolicy1Name[] = "GenAiPolicy1";
+constexpr char kGenAiPolicy2Name[] = "GenAiPolicy2";
+constexpr char kGenAiPolicy3Name[] = "GenAiPolicy3";
+constexpr char kGenAiPolicy4Name[] = "GenAiPolicy4";
+
+constexpr char kGenAiPolicy1PrefPath[] = "GenAiPolicy1PrefPath";
+constexpr char kGenAiPolicy2PrefPath[] = "GenAiPolicy2PrefPath";
+constexpr char kGenAiPolicy3PrefPath[] = "GenAiPolicy3PrefPath";
+constexpr char kGenAiPolicy4PrefPath[] = "GenAiPolicy4PrefPath";
 
 constexpr int kDefaultValue = 2;
 
@@ -37,26 +41,23 @@
   void SetUp() override {
     std::vector<GenAiDefaultSettingsPolicyHandler::GenAiPolicyDetails>
         gen_ai_default_policies;
-    gen_ai_default_policies.emplace_back(key::kHelpMeWriteSettings,
-                                         kHelpMeWriteSettingsPrefs);
-    gen_ai_default_policies.emplace_back(key::kTabOrganizerSettings,
-                                         kTabOrganizerSettingsPrefs);
-    gen_ai_default_policies.emplace_back(key::kCreateThemesSettings,
-                                         kCreateThemesSettingsPrefs);
-    gen_ai_default_policies.emplace_back(key::kDevToolsGenAiSettings,
-                                         kDevToolsGenAiSettingsPrefs);
-    gen_ai_default_policies.emplace_back(key::kHistorySearchSettings,
-                                         kHistorySearchSettingsPrefs);
+    gen_ai_default_policies.emplace_back(kGenAiPolicy1Name,
+                                         kGenAiPolicy1PrefPath);
+    gen_ai_default_policies.emplace_back(kGenAiPolicy2Name,
+                                         kGenAiPolicy2PrefPath);
+    gen_ai_default_policies.emplace_back(kGenAiPolicy3Name,
+                                         kGenAiPolicy3PrefPath);
+    gen_ai_default_policies.emplace_back(kGenAiPolicy4Name,
+                                         kGenAiPolicy4PrefPath);
     handler_ = std::make_unique<GenAiDefaultSettingsPolicyHandler>(
         std::move(gen_ai_default_policies));
 
-    policies_.Set(key::kHelpMeWriteSettings, POLICY_LEVEL_MANDATORY,
-                  POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(1),
-                  nullptr);
-    policies_.Set(key::kTabOrganizerSettings, POLICY_LEVEL_RECOMMENDED,
+    policies_.Set(kGenAiPolicy1Name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                  POLICY_SOURCE_CLOUD, base::Value(1), nullptr);
+    policies_.Set(kGenAiPolicy2Name, POLICY_LEVEL_RECOMMENDED,
                   POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, base::Value(1),
                   nullptr);
-    policies_.Set(key::kCreateThemesSettings, POLICY_LEVEL_MANDATORY,
+    policies_.Set(kGenAiPolicy3Name, POLICY_LEVEL_MANDATORY,
                   POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT,
                   base::Value(1), nullptr);
   }
@@ -86,13 +87,11 @@
 
   int pref_value;
   // The handler doesn't set prefs whose policies are set in `PolicyMap`.
-  EXPECT_FALSE(prefs_.GetInteger(kHelpMeWriteSettingsPrefs, &pref_value));
-  EXPECT_FALSE(prefs_.GetInteger(kTabOrganizerSettingsPrefs, &pref_value));
-  EXPECT_FALSE(prefs_.GetInteger(kCreateThemesSettingsPrefs, &pref_value));
+  EXPECT_FALSE(prefs_.GetInteger(kGenAiPolicy1PrefPath, &pref_value));
+  EXPECT_FALSE(prefs_.GetInteger(kGenAiPolicy2PrefPath, &pref_value));
+  EXPECT_FALSE(prefs_.GetInteger(kGenAiPolicy3PrefPath, &pref_value));
   // The handler sets prefs whose policies are unset in `PolicyMap`.
-  EXPECT_TRUE(prefs_.GetInteger(kDevToolsGenAiSettingsPrefs, &pref_value));
-  EXPECT_EQ(kDefaultValue, pref_value);
-  EXPECT_TRUE(prefs_.GetInteger(kHistorySearchSettingsPrefs, &pref_value));
+  EXPECT_TRUE(prefs_.GetInteger(kGenAiPolicy4PrefPath, &pref_value));
   EXPECT_EQ(kDefaultValue, pref_value);
 }
 
diff --git a/chrome/browser/policy/messaging_layer/upload/encrypted_reporting_client.cc b/chrome/browser/policy/messaging_layer/upload/encrypted_reporting_client.cc
index c1e56a6..9a657cb 100644
--- a/chrome/browser/policy/messaging_layer/upload/encrypted_reporting_client.cc
+++ b/chrome/browser/policy/messaging_layer/upload/encrypted_reporting_client.cc
@@ -908,8 +908,9 @@
     PayloadSizePerHourUmaReporter() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  timer_.Start(FROM_HERE, kReportingInterval, this,
-               &PayloadSizePerHourUmaReporter::Report);
+  timer_.Start(FROM_HERE, kReportingInterval,
+               base::BindRepeating(&PayloadSizePerHourUmaReporter::Report,
+                                   GetWeakPtr()));
 }
 
 EncryptedReportingClient::PayloadSizePerHourUmaReporter::
diff --git a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragment.java b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragment.java
index 75fc0f6..e4dbc7e 100644
--- a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragment.java
+++ b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragment.java
@@ -81,7 +81,6 @@
                             FragmentType.HISTORY_SYNC,
                             FragmentType.SAFE_BROWSING,
                             FragmentType.COOKIES,
-                            FragmentType.AD_TOPICS,
                             FragmentType.DONE));
     public static final List<Integer> ALL_FRAGMENT_TYPE_ORDER_PG3 =
             Collections.unmodifiableList(
diff --git a/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java b/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java
index 987e09c7..fbfa88e 100644
--- a/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java
+++ b/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java
@@ -463,7 +463,6 @@
         setHistorySyncState(false);
         setSafeBrowsingState(SafeBrowsingState.STANDARD_PROTECTION);
         setCookieControlsMode(CookieControlsMode.INCOGNITO_ONLY);
-        setAdTopicsState(false);
 
         launchPrivacyGuide();
         testButtonVisibility(false, false, false);
@@ -484,16 +483,11 @@
         onInternalRadioButtonOfViewWithId(R.id.enhanced_option).check(matches(isChecked()));
 
         navigateFromCardToNext(FragmentType.SAFE_BROWSING);
-        testButtonVisibility(true, true, false);
+        testButtonVisibility(false, true, true);
         onView(withId(R.id.block_third_party)).perform(click());
         onInternalRadioButtonOfViewWithId(R.id.block_third_party).check(matches(isChecked()));
 
         navigateFromCardToNext(FragmentType.COOKIES);
-        testButtonVisibility(false, true, true);
-        onView(withId(R.id.ad_topics_switch)).perform(click());
-        onView(withId(R.id.ad_topics_switch)).check(matches(isChecked()));
-
-        navigateFromCardToNext(FragmentType.AD_TOPICS);
         testButtonVisibility(false, false, false);
     }
 
@@ -564,17 +558,11 @@
         setHistorySyncState(false);
         setSafeBrowsingState(SafeBrowsingState.STANDARD_PROTECTION);
         setCookieControlsMode(CookieControlsMode.INCOGNITO_ONLY);
-        setAdTopicsState(false);
 
         launchPrivacyGuide();
         goToCard(FragmentType.DONE);
 
         pressBack();
-        onViewWaiting(allOf(withId(R.id.ad_topics_switch), isCompletelyDisplayed()));
-        onView(withId(R.id.ad_topics_switch)).perform(click());
-        onView(withId(R.id.ad_topics_switch)).check(matches(isChecked()));
-
-        pressBack();
         onViewWaiting(withText(R.string.privacy_guide_cookies_intro));
         onViewWaiting(allOf(withId(R.id.block_third_party), isCompletelyDisplayed()));
         onInternalRadioButtonOfViewWithId(R.id.block_third_party).perform(click());
@@ -619,7 +607,6 @@
         setPreloadStatePG3(PreloadPagesState.STANDARD_PRELOADING);
         setSafeBrowsingState(SafeBrowsingState.STANDARD_PROTECTION);
         setCookieControlsMode(CookieControlsMode.INCOGNITO_ONLY);
-        setAdTopicsState(false);
 
         launchPrivacyGuide();
         goToCard(FragmentType.DONE);
@@ -670,7 +657,9 @@
     @LargeTest
     @Feature({"PrivacyGuide"})
     @EnableFeatures({
+        ChromeFeatureList.PRIVACY_GUIDE_ANDROID_3,
         ChromeFeatureList.PRIVACY_SANDBOX_PRIVACY_GUIDE_AD_TOPICS,
+        ChromeFeatureList.PRIVACY_GUIDE_PRELOAD_ANDROID
     })
     public void testAdTopicsCard_adTopicsSwitchUpdatedOnResume() {
         // Verify that the Ad Topics Switch is updated when the pref is changed when page is
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
index 0766ed0..e61e612a 100644
--- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -302,17 +302,12 @@
   EXPECT_TRUE(
       tab_manager()->DiscardTabImpl(LifecycleUnitDiscardReason::URGENT));
   EXPECT_EQ(3, tsm()->count());
-  if (base::FeatureList::IsEnabled(features::kTabRanker)) {
-    // In testing configs with TabRanker enabled, we don't always know which tab
-    // it will kill. But exactly one of the first two tabs should be killed.
-    EXPECT_TRUE(IsTabDiscarded(GetWebContentsAt(0)) ^
-                IsTabDiscarded(GetWebContentsAt(1)));
-  } else {
-    // With TabRanker disabled, it should kill the first tab, since it was the
-    // oldest and was not selected.
-    EXPECT_TRUE(IsTabDiscarded(GetWebContentsAt(0)));
-    EXPECT_FALSE(IsTabDiscarded(GetWebContentsAt(1)));
-  }
+
+  // The first tab should be killed since it was the oldest and was not
+  // selected.
+  EXPECT_TRUE(IsTabDiscarded(GetWebContentsAt(0)));
+  EXPECT_FALSE(IsTabDiscarded(GetWebContentsAt(1)));
+
   EXPECT_FALSE(IsTabDiscarded(GetWebContentsAt(2)));
 
   // Run discard again. Both unselected tabs should now be killed.
diff --git a/chrome/browser/resource_coordinator/tab_manager_features.cc b/chrome/browser/resource_coordinator/tab_manager_features.cc
index 3735594..20b2c87 100644
--- a/chrome/browser/resource_coordinator/tab_manager_features.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_features.cc
@@ -22,10 +22,6 @@
              "CustomizedTabLoadTimeout",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables using the Tab Ranker to score tabs for discarding instead of relying
-// on last focused time.
-BASE_FEATURE(kTabRanker, "TabRanker", base::FEATURE_DISABLED_BY_DEFAULT);
-
 }  // namespace features
 
 namespace resource_coordinator {
@@ -41,40 +37,4 @@
   return base::Milliseconds(timeout_in_ms);
 }
 
-int GetNumOldestTabsToScoreWithTabRanker() {
-  return base::GetFieldTrialParamByFeatureAsInt(
-      features::kTabRanker, "number_of_oldest_tabs_to_score_with_TabRanker",
-      50);
-}
-
-int GetProcessTypeToScoreWithTabRanker() {
-  return base::GetFieldTrialParamByFeatureAsInt(
-      features::kTabRanker, "process_type_of_tabs_to_score_with_TabRanker", 3);
-}
-
-int GetNumOldestTabsToLogWithTabRanker() {
-  return base::GetFieldTrialParamByFeatureAsInt(
-      features::kTabRanker, "number_of_oldest_tabs_to_log_with_TabRanker", 0);
-}
-
-bool DisableBackgroundLogWithTabRanker() {
-  return base::GetFieldTrialParamByFeatureAsBool(
-      features::kTabRanker, "disable_background_log_with_TabRanker", true);
-}
-
-float GetDiscardCountPenaltyTabRanker() {
-  return static_cast<float>(base::GetFieldTrialParamByFeatureAsDouble(
-      features::kTabRanker, "discard_count_penalty", 0.0));
-}
-
-float GetMRUScorerPenaltyTabRanker() {
-  return static_cast<float>(base::GetFieldTrialParamByFeatureAsDouble(
-      features::kTabRanker, "mru_scorer_penalty", 1.0));
-}
-
-int GetScorerTypeForTabRanker() {
-  return base::GetFieldTrialParamByFeatureAsInt(features::kTabRanker,
-                                                "scorer_type", 1);
-}
-
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_features.h b/chrome/browser/resource_coordinator/tab_manager_features.h
index c588d3a..bcb2370 100644
--- a/chrome/browser/resource_coordinator/tab_manager_features.h
+++ b/chrome/browser/resource_coordinator/tab_manager_features.h
@@ -21,27 +21,6 @@
 
 base::TimeDelta GetTabLoadTimeout(const base::TimeDelta& default_timeout);
 
-// Gets number of oldest tab that should be scored by TabRanker.
-int GetNumOldestTabsToScoreWithTabRanker();
-
-// Gets ProcessType of tabs that should be scored by TabRanker.
-int GetProcessTypeToScoreWithTabRanker();
-
-// Gets number of oldest tabs that should be logged by TabRanker.
-int GetNumOldestTabsToLogWithTabRanker();
-
-// Whether to disable recording of the TabManager_TabMetrics UKM.
-bool DisableBackgroundLogWithTabRanker();
-
-// Gets reload count penalty parameter for TabRanker.
-float GetDiscardCountPenaltyTabRanker();
-
-// Gets mru penalty parameter that converts mru index to scores.
-float GetMRUScorerPenaltyTabRanker();
-
-// Gets which type of scorer to use for TabRanker.
-int GetScorerTypeForTabRanker();
-
 }  // namespace resource_coordinator
 
 #endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_FEATURES_H_
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index b977199..752699a 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -84,7 +84,6 @@
       "ash/inline_login:resources",
       "ash/settings:resources",
       "chromeos:resources",
-      "nearby_internals:resources",
     ]
   }
 
diff --git a/chrome/browser/resources/chromeos/BUILD.gn b/chrome/browser/resources/chromeos/BUILD.gn
index f8ddfef..c5e4fcb5 100644
--- a/chrome/browser/resources/chromeos/BUILD.gn
+++ b/chrome/browser/resources/chromeos/BUILD.gn
@@ -38,6 +38,7 @@
     "mako:resources",
     "manage_mirrorsync:resources",
     "multidevice_internals:resources",
+    "nearby_internals:resources",
     "nearby_share:resources",
     "network_ui:resources",
     "notification_tester:resources",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.ts
index 28c2ae9..c35a22e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.ts
@@ -130,7 +130,10 @@
   altSequence?: SerializedKeySequence;
 }
 
-/** Collection of command properties. */
+/**
+ * Collection of command properties.
+ * NOTE: sorted in lookup order when matching against commands.
+ */
 export const COMMAND_DATA: Record<Command, DataEntry> = {
   [Command.ANNOUNCE_BATTERY_DESCRIPTION]: {
     category: CommandCategory.INFORMATION,
@@ -385,26 +388,6 @@
   },
   [Command.MOVE_TO_START_OF_LINE]: {category: CommandCategory.NO_CATEGORY},
   [Command.MOVE_TO_END_OF_LINE]: {category: CommandCategory.NO_CATEGORY},
-  [Command.NATIVE_NEXT_CHARACTER]: {
-    category: CommandCategory.NO_CATEGORY,
-    sequence: {cvoxModifier: false, keys: {keyCode: [KeyCode.RIGHT]}},
-  },
-  [Command.NATIVE_NEXT_WORD]: {
-    category: CommandCategory.NO_CATEGORY,
-    sequence: {
-      cvoxModifier: false,
-      keys: {keyCode: [KeyCode.RIGHT], ctrlKey: [true]},
-    },
-  },
-  [Command.NATIVE_PREVIOUS_CHARACTER]: {
-    category: CommandCategory.NO_CATEGORY,
-    sequence: {cvoxModifier: false, keys: {keyCode: [KeyCode.LEFT]}},
-  },
-  [Command.NATIVE_PREVIOUS_WORD]: {
-    category: CommandCategory.NO_CATEGORY,
-    sequence:
-        {cvoxModifier: false, keys: {keyCode: [KeyCode.LEFT], ctrlKey: [true]}},
-  },
   [Command.NEXT_ARTICLE]: {category: CommandCategory.NO_CATEGORY},
   [Command.NEXT_AT_GRANULARITY]: {
     category: CommandCategory.NAVIGATION,
@@ -1036,4 +1019,27 @@
     sequence:
         {cvoxModifier: true, keys: {keyCode: [KeyCode.G], altKey: [true]}},
   },
+
+  // Keep these commands last since they potentially conflict with above
+  // commands when sticky mode is enabled.
+  [Command.NATIVE_NEXT_CHARACTER]: {
+    category: CommandCategory.NO_CATEGORY,
+    sequence: {cvoxModifier: false, keys: {keyCode: [KeyCode.RIGHT]}},
+  },
+  [Command.NATIVE_NEXT_WORD]: {
+    category: CommandCategory.NO_CATEGORY,
+    sequence: {
+      cvoxModifier: false,
+      keys: {keyCode: [KeyCode.RIGHT], ctrlKey: [true]},
+    },
+  },
+  [Command.NATIVE_PREVIOUS_CHARACTER]: {
+    category: CommandCategory.NO_CATEGORY,
+    sequence: {cvoxModifier: false, keys: {keyCode: [KeyCode.LEFT]}},
+  },
+  [Command.NATIVE_PREVIOUS_WORD]: {
+    category: CommandCategory.NO_CATEGORY,
+    sequence:
+        {cvoxModifier: false, keys: {keyCode: [KeyCode.LEFT], ctrlKey: [true]}},
+  },
 };
diff --git a/chrome/browser/resources/nearby_internals/.eslintrc.js b/chrome/browser/resources/chromeos/nearby_internals/.eslintrc.js
similarity index 100%
rename from chrome/browser/resources/nearby_internals/.eslintrc.js
rename to chrome/browser/resources/chromeos/nearby_internals/.eslintrc.js
diff --git a/chrome/browser/resources/nearby_internals/BUILD.gn b/chrome/browser/resources/chromeos/nearby_internals/BUILD.gn
similarity index 100%
rename from chrome/browser/resources/nearby_internals/BUILD.gn
rename to chrome/browser/resources/chromeos/nearby_internals/BUILD.gn
diff --git a/chrome/browser/resources/nearby_internals/DIR_METADATA b/chrome/browser/resources/chromeos/nearby_internals/DIR_METADATA
similarity index 100%
rename from chrome/browser/resources/nearby_internals/DIR_METADATA
rename to chrome/browser/resources/chromeos/nearby_internals/DIR_METADATA
diff --git a/chrome/browser/resources/nearby_internals/OWNERS b/chrome/browser/resources/chromeos/nearby_internals/OWNERS
similarity index 100%
rename from chrome/browser/resources/nearby_internals/OWNERS
rename to chrome/browser/resources/chromeos/nearby_internals/OWNERS
diff --git a/chrome/browser/resources/nearby_internals/contact_object.html b/chrome/browser/resources/chromeos/nearby_internals/contact_object.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/contact_object.html
rename to chrome/browser/resources/chromeos/nearby_internals/contact_object.html
diff --git a/chrome/browser/resources/nearby_internals/contact_object.ts b/chrome/browser/resources/chromeos/nearby_internals/contact_object.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/contact_object.ts
rename to chrome/browser/resources/chromeos/nearby_internals/contact_object.ts
diff --git a/chrome/browser/resources/nearby_internals/contact_tab.html b/chrome/browser/resources/chromeos/nearby_internals/contact_tab.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/contact_tab.html
rename to chrome/browser/resources/chromeos/nearby_internals/contact_tab.html
diff --git a/chrome/browser/resources/nearby_internals/contact_tab.ts b/chrome/browser/resources/chromeos/nearby_internals/contact_tab.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/contact_tab.ts
rename to chrome/browser/resources/chromeos/nearby_internals/contact_tab.ts
diff --git a/chrome/browser/resources/nearby_internals/cross_device_internals.html b/chrome/browser/resources/chromeos/nearby_internals/cross_device_internals.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/cross_device_internals.html
rename to chrome/browser/resources/chromeos/nearby_internals/cross_device_internals.html
diff --git a/chrome/browser/resources/nearby_internals/cross_device_internals.ts b/chrome/browser/resources/chromeos/nearby_internals/cross_device_internals.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/cross_device_internals.ts
rename to chrome/browser/resources/chromeos/nearby_internals/cross_device_internals.ts
diff --git a/chrome/browser/resources/nearby_internals/cross_device_logs_browser_proxy.ts b/chrome/browser/resources/chromeos/nearby_internals/cross_device_logs_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/cross_device_logs_browser_proxy.ts
rename to chrome/browser/resources/chromeos/nearby_internals/cross_device_logs_browser_proxy.ts
diff --git a/chrome/browser/resources/nearby_internals/http_message_object.html b/chrome/browser/resources/chromeos/nearby_internals/http_message_object.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/http_message_object.html
rename to chrome/browser/resources/chromeos/nearby_internals/http_message_object.html
diff --git a/chrome/browser/resources/nearby_internals/http_message_object.ts b/chrome/browser/resources/chromeos/nearby_internals/http_message_object.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/http_message_object.ts
rename to chrome/browser/resources/chromeos/nearby_internals/http_message_object.ts
diff --git a/chrome/browser/resources/nearby_internals/http_tab.html b/chrome/browser/resources/chromeos/nearby_internals/http_tab.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/http_tab.html
rename to chrome/browser/resources/chromeos/nearby_internals/http_tab.html
diff --git a/chrome/browser/resources/nearby_internals/http_tab.ts b/chrome/browser/resources/chromeos/nearby_internals/http_tab.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/http_tab.ts
rename to chrome/browser/resources/chromeos/nearby_internals/http_tab.ts
diff --git a/chrome/browser/resources/nearby_internals/index.html b/chrome/browser/resources/chromeos/nearby_internals/index.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/index.html
rename to chrome/browser/resources/chromeos/nearby_internals/index.html
diff --git a/chrome/browser/resources/nearby_internals/log_object.html b/chrome/browser/resources/chromeos/nearby_internals/log_object.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/log_object.html
rename to chrome/browser/resources/chromeos/nearby_internals/log_object.html
diff --git a/chrome/browser/resources/nearby_internals/log_object.ts b/chrome/browser/resources/chromeos/nearby_internals/log_object.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/log_object.ts
rename to chrome/browser/resources/chromeos/nearby_internals/log_object.ts
diff --git a/chrome/browser/resources/nearby_internals/log_types.html b/chrome/browser/resources/chromeos/nearby_internals/log_types.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/log_types.html
rename to chrome/browser/resources/chromeos/nearby_internals/log_types.html
diff --git a/chrome/browser/resources/nearby_internals/log_types.ts b/chrome/browser/resources/chromeos/nearby_internals/log_types.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/log_types.ts
rename to chrome/browser/resources/chromeos/nearby_internals/log_types.ts
diff --git a/chrome/browser/resources/nearby_internals/logging_tab.html b/chrome/browser/resources/chromeos/nearby_internals/logging_tab.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/logging_tab.html
rename to chrome/browser/resources/chromeos/nearby_internals/logging_tab.html
diff --git a/chrome/browser/resources/nearby_internals/logging_tab.ts b/chrome/browser/resources/chromeos/nearby_internals/logging_tab.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/logging_tab.ts
rename to chrome/browser/resources/chromeos/nearby_internals/logging_tab.ts
diff --git a/chrome/browser/resources/nearby_internals/nearby_contact_browser_proxy.ts b/chrome/browser/resources/chromeos/nearby_internals/nearby_contact_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/nearby_contact_browser_proxy.ts
rename to chrome/browser/resources/chromeos/nearby_internals/nearby_contact_browser_proxy.ts
diff --git a/chrome/browser/resources/nearby_internals/nearby_http_browser_proxy.ts b/chrome/browser/resources/chromeos/nearby_internals/nearby_http_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/nearby_http_browser_proxy.ts
rename to chrome/browser/resources/chromeos/nearby_internals/nearby_http_browser_proxy.ts
diff --git a/chrome/browser/resources/nearby_internals/nearby_internals.html b/chrome/browser/resources/chromeos/nearby_internals/nearby_internals.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/nearby_internals.html
rename to chrome/browser/resources/chromeos/nearby_internals/nearby_internals.html
diff --git a/chrome/browser/resources/nearby_internals/nearby_internals.ts b/chrome/browser/resources/chromeos/nearby_internals/nearby_internals.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/nearby_internals.ts
rename to chrome/browser/resources/chromeos/nearby_internals/nearby_internals.ts
diff --git a/chrome/browser/resources/nearby_internals/nearby_prefs_browser_proxy.ts b/chrome/browser/resources/chromeos/nearby_internals/nearby_prefs_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/nearby_prefs_browser_proxy.ts
rename to chrome/browser/resources/chromeos/nearby_internals/nearby_prefs_browser_proxy.ts
diff --git a/chrome/browser/resources/nearby_internals/nearby_presence_browser_proxy.ts b/chrome/browser/resources/chromeos/nearby_internals/nearby_presence_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/nearby_presence_browser_proxy.ts
rename to chrome/browser/resources/chromeos/nearby_internals/nearby_presence_browser_proxy.ts
diff --git a/chrome/browser/resources/nearby_internals/nearby_ui_trigger_browser_proxy.ts b/chrome/browser/resources/chromeos/nearby_internals/nearby_ui_trigger_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/nearby_ui_trigger_browser_proxy.ts
rename to chrome/browser/resources/chromeos/nearby_internals/nearby_ui_trigger_browser_proxy.ts
diff --git a/chrome/browser/resources/nearby_internals/np_list_object.html b/chrome/browser/resources/chromeos/nearby_internals/np_list_object.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/np_list_object.html
rename to chrome/browser/resources/chromeos/nearby_internals/np_list_object.html
diff --git a/chrome/browser/resources/nearby_internals/np_list_object.ts b/chrome/browser/resources/chromeos/nearby_internals/np_list_object.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/np_list_object.ts
rename to chrome/browser/resources/chromeos/nearby_internals/np_list_object.ts
diff --git a/chrome/browser/resources/nearby_internals/shared_style.css b/chrome/browser/resources/chromeos/nearby_internals/shared_style.css
similarity index 100%
rename from chrome/browser/resources/nearby_internals/shared_style.css
rename to chrome/browser/resources/chromeos/nearby_internals/shared_style.css
diff --git a/chrome/browser/resources/nearby_internals/types.ts b/chrome/browser/resources/chromeos/nearby_internals/types.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/types.ts
rename to chrome/browser/resources/chromeos/nearby_internals/types.ts
diff --git a/chrome/browser/resources/nearby_internals/ui_trigger_list_object.html b/chrome/browser/resources/chromeos/nearby_internals/ui_trigger_list_object.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/ui_trigger_list_object.html
rename to chrome/browser/resources/chromeos/nearby_internals/ui_trigger_list_object.html
diff --git a/chrome/browser/resources/nearby_internals/ui_trigger_list_object.ts b/chrome/browser/resources/chromeos/nearby_internals/ui_trigger_list_object.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/ui_trigger_list_object.ts
rename to chrome/browser/resources/chromeos/nearby_internals/ui_trigger_list_object.ts
diff --git a/chrome/browser/resources/nearby_internals/ui_trigger_tab.html b/chrome/browser/resources/chromeos/nearby_internals/ui_trigger_tab.html
similarity index 100%
rename from chrome/browser/resources/nearby_internals/ui_trigger_tab.html
rename to chrome/browser/resources/chromeos/nearby_internals/ui_trigger_tab.html
diff --git a/chrome/browser/resources/nearby_internals/ui_trigger_tab.ts b/chrome/browser/resources/chromeos/nearby_internals/ui_trigger_tab.ts
similarity index 100%
rename from chrome/browser/resources/nearby_internals/ui_trigger_tab.ts
rename to chrome/browser/resources/chromeos/nearby_internals/ui_trigger_tab.ts
diff --git a/chrome/browser/resources/data_sharing/BUILD.gn b/chrome/browser/resources/data_sharing/BUILD.gn
index e2469f1c..b2552a96a 100644
--- a/chrome/browser/resources/data_sharing/BUILD.gn
+++ b/chrome/browser/resources/data_sharing/BUILD.gn
@@ -49,7 +49,7 @@
   } else {
     static_files += [ "data_sharing_sdk.css" ]
 
-    non_web_component_files += [ "data_sharing_sdk.ts" ]
+    non_web_component_files += [ "dummy_data_sharing_sdk.ts" ]
   }
 
   webui_context_type = "untrusted"
diff --git a/chrome/browser/resources/data_sharing/data_sharing.ts b/chrome/browser/resources/data_sharing/data_sharing.ts
index 2353422a..9666142 100644
--- a/chrome/browser/resources/data_sharing/data_sharing.ts
+++ b/chrome/browser/resources/data_sharing/data_sharing.ts
@@ -2,7 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// <if expr="_google_chrome">
 import './data_sharing_sdk.js';
+// </if>
+// <if expr="not _google_chrome">
+import './dummy_data_sharing_sdk.js';
+
+// </if>
+
 
 import {ColorChangeUpdater} from '//resources/cr_components/color_change_listener/colors_css_updater.js';
 import {$} from 'chrome-untrusted://resources/js/util.js';
diff --git a/chrome/browser/resources/data_sharing/data_sharing_api.ts b/chrome/browser/resources/data_sharing/data_sharing_api.ts
index 2da5e36..46f8a05f 100644
--- a/chrome/browser/resources/data_sharing/data_sharing_api.ts
+++ b/chrome/browser/resources/data_sharing/data_sharing_api.ts
@@ -2,7 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// <if expr="_google_chrome">
 import './data_sharing_sdk.js';
+// </if>
+// <if expr="not _google_chrome">
+import './dummy_data_sharing_sdk.js';
+
+// </if>
 
 import {BrowserProxy} from './browser_proxy.js';
 import type {GroupData} from './group_data.mojom-webui.js';
diff --git a/chrome/browser/resources/data_sharing/data_sharing_sdk.ts b/chrome/browser/resources/data_sharing/dummy_data_sharing_sdk.ts
similarity index 100%
rename from chrome/browser/resources/data_sharing/data_sharing_sdk.ts
rename to chrome/browser/resources/data_sharing/dummy_data_sharing_sdk.ts
diff --git a/chrome/browser/resources/data_sharing/mojom_conversion_utils.ts b/chrome/browser/resources/data_sharing/mojom_conversion_utils.ts
index a3bf15b..aaf16fd 100644
--- a/chrome/browser/resources/data_sharing/mojom_conversion_utils.ts
+++ b/chrome/browser/resources/data_sharing/mojom_conversion_utils.ts
@@ -2,8 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
+// <if expr="_google_chrome">
 import './data_sharing_sdk.js';
+// </if>
+// <if expr="not _google_chrome">
+import './dummy_data_sharing_sdk.js';
+
+// </if>
 
 import type {GroupData, GroupMember} from './group_data.mojom-webui.js';
 import {MemberRole} from './group_data.mojom-webui.js';
diff --git a/chrome/browser/resources/history/product_specifications_lists.html b/chrome/browser/resources/history/product_specifications_lists.html
index 7269812..cd1dae2 100644
--- a/chrome/browser/resources/history/product_specifications_lists.html
+++ b/chrome/browser/resources/history/product_specifications_lists.html
@@ -5,10 +5,7 @@
   }
 
   #product-specifications-info-text {
-    box-sizing: border-box;
-    width: 100%;
-    margin: 0 auto;
-    padding: 6px 10px 8px;
+    padding: 6px 10px 8px 8px;
     color: var(--cr-secondary-text-color);
     font-size: 11px;
     font-weight: 400;
@@ -28,6 +25,14 @@
     margin-bottom: var(--card-padding-between);
   }
 
+  #product-list-padding-container {
+    padding: 0 var(--card-padding-side);
+    height: 100%;
+    display:flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
   #card-title-header {
     margin-bottom: var(--card-first-last-item-padding);
   }
@@ -55,8 +60,17 @@
     overflow-x: hidden;
     text-align: center;
   }
-</style>
 
+  .centered-message {
+    padding-top: 0;
+    padding-bottom: 0;
+    height: 100%;
+  }
+
+  #sync-or-error-message-picture-and-text-container {
+    height: 100%;
+  }
+</style>
 <div class="sync-or-error-message-container"
     id="sync-or-error-message-picture-and-text-container"
     hidden="[[!hideHistoryList_(productSpecificationsFeatureState_.*)]]">
@@ -90,14 +104,16 @@
 </div>
 
 <!-- Product specs history list, including empty state. -->
-<div hidden="[[hideHistoryList_(productSpecificationsFeatureState_.*)]]">
-  <div id="product-specifications-info-text" class="history-cards">
-    $i18n{compareHistoryInfo}
-  </div>
+<div hidden="[[hideHistoryList_(productSpecificationsFeatureState_.*)]]"
+  id="product-list-padding-container">
   <div class="centered-message"
       hidden$="[[hasResults_(displayedItems_.length)]]">
     $i18n{compareHistoryEmpty}
   </div>
+  <div id="product-specifications-info-text" class="history-cards"
+    hidden$="[[!hasResults_(displayedItems_.length)]]">
+    $i18n{compareHistoryInfo}
+  </div>
   <div class="history-cards" id="product-list-container"
       hidden$="[[!hasResults_(displayedItems_.length)]]">
     <div id="card-title-header" class="card-title" role="row">
diff --git a/chrome/browser/resources/lens/overlay/lens_overlay_app.html b/chrome/browser/resources/lens/overlay/lens_overlay_app.html
index e3d47783..4c1711c4 100644
--- a/chrome/browser/resources/lens/overlay/lens_overlay_app.html
+++ b/chrome/browser/resources/lens/overlay/lens_overlay_app.html
@@ -181,7 +181,7 @@
     --color-surface-container-highest-dark: [[skColorToHex_(theme.surfaceContainerHighestDark)]];
     --color-selection-element: [[skColorToHex_(theme.selectionElement)]];
     --color-overlay-icon: white;
-    --color-overlay-button-label: black;">
+    --color-overlay-button-label: white;">
   <cr-toast id="copyToast" duration="4000">
     <div>$i18n{copyToastMessage}</div>
     <cr-button on-click="onHideToastClick">
diff --git a/chrome/browser/resources/lens/overlay/translate_button.html b/chrome/browser/resources/lens/overlay/translate_button.html
index dc9de98..b884e9f 100644
--- a/chrome/browser/resources/lens/overlay/translate_button.html
+++ b/chrome/browser/resources/lens/overlay/translate_button.html
@@ -71,6 +71,26 @@
     width: 100%;
   }
 
+  .language-picker-menu::-webkit-scrollbar {
+    width: 14px;
+  }
+
+  .language-picker-menu::-webkit-scrollbar-button {
+    width: 0;
+    height: 0;
+  }
+
+  .language-picker-menu::-webkit-scrollbar-thumb {
+    background-color: rgba(var(--color-scrim-rgb), 0.3);
+    border: 4px solid white;
+    border-radius: 10px;
+    min-height: 56px;
+  }
+
+  .language-picker-menu::-webkit-scrollbar-track {
+    margin: 12px;
+  }
+
   .language-picker-menu-back-button {
     margin: 2px 0px 2px 10px;
   }
diff --git a/chrome/browser/resources/side_panel/read_anything/app.html b/chrome/browser/resources/side_panel/read_anything/app.html
index bc0a1df..b6d88ada 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.html
+++ b/chrome/browser/resources/side_panel/read_anything/app.html
@@ -27,7 +27,7 @@
         @letter-spacing-change="${this.onLetterSpacingChange_}"
         @theme-change="${this.onThemeChange_}"
         @line-spacing-change="${this.onLineSpacingChange_}"
-        @highlight-toggle="${this.onHighlightToggle_}"
+        @highlight-change="${this.onHighlightChange_}"
         @reset-toolbar="${this.onResetToolbar_}"
         @toolbar-overflow="${this.onToolbarOverflow_}"
         id="toolbar">
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index 00758dc..1f94c25 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -364,6 +364,7 @@
       theme: chrome.readingMode.colorTheme,
       speechRate: chrome.readingMode.speechRate,
       font: chrome.readingMode.fontName,
+      highlightGranularity: chrome.readingMode.highlightGranularity,
     };
 
     document.onselectionchange = () => {
@@ -2233,6 +2234,7 @@
       theme: chrome.readingMode.colorTheme,
       speechRate: chrome.readingMode.speechRate,
       font: chrome.readingMode.fontName,
+      highlightGranularity: chrome.readingMode.highlightGranularity,
     };
     this.styleUpdater_.setAllTextStyles();
     // TODO(crbug.com/40927698): Remove this call. Using this.settingsPrefs_
@@ -2340,10 +2342,6 @@
     this.styleUpdater_.setFontSize();
   }
 
-  protected onHighlightToggle_() {
-    this.styleUpdater_.setHighlight();
-  }
-
   protected onThemeChange_() {
     this.styleUpdater_.setTheme();
   }
@@ -2358,6 +2356,16 @@
     this.styleUpdater_.overflowToolbar(shouldScroll);
   }
 
+  protected onHighlightChange_(event: CustomEvent<{data: number}>) {
+    // Handler for HIGHLIGHT_CHANGE.
+    const changedHighlight = event.detail.data;
+    chrome.readingMode.onHighlightGranularityChanged(changedHighlight);
+    // Apply highlighting changes to the DOM.
+    this.styleUpdater_.setHighlight();
+    // TODO(crbug.com/364546547): Log these highlight granularity changes when
+    // the phrase menu is shown. (Toggles are already logged in the toolbar.)
+  }
+
   // If the screen is locked during speech, we should stop speaking.
   onLockScreen() {
     if (this.speechPlayingState.isSpeechActive) {
diff --git a/chrome/browser/resources/side_panel/read_anything/common.ts b/chrome/browser/resources/side_panel/read_anything/common.ts
index 07ad3df..b23c393 100644
--- a/chrome/browser/resources/side_panel/read_anything/common.ts
+++ b/chrome/browser/resources/side_panel/read_anything/common.ts
@@ -21,7 +21,6 @@
   FONT = 'font-change',
   RATE = 'rate-change',
   PLAY_PAUSE = 'play-pause-click',
-  HIGHLIGHT_TOGGLE = 'highlight-toggle',
   HIGHLIGHT_CHANGE = 'highlight-change',
   NEXT_GRANULARITY = 'next-granularity-click',
   PREVIOUS_GRANULARITY = 'previous-granularity-click',
@@ -40,6 +39,7 @@
   theme: number;
   speechRate: number;
   font: string;
+  highlightGranularity: number;
 }
 
 const ACTIVE_CSS_CLASS = 'active';
diff --git a/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.html b/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.html
index 2a33f2d8..b752795 100644
--- a/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.html
+++ b/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.html
@@ -4,6 +4,5 @@
     menu-items="[[options_]]"
     event-name="[[toolbarEventEnum_.HIGHLIGHT_CHANGE]]"
     current-selected-index="[[restoredHighlightIndex_(settingsPrefs)]]"
-    on-highlight-change="onHighlightChange_"
     initial-count="5">
 </simple-action-menu>
diff --git a/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts b/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts
index a37c1f5..d477ffbe 100644
--- a/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts
+++ b/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts
@@ -36,10 +36,10 @@
       title: loadTimeData.getString('wordHighlightTitle'),
       data: chrome.readingMode.wordHighlighting,
     },
-    ...(chrome.readingMode.isPhraseHighlightingEnabled?[{
+    {
       title: loadTimeData.getString('phraseHighlightTitle'),
       data: chrome.readingMode.phraseHighlighting,
-    }]: []),
+    },
     {
       title: loadTimeData.getString('sentenceHighlightTitle'),
       data: chrome.readingMode.sentenceHighlighting,
@@ -73,17 +73,6 @@
     this.$.menu.open(anchor);
   }
 
-  private onHighlightChange_(event: CustomEvent<{data: number}>) {
-    const changedHighlight = event.detail.data;
-    if (!chrome.readingMode.isPhraseHighlightingEnabled &&
-        changedHighlight === chrome.readingMode.phraseHighlighting) {
-      return;
-    } else {
-      chrome.readingMode.onHighlightGranularityChanged(event.detail.data);
-    }
-    // TODO(crbug.com/364546547): Log these highlight granularity changes.
-  }
-
   private restoredHighlightIndex_(): number {
     return getIndexOfSetting(
         this.options_, chrome.readingMode.highlightGranularity);
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
index 8dfe347..16ce19a 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
@@ -202,10 +202,6 @@
     // via the webui language menu.
     function onLanguagePrefChange(lang: string, enabled: boolean): void;
 
-    // Called when the highlight granularity is changed via the webui toolbar.
-    function turnedHighlightOn(): void;
-    function turnedHighlightOff(): void;
-
     // Returns the actual spacing value to use based on the given lineSpacing
     // category.
     function getLineSpacingValue(lineSpacing: number): number;
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
index 07a52c9..fdca840 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
@@ -271,7 +271,8 @@
     </template>
   </cr-lazy-render>
   <highlight-menu
-    id="highlightMenu" settings-prefs="[[settingsPrefs]]">
+    id="highlightMenu" settings-prefs="[[settingsPrefs]]"
+    on-highlight-change="onHighlightChange_">
   </highlight-menu>
   <cr-lazy-render id="fontSizeMenu">
     <template>
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts
index b9e0177..0d29989 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts
@@ -460,9 +460,10 @@
       this.setCheckMarkForMenu_(
           this.$.rateMenu.getIfExists(), this.rateOptions.indexOf(speechRate));
 
+      const highlightOn = chrome.readingMode.isHighlightOn();
+      this.setHighlightButtonTitle_(highlightOn);
       if (!chrome.readingMode.isPhraseHighlightingEnabled) {
-        // Only update the toggle state if the highlight menu is disabled.
-        this.setHighlightState_(chrome.readingMode.isHighlightOn());
+        this.setHighlightButtonIcon_(highlightOn);
       }
     }
   }
@@ -550,41 +551,67 @@
     openMenu(menu, event.target as HTMLElement);
   }
 
+  private onHighlightChange_(event: CustomEvent<{data: number}>) {
+    // Event handler for highlight-change (from highlight-menu).
+    const changedHighlight = event.detail.data;
+    this.setHighlightButtonIcon_(
+        changedHighlight !== chrome.readingMode.noHighlighting);
+  }
+
   private onHighlightClick_(event: MouseEvent) {
+    // Click handler for the highlight button. Used both for the
+    // highlight menu mode and the toggle button mode.
     if (chrome.readingMode.isPhraseHighlightingEnabled) {
       this.$.highlightMenu.open(event.target as HTMLElement);
     } else {
       // Don't show the highlight menu if phrase highlighting is disabled.
-      this.onHighlightToggleClick_();
+      this.onHighlightToggle_();
     }
   }
 
-  private onHighlightToggleClick_() {
+  private onHighlightToggle_() {
+    assert(
+        !chrome.readingMode.isPhraseHighlightingEnabled,
+        'should not be called when highlighting menu is shown');
     this.logger_.logSpeechSettingsChange(
         ReadAloudSettingsChange.HIGHLIGHT_CHANGE);
     const isHighlightOn = chrome.readingMode.isHighlightOn();
-    if (isHighlightOn) {
-      chrome.readingMode.turnedHighlightOff();
-    } else {
-      chrome.readingMode.turnedHighlightOn();
-    }
-
-    this.logger_.logHighlightState(!isHighlightOn);
-    this.setHighlightState_(!isHighlightOn);
+    const turnOn = !isHighlightOn;
+    this.logger_.logHighlightState(turnOn);
+    this.setHighlightButtonIcon_(turnOn);
+    this.setHighlightButtonTitle_(turnOn);
+    emitEvent(this, ToolbarEvent.HIGHLIGHT_CHANGE, {
+      data: turnOn ? chrome.readingMode.autoHighlighting :
+                     chrome.readingMode.noHighlighting,
+    });
   }
 
-  private setHighlightState_(turnOn: boolean) {
+  private setHighlightButtonIcon_(turnOn: boolean) {
+    // Sets the icon of the highlight button. This happens regardless of
+    // whether the button toggles highlight on/off (the behavior when the phrase
+    // highlighting flag is off), or the button shows the highlight menu (when
+    // the flag is on).
     const button = this.$.toolbarContainer.querySelector('#highlight');
     assert(button, 'no highlight button');
     if (turnOn) {
       button.setAttribute('iron-icon', 'read-anything:highlight-on');
-      button.setAttribute('title', loadTimeData.getString('turnHighlightOff'));
     } else {
       button.setAttribute('iron-icon', 'read-anything:highlight-off');
-      button.setAttribute('title', loadTimeData.getString('turnHighlightOn'));
     }
+  }
 
-    emitEvent(this, ToolbarEvent.HIGHLIGHT_TOGGLE);
+  private setHighlightButtonTitle_(turnOn: boolean) {
+    // Sets the title of the highlight button. This is dynamically changed only
+    // when the highlight menu is disabled (i.e. the button acts as a toggle).
+    const button = this.$.toolbarContainer.querySelector('#highlight');
+    assert(button, 'no highlight button');
+    // The title is the opposite of the state, since it connotes the action that
+    // will be performed when the button is next clicked, and not the present
+    // state.
+    const title =
+        loadTimeData.getString(turnOn ? 'turnHighlightOff' : 'turnHighlightOn');
+    button.setAttribute('title', title);
+    button.setAttribute('aria-label', title);
   }
 
   private onFontClick_(event: DomRepeatEvent<string>) {
diff --git a/chrome/browser/resources_integrity.cc b/chrome/browser/resources_integrity.cc
index 6cea8c4..59bdc6f 100644
--- a/chrome/browser/resources_integrity.cc
+++ b/chrome/browser/resources_integrity.cc
@@ -49,18 +49,19 @@
     return false;
 
   auto hash = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
-  std::vector<char> buffer(base::GetPageSize());
+  std::vector<uint8_t> buffer(base::GetPageSize());
 
-  int bytes_read = 0;
+  std::optional<size_t> bytes_read = 0;
   do {
-    bytes_read = file.ReadAtCurrentPos(buffer.data(), buffer.size());
-    if (bytes_read == -1)
+    bytes_read = file.ReadAtCurrentPos(buffer);
+    if (!bytes_read.has_value()) {
       return false;
-    hash->Update(buffer.data(), bytes_read);
-  } while (bytes_read > 0);
+    }
+    hash->Update(buffer.data(), *bytes_read);
+  } while (bytes_read.value_or(0) > 0);
 
   std::array<uint8_t, crypto::kSHA256Length> digest;
-  hash->Finish(digest.data(), digest.size());
+  hash->Finish(digest);
 
   return base::ranges::equal(digest, expected_signature);
 }
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc b/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc
index 7a62954..4be13f17 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc
@@ -113,14 +113,14 @@
           path, std::string_view(buf.data(), bytes_currently_read.value()));
     }
 
-    secure_hash->Update(buf.data(), bytes_currently_read.value());
+    secure_hash->Update(
+        base::as_byte_span(buf).subspan(0, bytes_currently_read.value()));
     bytes_read += bytes_currently_read.value();
   }
 
-  file_data.hash.resize(crypto::kSHA256Length);
-  secure_hash->Finish(std::data(file_data.hash), crypto::kSHA256Length);
-  file_data.hash =
-      base::HexEncode(base::as_bytes(base::make_span(file_data.hash)));
+  std::array<uint8_t, crypto::kSHA256Length> hash;
+  secure_hash->Finish(hash);
+  file_data.hash = base::HexEncode(hash);
 
   return {file_data.size <= BinaryUploadService::kMaxUploadSizeBytes
               ? BinaryUploadService::Result::SUCCESS
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index b4ca3f485..c88e942 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -69,6 +69,7 @@
 #include "chrome/browser/ui/startup/startup_tab.h"
 #include "chrome/browser/ui/startup/startup_types.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
@@ -96,6 +97,8 @@
 #include "components/keep_alive_registry/scoped_keep_alive.h"
 #include "components/memory_pressure/fake_memory_pressure_monitor.h"
 #include "components/saved_tab_groups/features.h"
+#include "components/saved_tab_groups/saved_tab_group.h"
+#include "components/saved_tab_groups/tab_group_sync_service.h"
 #include "components/sessions/content/content_live_tab.h"
 #include "components/sessions/content/content_test_helper.h"
 #include "components/sessions/core/serialized_navigation_entry_test_helper.h"
@@ -2997,6 +3000,14 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SessionRestoreTest, RestoreWithTabRemovedFromGroup) {
+  if (tab_groups::IsTabGroupSyncServiceDesktopMigrationEnabled()) {
+    // Cannot simulate sync removal of tab using TabGroupSyncService API. This
+    // causes this test to fail when the migration flag is enabled.
+    // TODO(crbug.com/365152362): Skip for now and reassess if this test is
+    // still necessary.
+    GTEST_SKIP();
+  }
+
   // Add two more tabs.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(url::kAboutBlankURL),
@@ -3022,9 +3033,9 @@
 
   auto* saved_tab_group =
       saved_tab_group_keyed_service->model()->Get(tab_group_id);
+  ASSERT_TRUE(saved_tab_group);
   auto saved_tab_group_id = saved_tab_group->saved_guid();
 
-  ASSERT_TRUE(saved_tab_group);
   // This ensures SessionService knows about the savedtabgroup. It shouldn't be
   // necessary.
   browser()
@@ -4501,10 +4512,21 @@
             !ShouldDeleteStaleSessionCookiesOnStartup());
 }
 
-class SavedTabGroupSessionRestoreTest : public SessionRestoreTest {
+class SavedTabGroupSessionRestoreTest
+    : public SessionRestoreTest,
+      public ::testing::WithParamInterface<bool> {
  public:
   SavedTabGroupSessionRestoreTest() {
-    feature_list_.InitAndEnableFeature(tab_groups::kTabGroupsSaveV2);
+    if (GetParam()) {
+      feature_list_.InitWithFeatures(
+          {tab_groups::kTabGroupsSaveV2,
+           tab_groups::kTabGroupSyncServiceDesktopMigration},
+          {});
+    } else {
+      feature_list_.InitWithFeatures(
+          {tab_groups::kTabGroupsSaveV2},
+          {tab_groups::kTabGroupSyncServiceDesktopMigration});
+    }
   }
   SavedTabGroupSessionRestoreTest(const SavedTabGroupSessionRestoreTest&) =
       delete;
@@ -4518,7 +4540,7 @@
 // This test simulates migrating from V1 of SavedTabGroups to V2. A user may
 // have unsaved groups at the time they update the browser. We must ensure all
 // groups are saved by default correctly. See crbug.com/344016224.
-IN_PROC_BROWSER_TEST_F(SavedTabGroupSessionRestoreTest,
+IN_PROC_BROWSER_TEST_P(SavedTabGroupSessionRestoreTest,
                        UnsavedGroupDefaultSavedAfterBrowserRestart) {
   // Add a second tab.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -4534,11 +4556,13 @@
       {0}, tab_groups::TabGroupId::GenerateNew());
 
   // Expect no groups have been saved at this point.
-  tab_groups::SavedTabGroupKeyedService* service =
-      tab_groups::SavedTabGroupServiceFactory::GetForProfile(
+  tab_groups::TabGroupSyncService* service =
+      tab_groups::SavedTabGroupUtils::GetServiceForProfile(
           browser()->profile());
-  ASSERT_NE(service, nullptr);
-  EXPECT_TRUE(service->model()->IsEmpty());
+  ASSERT_TRUE(service);
+
+  service->SetIsInitializedForTesting(true);
+  EXPECT_EQ(0u, service->GetAllGroups().size());
 
   // Close the browser and restore the last session
   Browser* restored = QuitBrowserAndRestore(browser());
@@ -4547,13 +4571,13 @@
   ASSERT_EQ(2, tabs);
 
   // Expect the unsaved group has been saved at this point.
-  EXPECT_EQ(1, service->model()->Count());
+  EXPECT_EQ(1u, service->GetAllGroups().size());
 }
 
 // This test simulates creating a default group (using the default group color
 // and no title). Ensure on restart there was no duplicated groups and that the
 // restored group is connected to the saved group.
-IN_PROC_BROWSER_TEST_F(SavedTabGroupSessionRestoreTest,
+IN_PROC_BROWSER_TEST_P(SavedTabGroupSessionRestoreTest,
                        NoDuplicatesOfDefaultSavedGroupAfterBrowserRestart) {
   // Add a second tab.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -4561,15 +4585,20 @@
       WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
 
+  // Expect no groups have been saved at this point.
+  tab_groups::TabGroupSyncService* service =
+      tab_groups::SavedTabGroupUtils::GetServiceForProfile(
+          browser()->profile());
+  ASSERT_TRUE(service);
+
+  service->SetIsInitializedForTesting(true);
+  EXPECT_EQ(0u, service->GetAllGroups().size());
+
   // Add the tab to a new group.
   browser()->tab_strip_model()->AddToNewGroup({0});
 
   // Expect the newly created to be saved at this point.
-  tab_groups::SavedTabGroupKeyedService* service =
-      tab_groups::SavedTabGroupServiceFactory::GetForProfile(
-          browser()->profile());
-  ASSERT_NE(service, nullptr);
-  EXPECT_EQ(1, service->model()->Count());
+  EXPECT_EQ(1u, service->GetAllGroups().size());
 
   // Close the browser and restore the last session
   Browser* restored = QuitBrowserAndRestore(browser());
@@ -4577,13 +4606,13 @@
   const int tabs = tab_strip_model->count();
   ASSERT_EQ(2, tabs);
 
-  // Expect the restored browser to still has 1 saved group i.e. no duplicates.
-  EXPECT_EQ(1, service->model()->Count());
+  // Expect the restored browser to still have 1 saved group i.e. no duplicates.
+  EXPECT_EQ(1u, service->GetAllGroups().size());
 }
 
 // This test simulates creating multiple groups with different visual data
 // and ensuring on restart they are restored with the same information.
-IN_PROC_BROWSER_TEST_F(SavedTabGroupSessionRestoreTest,
+IN_PROC_BROWSER_TEST_P(SavedTabGroupSessionRestoreTest,
                        MultipleSavedGroupsAfterBrowserRestart) {
   // Add a second tab.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -4597,20 +4626,22 @@
       WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
 
-  tab_groups::SavedTabGroupKeyedService* service =
-      tab_groups::SavedTabGroupServiceFactory::GetForProfile(
+  // Expect no groups have been saved at this point.
+  tab_groups::TabGroupSyncService* service =
+      tab_groups::SavedTabGroupUtils::GetServiceForProfile(
           browser()->profile());
-  ASSERT_NE(service, nullptr);
+  ASSERT_TRUE(service);
+  service->SetIsInitializedForTesting(true);
 
   // Add the tab to a new groups.
   auto group1 = browser()->tab_strip_model()->AddToNewGroup({0});
-  base::Uuid group1_saved_guid = service->model()->Get(group1)->saved_guid();
+  base::Uuid group1_saved_guid = service->GetGroup(group1)->saved_guid();
 
   auto group2 = browser()->tab_strip_model()->AddToNewGroup({1});
-  base::Uuid group2_saved_guid = service->model()->Get(group2)->saved_guid();
+  base::Uuid group2_saved_guid = service->GetGroup(group2)->saved_guid();
 
   // Expect the newly created to be saved at this point.
-  EXPECT_EQ(2, service->model()->Count());
+  EXPECT_EQ(2u, service->GetAllGroups().size());
 
   // Update the visual data of the new groups.
   browser()
@@ -4636,10 +4667,11 @@
   ASSERT_EQ(3, tabs);
 
   // Expect the restored browser to still has 2 saved group.
-  EXPECT_EQ(2, service->model()->Count());
+  EXPECT_EQ(2u, service->GetAllGroups().size());
 
-  auto* saved_group1 = service->model()->Get(group1_saved_guid);
-  ASSERT_NE(saved_group1, nullptr);
+  std::optional<tab_groups::SavedTabGroup> saved_group1 =
+      service->GetGroup(group1_saved_guid);
+  ASSERT_TRUE(saved_group1);
   ASSERT_TRUE(saved_group1->local_group_id().has_value());
   auto* local_group1 = tab_strip_model->group_model()->GetTabGroup(
       saved_group1->local_group_id().value());
@@ -4647,8 +4679,9 @@
   EXPECT_EQ(tab_groups::TabGroupColorId::kGrey,
             local_group1->visual_data()->color());
 
-  auto* saved_group2 = service->model()->Get(group2_saved_guid);
-  ASSERT_NE(saved_group2, nullptr);
+  std::optional<tab_groups::SavedTabGroup> saved_group2 =
+      service->GetGroup(group2_saved_guid);
+  ASSERT_TRUE(saved_group2);
   ASSERT_TRUE(saved_group2->local_group_id().has_value());
   auto* local_group2 = tab_strip_model->group_model()->GetTabGroup(
       saved_group2->local_group_id().value());
@@ -4656,3 +4689,7 @@
   EXPECT_EQ(tab_groups::TabGroupColorId::kBlue,
             local_group2->visual_data()->color());
 }
+
+INSTANTIATE_TEST_SUITE_P(SessionRestore,
+                         SavedTabGroupSessionRestoreTest,
+                         testing::Bool());
diff --git a/chrome/browser/subresource_filter/safe_browsing_child_navigation_throttle_unittest.cc b/chrome/browser/subresource_filter/safe_browsing_child_navigation_throttle_unittest.cc
new file mode 100644
index 0000000..983bd66
--- /dev/null
+++ b/chrome/browser/subresource_filter/safe_browsing_child_navigation_throttle_unittest.cc
@@ -0,0 +1,244 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.h"
+
+#include <memory>
+
+#include "base/functional/bind.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/features.h"
+#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
+#include "components/subresource_filter/content/shared/browser/child_frame_navigation_test_utils.h"
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
+#include "components/subresource_filter/core/common/common_features.h"
+#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/navigation_simulator.h"
+#include "services/network/public/cpp/features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+namespace {
+
+using content_settings::CookieSettings;
+
+const char kChildFrameNavigationDeferredForAdTaggingHistogram[] =
+    "PageLoad.FrameCounts.AdFrames.PerFrame.DeferredForTagging";
+
+}  // namespace
+
+class SafeBrowsingChildNavigationThrottleAdTaggingTest
+    : public ChildFrameNavigationFilteringThrottleTestHarness {
+ public:
+  SafeBrowsingChildNavigationThrottleAdTaggingTest() = default;
+
+  SafeBrowsingChildNavigationThrottleAdTaggingTest(
+      const SafeBrowsingChildNavigationThrottleAdTaggingTest&) = delete;
+  SafeBrowsingChildNavigationThrottleAdTaggingTest& operator=(
+      const SafeBrowsingChildNavigationThrottleAdTaggingTest&) = delete;
+
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{subresource_filter::kTPCDAdHeuristicSubframeRequestTagging,
+          {{"check_exceptions", "true"}}},
+         {net::features::kTopLevelTpcdTrialSettings, {}},
+         {net::features::kTpcdTrialSettings, {}},
+         {content_settings::features::kTrackingProtection3pcd, {}}},
+        {});
+
+    ChildFrameNavigationFilteringThrottleTestHarness::SetUp();
+    settings_map_ =
+        HostContentSettingsMapFactory::GetForProfile(browser_context());
+    profile_interaction_manager_ = std::make_unique<ProfileInteractionManager>(
+        SubresourceFilterProfileContextFactory::GetForProfile(profile()));
+  }
+
+  // content::RenderViewHostTestHarness:
+  std::unique_ptr<content::BrowserContext> CreateBrowserContext() override {
+    return std::make_unique<TestingProfile>();
+  }
+
+  Profile* profile() { return Profile::FromBrowserContext(browser_context()); }
+
+  // content::WebContentsObserver:
+  void DidStartNavigation(
+      content::NavigationHandle* navigation_handle) override {
+    ASSERT_FALSE(navigation_handle->IsInMainFrame());
+    // The |parent_filter_| is the parent frame's filter. Do not register a
+    // throttle if the parent is not activated with a valid filter.
+    if (parent_filter_) {
+      auto throttle = std::make_unique<SafeBrowsingChildNavigationThrottle>(
+          navigation_handle, parent_filter_.get(),
+          profile_interaction_manager_->AsWeakPtr(),
+          base::BindRepeating([](const GURL& filtered_url) {
+            return base::StringPrintf(
+                kDisallowChildFrameConsoleMessageFormat,
+                filtered_url.possibly_invalid_spec().c_str());
+          }),
+          /*ad_evidence=*/std::nullopt);
+      ASSERT_NE(nullptr, throttle->GetNameForLogging());
+      navigation_handle->RegisterThrottleForTesting(std::move(throttle));
+    }
+  }
+
+  void CreateSubframeAndInitNavigation(const GURL& first_url,
+                                       content::RenderFrameHost* parent) {
+    content::RenderFrameHost* render_frame =
+        content::RenderFrameHostTester::For(parent)->AppendChild(
+            base::StringPrintf("subframe-%s", first_url.spec().c_str()));
+    navigation_simulator_ =
+        content::NavigationSimulator::CreateRendererInitiated(first_url,
+                                                              render_frame);
+    navigation_simulator_->SetTransition(ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+    navigation_simulator_->SetAutoAdvance(false);
+  }
+
+  void Create3pTrialSetting(GURL first_party_url, GURL third_party_url) {
+    settings_map_->SetContentSettingDefaultScope(
+        third_party_url, first_party_url, ContentSettingsType::TPCD_TRIAL,
+        CONTENT_SETTING_ALLOW);
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  scoped_refptr<HostContentSettingsMap> settings_map_;
+  std::unique_ptr<ProfileInteractionManager> profile_interaction_manager_;
+};
+
+TEST_F(SafeBrowsingChildNavigationThrottleAdTaggingTest,
+       FrameNavigationNotDeferred) {
+  base::HistogramTester histogram_tester;
+
+  InitializeDocumentSubresourceFilter(
+      GURL("https://example.test"),
+      subresource_filter::mojom::ActivationLevel::kDryRun);
+
+  CreateSubframeAndInitNavigation(GURL("https://child-frame.test"), main_rfh());
+  navigation_simulator()->Start();
+
+  // The navigation should NOT be deferred, since no 3P cookie exception
+  // applies.
+  EXPECT_FALSE(navigation_simulator()->IsDeferred());
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            navigation_simulator()->GetLastThrottleCheckResult().action());
+
+  histogram_tester.ExpectUniqueSample(
+      kChildFrameNavigationDeferredForAdTaggingHistogram, false, 1);
+}
+
+TEST_F(SafeBrowsingChildNavigationThrottleAdTaggingTest,
+       FrameNavigationDeferredIfExceptionMatch) {
+  base::HistogramTester histogram_tester;
+  Create3pTrialSetting(GURL("https://example.test"),
+                       GURL("https://excepted-child-frame.test"));
+
+  InitializeDocumentSubresourceFilter(GURL("https://example.test"),
+                                      mojom::ActivationLevel::kDryRun);
+  CreateSubframeAndInitNavigation(GURL("https://excepted-child-frame.test"),
+                                  main_rfh());
+  navigation_simulator()->Start();
+
+  // The navigation should be deferred, since a 3P cookie exception applies.
+  EXPECT_TRUE(navigation_simulator()->IsDeferred());
+
+  histogram_tester.ExpectUniqueSample(
+      kChildFrameNavigationDeferredForAdTaggingHistogram, true, 1);
+}
+
+TEST_F(SafeBrowsingChildNavigationThrottleAdTaggingTest,
+       FrameRedirectNavigationDeferredIfExceptionMatch) {
+  Create3pTrialSetting(GURL("https://example.test"),
+                       GURL("https://excepted-child-frame.test"));
+
+  InitializeDocumentSubresourceFilter(GURL("https://example.test"),
+                                      mojom::ActivationLevel::kDryRun);
+  CreateSubframeAndInitNavigation(GURL("https://child-frame.test"), main_rfh());
+
+  base::HistogramTester histogram_tester;
+
+  // The navigation should NOT be deferred, since no 3P cookie exception
+  // applies.
+  navigation_simulator()->Start();
+  EXPECT_FALSE(navigation_simulator()->IsDeferred());
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            navigation_simulator()->GetLastThrottleCheckResult().action());
+
+  histogram_tester.ExpectUniqueSample(
+      kChildFrameNavigationDeferredForAdTaggingHistogram, false, 1);
+
+  // Redirect the navigation to a URL that a 3P cookie exception applies to
+  // (under the current top-level origin).
+  navigation_simulator()->Redirect(GURL("https://excepted-child-frame.test"));
+
+  // The navigation should be deferred.
+  EXPECT_TRUE(navigation_simulator()->IsDeferred());
+
+  histogram_tester.ExpectTotalCount(
+      kChildFrameNavigationDeferredForAdTaggingHistogram, 2);
+  histogram_tester.ExpectBucketCount(
+      kChildFrameNavigationDeferredForAdTaggingHistogram, true,
+      1);  // from excepted-child-frame.test
+}
+
+class SafeBrowsingChildNavigationThrottleExceptionCheckDisabledTest
+    : public SafeBrowsingChildNavigationThrottleAdTaggingTest {
+ public:
+  SafeBrowsingChildNavigationThrottleExceptionCheckDisabledTest() = default;
+
+  SafeBrowsingChildNavigationThrottleExceptionCheckDisabledTest(
+      const SafeBrowsingChildNavigationThrottleExceptionCheckDisabledTest&) =
+      delete;
+  SafeBrowsingChildNavigationThrottleExceptionCheckDisabledTest& operator=(
+      const SafeBrowsingChildNavigationThrottleExceptionCheckDisabledTest&) =
+      delete;
+
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{subresource_filter::kTPCDAdHeuristicSubframeRequestTagging,
+          {{"check_exceptions", "false"}}},
+         {net::features::kTopLevelTpcdTrialSettings, {}},
+         {net::features::kTpcdTrialSettings, {}},
+         {content_settings::features::kTrackingProtection3pcd, {}}},
+        {});
+
+    ChildFrameNavigationFilteringThrottleTestHarness::SetUp();
+    settings_map_ =
+        HostContentSettingsMapFactory::GetForProfile(browser_context());
+    profile_interaction_manager_ = std::make_unique<ProfileInteractionManager>(
+        SubresourceFilterProfileContextFactory::GetForProfile(profile()));
+  }
+};
+
+TEST_F(SafeBrowsingChildNavigationThrottleExceptionCheckDisabledTest,
+       FrameNavigationDeferredWithoutException) {
+  base::HistogramTester histogram_tester;
+
+  InitializeDocumentSubresourceFilter(
+      GURL("https://example.test"),
+      subresource_filter::mojom::ActivationLevel::kDryRun);
+
+  CreateSubframeAndInitNavigation(GURL("https://child-frame.test"), main_rfh());
+  navigation_simulator()->Start();
+
+  // The navigation should be deferred, even though no 3P cookie exception
+  // applies, since exception checking is disabled.
+  EXPECT_TRUE(navigation_simulator()->IsDeferred());
+
+  histogram_tester.ExpectUniqueSample(
+      kChildFrameNavigationDeferredForAdTaggingHistogram, true, 1);
+}
+
+}  // namespace subresource_filter
diff --git a/chrome/browser/subresource_filter/subresource_filter_profile_context_factory.cc b/chrome/browser/subresource_filter/subresource_filter_profile_context_factory.cc
index 88f3c62..c22e0af 100644
--- a/chrome/browser/subresource_filter/subresource_filter_profile_context_factory.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_profile_context_factory.cc
@@ -5,10 +5,12 @@
 #include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h"
 
 #include "base/no_destructor.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/subresource_filter/subresource_filter_history_observer.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/subresource_filter/content/browser/subresource_filter_profile_context.h"
 
@@ -48,7 +50,8 @@
 
   auto* subresource_filter_profile_context =
       new subresource_filter::SubresourceFilterProfileContext(
-          HostContentSettingsMapFactory::GetForProfile(profile));
+          HostContentSettingsMapFactory::GetForProfile(profile),
+          CookieSettingsFactory::GetForProfile(profile));
 
   // Create and attach a SubresourceFilterHistoryObserver instance if possible.
   auto* history_service = HistoryServiceFactory::GetForProfile(
diff --git a/chrome/browser/sync/BUILD.gn b/chrome/browser/sync/BUILD.gn
index ef10ffd..7b46061 100644
--- a/chrome/browser/sync/BUILD.gn
+++ b/chrome/browser/sync/BUILD.gn
@@ -13,6 +13,8 @@
     "account_bookmark_sync_service_factory.h",
     "chrome_sync_client.cc",
     "chrome_sync_client.h",
+    "chrome_sync_controller_builder.cc",
+    "chrome_sync_controller_builder.h",
     "data_type_store_service_factory.cc",
     "data_type_store_service_factory.h",
     "device_info_sync_client_impl.cc",
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 9e2e6dbc..bb86055 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -10,150 +10,48 @@
 #include "base/check.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
-#include "base/functional/bind.h"
 #include "base/path_service.h"
 #include "base/syslog_logging.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
-#include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/commerce/product_specifications/product_specifications_service_factory.h"
-#include "chrome/browser/consent_auditor/consent_auditor_factory.h"
-#include "chrome/browser/data_sharing/data_sharing_service_factory.h"
-#include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
-#include "chrome/browser/metrics/variations/google_groups_manager_factory.h"
-#include "chrome/browser/password_manager/account_password_store_factory.h"
-#include "chrome/browser/password_manager/password_receiver_service_factory.h"
-#include "chrome/browser/password_manager/password_sender_service_factory.h"
-#include "chrome/browser/password_manager/profile_password_store_factory.h"
-#include "chrome/browser/plus_addresses/plus_address_setting_service_factory.h"
-#include "chrome/browser/power_bookmarks/power_bookmark_service_factory.h"
-#include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_key.h"
-#include "chrome/browser/reading_list/reading_list_model_factory.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/security_events/security_event_recorder.h"
-#include "chrome/browser/security_events/security_event_recorder_factory.h"
-#include "chrome/browser/sharing/sharing_message_bridge_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
-#include "chrome/browser/sync/account_bookmark_sync_service_factory.h"
 #include "chrome/browser/sync/data_type_store_service_factory.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
-#include "chrome/browser/sync/local_or_syncable_bookmark_sync_service_factory.h"
-#include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
-#include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/sync/sync_invalidations_service_factory.h"
-#include "chrome/browser/sync/user_event_service_factory.h"
-#include "chrome/browser/tab_group_sync/feature_utils.h"
-#include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h"
-#include "chrome/browser/tab_group_sync/tab_group_trial.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/themes/theme_service_factory.h"
-#include "chrome/browser/themes/theme_syncable_service.h"
 #include "chrome/browser/trusted_vault/trusted_vault_service_factory.h"
-#include "chrome/browser/ui/ui_features.h"
-#include "chrome/browser/webdata_services/web_data_service_factory.h"
 #include "chrome/common/buildflags.h"
-#include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_paths.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/browser_sync/common_controller_builder.h"
 #include "components/browser_sync/sync_engine_factory_impl.h"
-#include "components/data_sharing/public/features.h"
-#include "components/desks_storage/core/desk_sync_service.h"
-#include "components/plus_addresses/webdata/plus_address_webdata_service.h"
 #include "components/prefs/pref_service.h"
-#include "components/saved_tab_groups/features.h"
-#include "components/saved_tab_groups/tab_group_sync_service.h"
-#include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/supervised_user/core/browser/supervised_user_settings_service.h"
-#include "components/sync/base/data_type.h"
 #include "components/sync/base/features.h"
 #include "components/sync/base/pref_names.h"
-#include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/model/data_type_controller_delegate.h"
-#include "components/sync/model/data_type_store.h"
 #include "components/sync/model/data_type_store_service.h"
-#include "components/sync/model/forwarding_data_type_controller_delegate.h"
-#include "components/sync/service/data_type_controller.h"
-#include "components/sync/service/sync_engine_factory.h"
-#include "components/sync/service/syncable_service_based_data_type_controller.h"
 #include "components/sync/service/trusted_vault_synthetic_field_trial.h"
 #include "components/sync_device_info/device_info_sync_service.h"
-#include "components/sync_preferences/pref_service_syncable.h"
+#include "components/trusted_vault/trusted_vault_server_constants.h"
 #include "components/trusted_vault/trusted_vault_service.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/buildflags/buildflags.h"
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "chrome/browser/extensions/api/storage/settings_sync_util.h"
-#include "chrome/browser/extensions/extension_sync_service.h"
-#include "chrome/browser/sync/glue/extension_data_type_controller.h"
-#include "chrome/browser/sync/glue/extension_setting_data_type_controller.h"
-#include "chrome/browser/web_applications/web_app_provider.h"
-#include "chrome/browser/web_applications/web_app_sync_bridge.h"
-#include "chrome/browser/web_applications/web_app_utils.h"
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
-#if BUILDFLAG(ENABLE_SPELLCHECK)
-#include "chrome/browser/spellchecker/spellcheck_factory.h"
-#include "chrome/browser/spellchecker/spellcheck_service.h"
-#include "components/spellcheck/browser/pref_names.h"
-#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
-
-#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
-    BUILDFLAG(IS_WIN)
-#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
-#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
-#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#elif BUILDFLAG(IS_ANDROID)
-#include "components/saved_tab_groups/features.h"
-#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
-        // BUILDFLAG(IS_WIN)
-
-#if !BUILDFLAG(IS_ANDROID)
-#include "chrome/browser/webauthn/passkey_model_factory.h"
-#include "components/webauthn/core/browser/passkey_model.h"
-#endif  // !BUILDFLAG(IS_ANDROID)
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/components/arc/arc_util.h"
-#include "ash/constants/ash_features.h"
-#include "ash/constants/ash_switches.h"
-#include "chrome/browser/ash/app_list/app_list_syncable_service.h"
-#include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h"
-#include "chrome/browser/ash/app_list/arc/arc_package_sync_data_type_controller.h"
-#include "chrome/browser/ash/app_list/arc/arc_package_syncable_service.h"
-#include "chrome/browser/ash/arc/arc_util.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
-#include "chrome/browser/ash/floating_sso/floating_sso_service.h"
-#include "chrome/browser/ash/floating_sso/floating_sso_service_factory.h"
-#include "chrome/browser/ash/printing/oauth2/authorization_zones_manager.h"
-#include "chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h"
-#include "chrome/browser/ash/printing/printers_sync_bridge.h"
-#include "chrome/browser/ash/printing/synced_printers_manager.h"
-#include "chrome/browser/ash/printing/synced_printers_manager_factory.h"
-#include "chrome/browser/sync/desk_sync_service_factory.h"
-#include "chrome/browser/sync/wifi_configuration_sync_service_factory.h"
-#include "chromeos/ash/components/sync_wifi/wifi_configuration_sync_service.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_ANDROID)
-#include "chrome/browser/android/webapk/webapk_sync_service.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/password_manager/account_password_store_factory.h"
+#include "chrome/browser/password_manager/profile_password_store_factory.h"
+#include "chrome/browser/reading_list/reading_list_model_factory.h"
 #include "components/browser_sync/sync_client_utils.h"
+#include "components/keyed_service/core/service_access_type.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #endif  // BUILDFLAG(IS_ANDROID)
 
-using content::BrowserThread;
-
 namespace browser_sync {
-
 namespace {
 
+using content::BrowserThread;
+
 // A global variable is needed to detect multiprofile scenarios where more than
 // one profile try to register a synthetic field trial.
 bool trusted_vault_synthetic_field_trial_registered = false;
@@ -163,93 +61,6 @@
     FILE_PATH_LITERAL("profile.pb");
 #endif  // BUILDFLAG(IS_WIN)
 
-base::RepeatingClosure GetDumpStackClosure() {
-  return base::BindRepeating(&syncer::ReportUnrecoverableError,
-                             chrome::GetChannel());
-}
-
-bool ShouldSyncBrowserTypes() {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  return crosapi::browser_util::IsAshBrowserSyncEnabled();
-#else
-  return true;
-#endif
-}
-
-syncer::DataTypeSet GetDisabledCommonDataTypes() {
-  if (!ShouldSyncBrowserTypes()) {
-    // If browser-sync is disabled (on ChromeOS Ash), most "common" data types
-    // are disabled. These types will be synced in Lacros instead.
-    return base::Difference(syncer::UserTypes(),
-                            {syncer::DEVICE_INFO, syncer::USER_CONSENTS});
-  }
-
-  // Common case: No disabled types.
-  return {};
-}
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-// App sync is enabled by default, with the exception of Lacros secondary
-// profiles.
-bool IsAppSyncEnabled(Profile* profile) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (!profile->IsMainProfile() &&
-      !web_app::IsMainProfileCheckSkippedForTesting()) {
-    return false;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
-
-  return true;
-}
-
-bool ShouldSyncAppsTypesInTransportMode() {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // When apps sync controlled by Ash Sync settings, allow running apps-related
-  // types (WEB_APPS, APPS and APP_SETTINGS) in transport-only mode using the
-  // same `delegate`.
-  return base::FeatureList::IsEnabled(syncer::kSyncChromeOSAppsToggleSharing);
-#else
-  return false;
-#endif
-}
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
-syncer::DataTypeControllerDelegate* GetSavedTabGroupControllerDelegate(
-    Profile* profile) {
-#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
-    BUILDFLAG(IS_WIN)
-  tab_groups::TabGroupSyncService* service =
-      tab_groups::SavedTabGroupUtils::GetServiceForProfile(profile);
-  CHECK(service);
-  return service->GetSavedTabGroupControllerDelegate().get();
-#elif BUILDFLAG(IS_ANDROID)
-  return tab_groups::TabGroupSyncServiceFactory::GetForProfile(profile)
-      ->GetSavedTabGroupControllerDelegate()
-      .get();
-#else
-  NOTREACHED();
-#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
-        // BUILDFLAG(IS_WIN)
-}
-
-syncer::DataTypeControllerDelegate* GetSharedTabGroupControllerDelegate(
-    Profile* profile) {
-#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
-    BUILDFLAG(IS_WIN)
-  tab_groups::TabGroupSyncService* service =
-      tab_groups::SavedTabGroupUtils::GetServiceForProfile(profile);
-  CHECK(service);
-  return service->GetSharedTabGroupControllerDelegate().get();
-#elif BUILDFLAG(IS_ANDROID)
-  return tab_groups::TabGroupSyncServiceFactory::GetForProfile(profile)
-      ->GetSharedTabGroupControllerDelegate()
-      .get();
-#else
-  NOTREACHED();
-#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
-        // BUILDFLAG(IS_WIN)
-}
-
 }  // namespace
 
 ChromeSyncClient::ChromeSyncClient(Profile* profile)
@@ -260,7 +71,7 @@
       this,
       DeviceInfoSyncServiceFactory::GetForProfile(profile_)
           ->GetDeviceInfoTracker(),
-      GetDataTypeStoreService()->GetSyncDataPath());
+      DataTypeStoreServiceFactory::GetForProfile(profile_)->GetSyncDataPath());
 
 #if BUILDFLAG(IS_ANDROID)
   scoped_refptr<password_manager::PasswordStoreInterface>
@@ -342,345 +153,6 @@
 }
 #endif  // BUILDFLAG(IS_ANDROID)
 
-syncer::DataTypeController::TypeVector
-ChromeSyncClient::CreateDataTypeControllers(syncer::SyncService* sync_service) {
-  scoped_refptr<autofill::AutofillWebDataService> profile_web_data_service =
-      WebDataServiceFactory::GetAutofillWebDataForProfile(
-          profile_, ServiceAccessType::IMPLICIT_ACCESS);
-  scoped_refptr<autofill::AutofillWebDataService> account_web_data_service =
-      WebDataServiceFactory::GetAutofillWebDataForAccount(
-          profile_, ServiceAccessType::IMPLICIT_ACCESS);
-
-  // This class assumes that the tasks posted by the profile and account storage
-  // services will execute, in order, on the same sequence.
-  // This DCHECK makes that assumption explicit.
-#if DCHECK_IS_ON()
-  if (account_web_data_service && profile_web_data_service) {
-    profile_web_data_service->GetDBTaskRunner()->PostTask(
-        FROM_HERE, base::BindOnce(
-                       [](scoped_refptr<base::SequencedTaskRunner> ac_tr) {
-                         CHECK(ac_tr->RunsTasksInCurrentSequence());
-                       },
-                       account_web_data_service->GetDBTaskRunner()));
-  }
-#endif  // DCHECK_IS_ON()
-
-  browser_sync::CommonControllerBuilder builder;
-  builder.SetAutofillWebDataService(content::GetUIThreadTaskRunner({}),
-                                    profile_web_data_service,
-                                    account_web_data_service);
-  builder.SetBookmarkModel(
-      BookmarkModelFactory::GetForBrowserContext(profile_));
-  builder.SetBookmarkSyncService(
-      LocalOrSyncableBookmarkSyncServiceFactory::GetForProfile(profile_),
-      AccountBookmarkSyncServiceFactory::GetForProfile(profile_));
-  builder.SetConsentAuditor(ConsentAuditorFactory::GetForProfile(profile_));
-  builder.SetDataSharingService(
-      data_sharing::DataSharingServiceFactory::GetForProfile(profile_));
-  builder.SetDeviceInfoSyncService(
-      DeviceInfoSyncServiceFactory::GetForProfile(profile_));
-  builder.SetDualReadingListModel(
-      ReadingListModelFactory::GetAsDualReadingListForBrowserContext(profile_));
-  builder.SetFaviconService(FaviconServiceFactory::GetForProfile(
-      profile_, ServiceAccessType::IMPLICIT_ACCESS));
-  builder.SetGoogleGroupsManager(
-      GoogleGroupsManagerFactory::GetForBrowserContext(profile_));
-  builder.SetHistoryService(HistoryServiceFactory::GetForProfile(
-      profile_, ServiceAccessType::EXPLICIT_ACCESS));
-  builder.SetIdentityManager(GetIdentityManager());
-  builder.SetDataTypeStoreService(
-      DataTypeStoreServiceFactory::GetForProfile(profile_));
-#if !BUILDFLAG(IS_ANDROID)
-  builder.SetPasskeyModel(
-      base::FeatureList::IsEnabled(syncer::kSyncWebauthnCredentials)
-          ? PasskeyModelFactory::GetForProfile(profile_)
-          : nullptr);
-#endif  // !BUILDFLAG(IS_ANDROID)
-  builder.SetPasswordReceiverService(
-      PasswordReceiverServiceFactory::GetForProfile(profile_));
-  builder.SetPasswordSenderService(
-      PasswordSenderServiceFactory::GetForProfile(profile_));
-  builder.SetPasswordStore(ProfilePasswordStoreFactory::GetForProfile(
-                               profile_, ServiceAccessType::IMPLICIT_ACCESS),
-                           AccountPasswordStoreFactory::GetForProfile(
-                               profile_, ServiceAccessType::IMPLICIT_ACCESS));
-  builder.SetPlusAddressServices(
-      PlusAddressSettingServiceFactory::GetForBrowserContext(profile_),
-      WebDataServiceFactory::GetPlusAddressWebDataForProfile(
-          profile_, ServiceAccessType::IMPLICIT_ACCESS));
-  builder.SetPowerBookmarkService(
-      PowerBookmarkServiceFactory::GetForBrowserContext(profile_));
-  builder.SetPrefService(profile_->GetPrefs());
-  builder.SetPrefServiceSyncable(PrefServiceSyncableFromProfile(profile_));
-  builder.SetProductSpecificationsService(
-      commerce::ProductSpecificationsServiceFactory::GetForBrowserContext(
-          profile_));
-  builder.SetTemplateURLService(
-#if BUILDFLAG(IS_ANDROID)
-      nullptr
-#else   // BUILDFLAG(IS_ANDROID)
-      ShouldSyncBrowserTypes()
-          ? TemplateURLServiceFactory::GetForProfile(profile_)
-          : nullptr
-#endif  // BUILDFLAG(IS_ANDROID)
-  );
-  builder.SetSendTabToSelfSyncService(
-      SendTabToSelfSyncServiceFactory::GetForProfile(profile_));
-  builder.SetSessionSyncService(
-      SessionSyncServiceFactory::GetForProfile(profile_));
-  builder.SetSharingMessageBridge(
-      ShouldSyncBrowserTypes()
-          ? SharingMessageBridgeFactory::GetForBrowserContext(profile_)
-          : nullptr);
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-  builder.SetSupervisedUserSettingsService(
-      SupervisedUserSettingsServiceFactory::GetForKey(
-          profile_->GetProfileKey()));
-#endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
-  builder.SetUserEventService(
-      browser_sync::UserEventServiceFactory::GetForProfile(profile_));
-
-  syncer::DataTypeController::TypeVector controllers = builder.Build(
-      GetDisabledCommonDataTypes(), sync_service, chrome::GetChannel());
-
-  const base::RepeatingClosure dump_stack = GetDumpStackClosure();
-
-  syncer::RepeatingDataTypeStoreFactory data_type_store_factory =
-      GetDataTypeStoreService()->GetStoreFactory();
-
-  if (ShouldSyncBrowserTypes()) {
-    syncer::DataTypeControllerDelegate* security_events_delegate =
-        SecurityEventRecorderFactory::GetForProfile(profile_)
-            ->GetControllerDelegate()
-            .get();
-    // Forward both full-sync and transport-only modes to the same delegate,
-    // since behavior for SECURITY_EVENTS does not differ.
-    controllers.push_back(std::make_unique<syncer::DataTypeController>(
-        syncer::SECURITY_EVENTS,
-        /*delegate_for_full_sync_mode=*/
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            security_events_delegate),
-        /*delegate_for_transport_mode=*/
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            security_events_delegate)));
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-    // Extension sync is enabled by default.
-    controllers.push_back(std::make_unique<ExtensionDataTypeController>(
-        syncer::EXTENSIONS, data_type_store_factory,
-        GetSyncableServiceForType(syncer::EXTENSIONS), dump_stack,
-        ExtensionDataTypeController::DelegateMode::kLegacyFullSyncModeOnly,
-        profile_));
-
-    // Extension setting sync is enabled by default.
-    controllers.push_back(std::make_unique<ExtensionSettingDataTypeController>(
-        syncer::EXTENSION_SETTINGS, data_type_store_factory,
-        extensions::settings_sync_util::GetSyncableServiceProvider(
-            profile_, syncer::EXTENSION_SETTINGS),
-        dump_stack,
-        ExtensionSettingDataTypeController::DelegateMode::
-            kLegacyFullSyncModeOnly,
-        profile_));
-
-    if (IsAppSyncEnabled(profile_)) {
-      controllers.push_back(CreateAppsDataTypeController());
-
-      controllers.push_back(CreateAppSettingsDataTypeController(sync_service));
-
-      if (web_app::AreWebAppsEnabled(profile_) &&
-          web_app::WebAppProvider::GetForWebApps(profile_)) {
-        controllers.push_back(CreateWebAppsDataTypeController());
-      }
-    }
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
-#if BUILDFLAG(IS_ANDROID)
-    if (base::FeatureList::IsEnabled(syncer::kWebApkBackupAndRestoreBackend)) {
-      syncer::DataTypeControllerDelegate* delegate =
-          webapk::WebApkSyncService::GetForProfile(profile_)
-              ->GetDataTypeControllerDelegate()
-              .get();
-      controllers.push_back(std::make_unique<syncer::DataTypeController>(
-          syncer::WEB_APKS,
-          /*delegate_for_full_sync_mode=*/
-          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-              delegate),
-          /*delegate_for_transport_mode=*/
-          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-              delegate)));
-    }
-#endif  // BUILDFLAG(IS_ANDROID)
-
-#if !BUILDFLAG(IS_ANDROID)
-    // Theme sync is enabled by default.
-    controllers.push_back(std::make_unique<ExtensionDataTypeController>(
-        syncer::THEMES, data_type_store_factory,
-        GetSyncableServiceForType(syncer::THEMES), dump_stack,
-        ExtensionDataTypeController::DelegateMode::kLegacyFullSyncModeOnly,
-        profile_));
-#endif  // !BUILDFLAG(IS_ANDROID)
-
-    // Tab group sync is enabled via separate feature flags on different
-    // platforms.
-    bool enable_tab_group_sync = false;
-#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
-    BUILDFLAG(IS_WIN)
-    enable_tab_group_sync = true;
-#elif BUILDFLAG(IS_ANDROID)
-    enable_tab_group_sync =
-        tab_groups::IsTabGroupSyncEnabled(GetPrefService()) &&
-        !base::FeatureList::IsEnabled(
-            tab_groups::kTabGroupSyncDisableNetworkLayer);
-    tab_groups::TabGroupTrial::OnTabgroupSyncEnabled(enable_tab_group_sync);
-#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
-        // BUILDFLAG(IS_WIN)
-
-    if (enable_tab_group_sync) {
-      syncer::DataTypeControllerDelegate* delegate =
-          GetSavedTabGroupControllerDelegate(profile_);
-
-      controllers.push_back(std::make_unique<syncer::DataTypeController>(
-          syncer::SAVED_TAB_GROUP,
-          /*delegate_for_full_sync_mode=*/
-          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-              delegate),
-          /*delegate_for_transport_mode=*/
-          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-              delegate)));
-    }
-
-    if (base::FeatureList::IsEnabled(
-            data_sharing::features::kDataSharingFeature)) {
-      syncer::DataTypeControllerDelegate* delegate =
-          GetSharedTabGroupControllerDelegate(profile_);
-      controllers.push_back(std::make_unique<syncer::DataTypeController>(
-          syncer::SHARED_TAB_GROUP_DATA,
-          /*delegate_for_full_sync_mode=*/
-          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-              delegate),
-          /*delegate_for_transport_mode=*/
-          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-              delegate)));
-    }
-
-// Chrome prefers OS provided spell checkers where they exist. So only sync the
-// custom dictionary on platforms that typically don't provide one.
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
-    // Dictionary sync is enabled by default.
-    if (GetPrefService()->GetBoolean(spellcheck::prefs::kSpellCheckEnable)) {
-      controllers.push_back(
-          std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
-              syncer::DICTIONARY, data_type_store_factory,
-              GetSyncableServiceForType(syncer::DICTIONARY), dump_stack,
-              syncer::SyncableServiceBasedDataTypeController::DelegateMode::
-                  kLegacyFullSyncModeOnly));
-    }
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
-  }
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Some profile types (e.g. sign-in screen) don't support app list.
-  // Temporarily Disable AppListSyncableService for tablet form factor devices.
-  // See crbug/1013732 for details.
-  if (app_list::AppListSyncableServiceFactory::GetForProfile(profile_) &&
-      !ash::switches::IsTabletFormFactor()) {
-    // Runs in sync transport-mode and full-sync mode.
-    controllers.push_back(
-        std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
-            syncer::APP_LIST, data_type_store_factory,
-            GetSyncableServiceForType(syncer::APP_LIST), dump_stack,
-            syncer::SyncableServiceBasedDataTypeController::DelegateMode::
-                kTransportModeWithSingleModel));
-  }
-
-  if (arc::IsArcAllowedForProfile(profile_) &&
-      !arc::IsArcAppSyncFlowDisabled()) {
-    controllers.push_back(std::make_unique<ArcPackageSyncDataTypeController>(
-        data_type_store_factory, GetSyncableServiceForType(syncer::ARC_PACKAGE),
-        dump_stack, sync_service, profile_));
-  }
-  controllers.push_back(
-      std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
-          syncer::OS_PREFERENCES, data_type_store_factory,
-          GetSyncableServiceForType(syncer::OS_PREFERENCES), dump_stack,
-          syncer::SyncableServiceBasedDataTypeController::DelegateMode::
-              kTransportModeWithSingleModel));
-  controllers.push_back(
-      std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
-          syncer::OS_PRIORITY_PREFERENCES, data_type_store_factory,
-          GetSyncableServiceForType(syncer::OS_PRIORITY_PREFERENCES),
-          dump_stack,
-          syncer::SyncableServiceBasedDataTypeController::DelegateMode::
-              kTransportModeWithSingleModel));
-
-  syncer::DataTypeControllerDelegate* printers_delegate =
-      ash::SyncedPrintersManagerFactory::GetForBrowserContext(profile_)
-          ->GetSyncBridge()
-          ->change_processor()
-          ->GetControllerDelegate()
-          .get();
-  controllers.push_back(std::make_unique<syncer::DataTypeController>(
-      syncer::PRINTERS,
-      std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-          printers_delegate),
-      /*delegate_for_transport_mode=*/nullptr));
-
-  if (WifiConfigurationSyncServiceFactory::ShouldRunInProfile(profile_)) {
-    syncer::DataTypeControllerDelegate* wifi_configurations_delegate =
-        WifiConfigurationSyncServiceFactory::GetForProfile(profile_,
-                                                           /*create=*/true)
-            ->GetControllerDelegate()
-            .get();
-    controllers.push_back(std::make_unique<syncer::DataTypeController>(
-        syncer::WIFI_CONFIGURATIONS,
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            wifi_configurations_delegate),
-        /*delegate_for_transport_mode=*/nullptr));
-  }
-
-  syncer::DataTypeControllerDelegate* workspace_desk_delegate =
-      DeskSyncServiceFactory::GetForProfile(profile_)
-          ->GetControllerDelegate()
-          .get();
-  controllers.push_back(std::make_unique<syncer::DataTypeController>(
-      syncer::WORKSPACE_DESK,
-      std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-          workspace_desk_delegate),
-      /*delegate_for_transport_mode=*/nullptr));
-
-  if (ash::features::IsOAuthIppEnabled()) {
-    syncer::DataTypeControllerDelegate*
-        printers_authorization_servers_delegate =
-            ash::printing::oauth2::AuthorizationZonesManagerFactory::
-                GetForBrowserContext(profile_)
-                    ->GetDataTypeSyncBridge()
-                    ->change_processor()
-                    ->GetControllerDelegate()
-                    .get();
-    controllers.push_back(std::make_unique<syncer::DataTypeController>(
-        syncer::PRINTERS_AUTHORIZATION_SERVERS,
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            printers_authorization_servers_delegate),
-        /*delegate_for_transport_mode=*/nullptr));
-  }
-
-  if (ash::features::IsFloatingSsoAllowed()) {
-    syncer::DataTypeControllerDelegate* cookies_delegate =
-        ash::floating_sso::FloatingSsoServiceFactory::GetForProfile(profile_)
-            ->GetControllerDelegate()
-            .get();
-    controllers.push_back(std::make_unique<syncer::DataTypeController>(
-        syncer::COOKIES,
-        /*delegate_for_full_sync_mode=*/
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            cookies_delegate),
-        /*delegate_for_transport_mode=*/nullptr));
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-  return controllers;
-}
-
 trusted_vault::TrustedVaultClient* ChromeSyncClient::GetTrustedVaultClient() {
   return TrustedVaultServiceFactory::GetForProfile(profile_)
       ->GetTrustedVaultClient(trusted_vault::SecurityDomainId::kChromeSync);
@@ -696,57 +168,6 @@
   return extensions_activity_monitor_.GetExtensionsActivity();
 }
 
-syncer::DataTypeStoreService* ChromeSyncClient::GetDataTypeStoreService() {
-  return DataTypeStoreServiceFactory::GetForProfile(profile_);
-}
-
-base::WeakPtr<syncer::SyncableService>
-ChromeSyncClient::GetSyncableServiceForType(syncer::DataType type) {
-  switch (type) {
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-    case syncer::APPS:
-    case syncer::EXTENSIONS: {
-      syncer::SyncableService* service = ExtensionSyncService::Get(profile_);
-      return service ? service->AsWeakPtr() : nullptr;
-    }
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    case syncer::APP_LIST: {
-      syncer::SyncableService* service =
-          app_list::AppListSyncableServiceFactory::GetForProfile(profile_);
-      return service ? service->AsWeakPtr() : nullptr;
-    }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-#if !BUILDFLAG(IS_ANDROID)
-    case syncer::THEMES:
-      return ThemeServiceFactory::GetForProfile(profile_)
-          ->GetThemeSyncableService()
-          ->AsWeakPtr();
-#endif  // !BUILDFLAG(IS_ANDROID)
-#if BUILDFLAG(ENABLE_SPELLCHECK)
-    case syncer::DICTIONARY: {
-      SpellcheckService* spellcheck_service =
-          SpellcheckServiceFactory::GetForContext(profile_);
-      return spellcheck_service
-                 ? spellcheck_service->GetCustomDictionary()->AsWeakPtr()
-                 : nullptr;
-    }
-#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    case syncer::ARC_PACKAGE:
-      return arc::ArcPackageSyncableService::Get(profile_)->AsWeakPtr();
-    case syncer::OS_PREFERENCES:
-    case syncer::OS_PRIORITY_PREFERENCES:
-      return PrefServiceSyncableFromProfile(profile_)
-          ->GetSyncableService(type)
-          ->AsWeakPtr();
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-    default:
-      NOTREACHED_IN_MIGRATION();
-      return nullptr;
-  }
-}
-
 syncer::SyncEngineFactory* ChromeSyncClient::GetSyncEngineFactory() {
   return engine_factory_.get();
 }
@@ -817,64 +238,4 @@
       variations::SyntheticTrialAnnotationMode::kCurrentLog);
 }
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-std::unique_ptr<syncer::DataTypeController>
-ChromeSyncClient::CreateAppsDataTypeController() {
-  auto delegate_mode =
-      ExtensionDataTypeController::DelegateMode::kLegacyFullSyncModeOnly;
-  if (ShouldSyncAppsTypesInTransportMode()) {
-    delegate_mode = ExtensionDataTypeController::DelegateMode::
-        kTransportModeWithSingleModel;
-  }
-  return std::make_unique<ExtensionDataTypeController>(
-      syncer::APPS, GetDataTypeStoreService()->GetStoreFactory(),
-      GetSyncableServiceForType(syncer::APPS), GetDumpStackClosure(),
-      delegate_mode, profile_);
-}
-
-std::unique_ptr<syncer::DataTypeController>
-ChromeSyncClient::CreateAppSettingsDataTypeController(
-    syncer::SyncService* sync_service) {
-  auto delegate_mode =
-      ExtensionSettingDataTypeController::DelegateMode::kLegacyFullSyncModeOnly;
-  if (ShouldSyncAppsTypesInTransportMode()) {
-    delegate_mode = ExtensionSettingDataTypeController::DelegateMode::
-        kTransportModeWithSingleModel;
-  }
-  return std::make_unique<ExtensionSettingDataTypeController>(
-      syncer::APP_SETTINGS, GetDataTypeStoreService()->GetStoreFactory(),
-      extensions::settings_sync_util::GetSyncableServiceProvider(
-          profile_, syncer::APP_SETTINGS),
-      GetDumpStackClosure(), delegate_mode, profile_);
-}
-
-std::unique_ptr<syncer::DataTypeController>
-ChromeSyncClient::CreateWebAppsDataTypeController() {
-  auto* provider = web_app::WebAppProvider::GetForWebApps(profile_);
-
-  // This function should never be called when GetForWebApps() returns nullptr.
-  DCHECK(provider);
-  DCHECK(web_app::AreWebAppsEnabled(profile_));
-
-  syncer::DataTypeControllerDelegate* delegate = provider->sync_bridge_unsafe()
-                                                     .change_processor()
-                                                     ->GetControllerDelegate()
-                                                     .get();
-
-  std::unique_ptr<syncer::DataTypeControllerDelegate>
-      delegate_for_transport_mode = nullptr;
-  if (ShouldSyncAppsTypesInTransportMode()) {
-    delegate_for_transport_mode =
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            delegate);
-  }
-  return std::make_unique<syncer::DataTypeController>(
-      syncer::WEB_APPS,
-      /*delegate_for_full_sync_mode=*/
-      std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(delegate),
-      /*delegate_for_transport_mode=*/
-      std::move(delegate_for_transport_mode));
-}
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index ad9cae57..986695c0 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -11,20 +11,12 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/sync/glue/extensions_activity_monitor.h"
 #include "components/prefs/pref_change_registrar.h"
-#include "components/sync/service/data_type_controller.h"
 #include "components/sync/service/local_data_description.h"
 #include "components/sync/service/sync_client.h"
 #include "extensions/buildflags/buildflags.h"
 
 class Profile;
 
-namespace syncer {
-class DataTypeController;
-class DataTypeStoreService;
-class SyncService;
-class SyncableService;
-}  // namespace syncer
-
 namespace browser_sync {
 
 class LocalDataQueryHelper;
@@ -40,10 +32,6 @@
 
   ~ChromeSyncClient() override;
 
-  // TODO(crbug.com/335688372): Inline this in the sync_service_factory.cc.
-  syncer::DataTypeController::TypeVector CreateDataTypeControllers(
-      syncer::SyncService* sync_service);
-
   // SyncClient implementation.
   PrefService* GetPrefService() override;
   signin::IdentityManager* GetIdentityManager() override;
@@ -69,32 +57,13 @@
 #endif  // BUILDFLAG(IS_ANDROID)
 
  private:
-  // Convenience function that exercises DataTypeStoreServiceFactory.
-  syncer::DataTypeStoreService* GetDataTypeStoreService();
-
-  // Convenience function used during controller creation.
-  base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
-      syncer::DataType type);
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  // Creates the DataTypeController for syncer::APPS.
-  std::unique_ptr<syncer::DataTypeController> CreateAppsDataTypeController();
-
-  // Creates the DataTypeController for syncer::APP_SETTINGS.
-  std::unique_ptr<syncer::DataTypeController>
-  CreateAppSettingsDataTypeController(syncer::SyncService* sync_service);
-
-  // Creates the DataTypeController for syncer::WEB_APPS.
-  std::unique_ptr<syncer::DataTypeController> CreateWebAppsDataTypeController();
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
   const raw_ptr<Profile> profile_;
 
   // The sync engine factory in use by this client.
   std::unique_ptr<browser_sync::SyncEngineFactoryImpl> engine_factory_;
 
   // Generates and monitors the ExtensionsActivity object used by sync.
-  ExtensionsActivityMonitor extensions_activity_monitor_;
+  browser_sync::ExtensionsActivityMonitor extensions_activity_monitor_;
 
 #if BUILDFLAG(IS_ANDROID)
   std::unique_ptr<browser_sync::LocalDataQueryHelper> local_data_query_helper_;
diff --git a/chrome/browser/sync/chrome_sync_controller_builder.cc b/chrome/browser/sync/chrome_sync_controller_builder.cc
new file mode 100644
index 0000000..38583ca
--- /dev/null
+++ b/chrome/browser/sync/chrome_sync_controller_builder.cc
@@ -0,0 +1,438 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync/chrome_sync_controller_builder.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/security_events/security_event_recorder.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_syncable_service.h"
+#include "chrome/browser/ui/ui_features.h"
+#include "chrome/common/buildflags.h"
+#include "chrome/common/channel_info.h"
+#include "components/desks_storage/core/desk_sync_service.h"
+#include "components/prefs/pref_service.h"
+#include "components/spellcheck/spellcheck_buildflags.h"
+#include "components/sync/base/data_type.h"
+#include "components/sync/base/features.h"
+#include "components/sync/base/pref_names.h"
+#include "components/sync/base/report_unrecoverable_error.h"
+#include "components/sync/model/data_type_controller_delegate.h"
+#include "components/sync/model/data_type_store.h"
+#include "components/sync/model/data_type_store_service.h"
+#include "components/sync/model/forwarding_data_type_controller_delegate.h"
+#include "components/sync/service/data_type_controller.h"
+#include "components/sync/service/syncable_service_based_data_type_controller.h"
+#include "content/public/browser/browser_thread.h"
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/api/storage/settings_sync_util.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
+#include "chrome/browser/sync/glue/extension_data_type_controller.h"
+#include "chrome/browser/sync/glue/extension_setting_data_type_controller.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_sync_bridge.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/components/arc/arc_util.h"
+#include "ash/constants/ash_features.h"
+#include "ash/constants/ash_switches.h"
+#include "chrome/browser/ash/app_list/app_list_syncable_service.h"
+#include "chrome/browser/ash/app_list/arc/arc_package_sync_data_type_controller.h"
+#include "chrome/browser/ash/app_list/arc/arc_package_syncable_service.h"
+#include "chrome/browser/ash/arc/arc_util.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/floating_sso/floating_sso_service.h"
+#include "chrome/browser/ash/printing/oauth2/authorization_zones_manager.h"
+#include "chrome/browser/ash/printing/printers_sync_bridge.h"
+#include "chrome/browser/ash/printing/synced_printers_manager.h"
+#include "chromeos/ash/components/sync_wifi/wifi_configuration_sync_service.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+#if BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/android/webapk/webapk_sync_service.h"
+#endif  // BUILDFLAG(IS_ANDROID)
+
+namespace {
+
+bool ShouldSyncBrowserTypes() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  return crosapi::browser_util::IsAshBrowserSyncEnabled();
+#else
+  return true;
+#endif
+}
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+bool IsLacrosSecondaryProfile(Profile* profile) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  return !profile->IsMainProfile() &&
+         !web_app::IsMainProfileCheckSkippedForTesting();
+#else   // BUILDFLAG(IS_CHROMEOS_LACROS)
+  return false;
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+}
+
+bool ShouldSyncAppsTypesInTransportMode() {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  // When apps sync controlled by Ash Sync settings, allow running apps-related
+  // types (WEB_APPS, APPS and APP_SETTINGS) in transport-only mode using the
+  // same `delegate`.
+  return base::FeatureList::IsEnabled(syncer::kSyncChromeOSAppsToggleSharing);
+#else   // BUILDFLAG(IS_CHROMEOS_LACROS)
+  return false;
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+}
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+}  // namespace
+
+ChromeSyncControllerBuilder::ChromeSyncControllerBuilder() = default;
+
+ChromeSyncControllerBuilder::~ChromeSyncControllerBuilder() = default;
+
+void ChromeSyncControllerBuilder::SetDataTypeStoreService(
+    syncer::DataTypeStoreService* data_type_store_service) {
+  data_type_store_service_.Set(data_type_store_service);
+}
+
+void ChromeSyncControllerBuilder::SetSecurityEventRecorder(
+    SecurityEventRecorder* security_event_recorder) {
+  security_event_recorder_.Set(security_event_recorder);
+}
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+void ChromeSyncControllerBuilder::SetExtensionSyncService(
+    ExtensionSyncService* extension_sync_service) {
+  extension_sync_service_.Set(extension_sync_service);
+}
+
+void ChromeSyncControllerBuilder::SetExtensionSystemProfile(Profile* profile) {
+  extension_system_profile_.Set(profile);
+}
+
+void ChromeSyncControllerBuilder::SetThemeService(ThemeService* theme_service) {
+  theme_service_.Set(theme_service);
+}
+
+void ChromeSyncControllerBuilder::SetWebAppProvider(
+    web_app::WebAppProvider* web_app_provider) {
+  web_app_provider_.Set(web_app_provider);
+}
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+void ChromeSyncControllerBuilder::SetSpellcheckService(
+    SpellcheckService* spellcheck_service) {
+  spellcheck_service_.Set(spellcheck_service);
+}
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+
+#if BUILDFLAG(IS_ANDROID)
+void ChromeSyncControllerBuilder::SetWebApkSyncService(
+    webapk::WebApkSyncService* web_apk_sync_service) {
+  web_apk_sync_service_.Set(web_apk_sync_service);
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void ChromeSyncControllerBuilder::SetAppListSyncableService(
+    app_list::AppListSyncableService* app_list_syncable_service) {
+  app_list_syncable_service_.Set(app_list_syncable_service);
+}
+
+void ChromeSyncControllerBuilder::SetAuthorizationZonesManager(
+    ash::printing::oauth2::AuthorizationZonesManager*
+        authorization_zones_manager) {
+  authorization_zones_manager_.Set(authorization_zones_manager);
+}
+
+void ChromeSyncControllerBuilder::SetArcPackageSyncableService(
+    arc::ArcPackageSyncableService* arc_package_syncable_service,
+    Profile* arc_package_profile) {
+  arc_package_syncable_service_.Set(arc_package_syncable_service);
+  arc_package_profile_.Set(arc_package_profile);
+}
+
+void ChromeSyncControllerBuilder::SetDeskSyncService(
+    desks_storage::DeskSyncService* desk_sync_service) {
+  desk_sync_service_.Set(desk_sync_service);
+}
+
+void ChromeSyncControllerBuilder::SetFloatingSsoService(
+    ash::floating_sso::FloatingSsoService* floating_sso_service) {
+  floating_sso_service_.Set(floating_sso_service);
+}
+
+void ChromeSyncControllerBuilder::SetOsPrefServiceSyncable(
+    sync_preferences::PrefServiceSyncable* os_pref_service_syncable) {
+  os_pref_service_syncable_.Set(os_pref_service_syncable);
+}
+
+void ChromeSyncControllerBuilder::SetSyncedPrintersManager(
+    ash::SyncedPrintersManager* synced_printer_manager) {
+  synced_printer_manager_.Set(synced_printer_manager);
+}
+
+void ChromeSyncControllerBuilder::SetWifiConfigurationSyncService(
+    ash::sync_wifi::WifiConfigurationSyncService*
+        wifi_configuration_sync_service) {
+  wifi_configuration_sync_service_.Set(wifi_configuration_sync_service);
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+std::vector<std::unique_ptr<syncer::DataTypeController>>
+ChromeSyncControllerBuilder::Build(syncer::SyncService* sync_service) {
+  std::vector<std::unique_ptr<syncer::DataTypeController>> controllers;
+
+  const base::RepeatingClosure dump_stack = base::BindRepeating(
+      &syncer::ReportUnrecoverableError, chrome::GetChannel());
+
+  syncer::RepeatingDataTypeStoreFactory data_type_store_factory =
+      data_type_store_service_.value()->GetStoreFactory();
+
+  if (ShouldSyncBrowserTypes()) {
+    syncer::DataTypeControllerDelegate* security_events_delegate =
+        security_event_recorder_.value()->GetControllerDelegate().get();
+    // Forward both full-sync and transport-only modes to the same delegate,
+    // since behavior for SECURITY_EVENTS does not differ.
+    controllers.push_back(std::make_unique<syncer::DataTypeController>(
+        syncer::SECURITY_EVENTS,
+        /*delegate_for_full_sync_mode=*/
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            security_events_delegate),
+        /*delegate_for_transport_mode=*/
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            security_events_delegate)));
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+    if (extension_sync_service_.value()) {
+      controllers.push_back(
+          std::make_unique<browser_sync::ExtensionDataTypeController>(
+              syncer::EXTENSIONS, data_type_store_factory,
+              extension_sync_service_.value()->AsWeakPtr(), dump_stack,
+              browser_sync::ExtensionDataTypeController::DelegateMode::
+                  kLegacyFullSyncModeOnly,
+              extension_system_profile_.value()));
+
+      controllers.push_back(
+          std::make_unique<browser_sync::ExtensionSettingDataTypeController>(
+              syncer::EXTENSION_SETTINGS, data_type_store_factory,
+              extensions::settings_sync_util::GetSyncableServiceProvider(
+                  extension_system_profile_.value(),
+                  syncer::EXTENSION_SETTINGS),
+              dump_stack,
+              browser_sync::ExtensionSettingDataTypeController::DelegateMode::
+                  kLegacyFullSyncModeOnly,
+              extension_system_profile_.value()));
+
+      if (!IsLacrosSecondaryProfile(extension_system_profile_.value())) {
+        auto delegate_mode = browser_sync::ExtensionDataTypeController::
+            DelegateMode::kLegacyFullSyncModeOnly;
+        auto setting_delegate_mode =
+            browser_sync::ExtensionSettingDataTypeController::DelegateMode::
+                kLegacyFullSyncModeOnly;
+        if (ShouldSyncAppsTypesInTransportMode()) {
+          delegate_mode = browser_sync::ExtensionDataTypeController::
+              DelegateMode::kTransportModeWithSingleModel;
+          setting_delegate_mode =
+              browser_sync::ExtensionSettingDataTypeController::DelegateMode::
+                  kTransportModeWithSingleModel;
+        }
+
+        controllers.push_back(
+            std::make_unique<browser_sync::ExtensionDataTypeController>(
+                syncer::APPS, data_type_store_factory,
+                extension_sync_service_.value()->AsWeakPtr(), dump_stack,
+                delegate_mode, extension_system_profile_.value()));
+
+        controllers.push_back(
+            std::make_unique<browser_sync::ExtensionSettingDataTypeController>(
+                syncer::APP_SETTINGS, data_type_store_factory,
+                extensions::settings_sync_util::GetSyncableServiceProvider(
+                    extension_system_profile_.value(), syncer::APP_SETTINGS),
+                dump_stack, setting_delegate_mode,
+                extension_system_profile_.value()));
+      }
+    }
+
+    if (theme_service_.value()) {
+      controllers.push_back(
+          std::make_unique<browser_sync::ExtensionDataTypeController>(
+              syncer::THEMES, data_type_store_factory,
+              theme_service_.value()->GetThemeSyncableService()->AsWeakPtr(),
+              dump_stack,
+              browser_sync::ExtensionDataTypeController::DelegateMode::
+                  kLegacyFullSyncModeOnly,
+              extension_system_profile_.value()));
+    }
+
+    if (!IsLacrosSecondaryProfile(extension_system_profile_.value()) &&
+        web_app_provider_.value()) {
+      syncer::DataTypeControllerDelegate* delegate =
+          web_app_provider_.value()
+              ->sync_bridge_unsafe()
+              .change_processor()
+              ->GetControllerDelegate()
+              .get();
+
+      std::unique_ptr<syncer::DataTypeControllerDelegate>
+          delegate_for_transport_mode = nullptr;
+      if (ShouldSyncAppsTypesInTransportMode()) {
+        delegate_for_transport_mode =
+            std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+                delegate);
+      }
+      controllers.push_back(std::make_unique<syncer::DataTypeController>(
+          syncer::WEB_APPS,
+          /*delegate_for_full_sync_mode=*/
+          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+              delegate),
+          /*delegate_for_transport_mode=*/
+          std::move(delegate_for_transport_mode)));
+    }
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+#if BUILDFLAG(IS_ANDROID)
+    if (web_apk_sync_service_.value()) {
+      syncer::DataTypeControllerDelegate* delegate =
+          web_apk_sync_service_.value()->GetDataTypeControllerDelegate().get();
+      controllers.push_back(std::make_unique<syncer::DataTypeController>(
+          syncer::WEB_APKS,
+          /*delegate_for_full_sync_mode=*/
+          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+              delegate),
+          /*delegate_for_transport_mode=*/
+          std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+              delegate)));
+    }
+#endif  // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+    // Chrome prefers OS provided spell checkers where they exist. So only sync
+    // the custom dictionary on platforms that typically don't provide one.
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
+    // Dictionary sync is enabled by default.
+    if (spellcheck_service_.value()) {
+      controllers.push_back(
+          std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
+              syncer::DICTIONARY, data_type_store_factory,
+              spellcheck_service_.value()->GetCustomDictionary()->AsWeakPtr(),
+              dump_stack,
+              syncer::SyncableServiceBasedDataTypeController::DelegateMode::
+                  kLegacyFullSyncModeOnly));
+    }
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+  }
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  CHECK(os_pref_service_syncable_.value());
+  controllers.push_back(
+      std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
+          syncer::OS_PREFERENCES, data_type_store_factory,
+          os_pref_service_syncable_.value()
+              ->GetSyncableService(syncer::OS_PREFERENCES)
+              ->AsWeakPtr(),
+          dump_stack,
+          syncer::SyncableServiceBasedDataTypeController::DelegateMode::
+              kTransportModeWithSingleModel));
+  controllers.push_back(
+      std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
+          syncer::OS_PRIORITY_PREFERENCES, data_type_store_factory,
+          os_pref_service_syncable_.value()
+              ->GetSyncableService(syncer::OS_PRIORITY_PREFERENCES)
+              ->AsWeakPtr(),
+          dump_stack,
+          syncer::SyncableServiceBasedDataTypeController::DelegateMode::
+              kTransportModeWithSingleModel));
+
+  CHECK(synced_printer_manager_.value());
+  controllers.push_back(std::make_unique<syncer::DataTypeController>(
+      syncer::PRINTERS,
+      std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+          synced_printer_manager_.value()
+              ->GetSyncBridge()
+              ->change_processor()
+              ->GetControllerDelegate()
+              .get()),
+      /*delegate_for_transport_mode=*/nullptr));
+
+  // Some profile types (e.g. sign-in screen) don't support app list.
+  // Temporarily Disable AppListSyncableService for tablet form factor devices.
+  // See crbug/1013732 for details.
+  if (app_list_syncable_service_.value() &&
+      !ash::switches::IsTabletFormFactor()) {
+    // Runs in sync transport-mode and full-sync mode.
+    controllers.push_back(
+        std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
+            syncer::APP_LIST, data_type_store_factory,
+            app_list_syncable_service_.value()->AsWeakPtr(), dump_stack,
+            syncer::SyncableServiceBasedDataTypeController::DelegateMode::
+                kTransportModeWithSingleModel));
+  }
+
+  if (arc_package_syncable_service_.value()) {
+    controllers.push_back(std::make_unique<ArcPackageSyncDataTypeController>(
+        data_type_store_factory,
+        arc_package_syncable_service_.value()->AsWeakPtr(), dump_stack,
+        sync_service, arc_package_profile_.value()));
+  }
+
+  if (wifi_configuration_sync_service_.value()) {
+    syncer::DataTypeControllerDelegate* wifi_configurations_delegate =
+        wifi_configuration_sync_service_.value()->GetControllerDelegate().get();
+    controllers.push_back(std::make_unique<syncer::DataTypeController>(
+        syncer::WIFI_CONFIGURATIONS,
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            wifi_configurations_delegate),
+        /*delegate_for_transport_mode=*/nullptr));
+  }
+
+  CHECK(desk_sync_service_.value());
+  controllers.push_back(std::make_unique<syncer::DataTypeController>(
+      syncer::WORKSPACE_DESK,
+      std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+          desk_sync_service_.value()->GetControllerDelegate().get()),
+      /*delegate_for_transport_mode=*/nullptr));
+
+  if (authorization_zones_manager_.value()) {
+    syncer::DataTypeControllerDelegate*
+        printers_authorization_servers_delegate =
+            authorization_zones_manager_.value()
+                ->GetDataTypeSyncBridge()
+                ->change_processor()
+                ->GetControllerDelegate()
+                .get();
+    controllers.push_back(std::make_unique<syncer::DataTypeController>(
+        syncer::PRINTERS_AUTHORIZATION_SERVERS,
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            printers_authorization_servers_delegate),
+        /*delegate_for_transport_mode=*/nullptr));
+  }
+
+  if (floating_sso_service_.value()) {
+    controllers.push_back(std::make_unique<syncer::DataTypeController>(
+        syncer::COOKIES,
+        /*delegate_for_full_sync_mode=*/
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            floating_sso_service_.value()->GetControllerDelegate().get()),
+        /*delegate_for_transport_mode=*/nullptr));
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  return controllers;
+}
diff --git a/chrome/browser/sync/chrome_sync_controller_builder.h b/chrome/browser/sync/chrome_sync_controller_builder.h
new file mode 100644
index 0000000..a3d5017
--- /dev/null
+++ b/chrome/browser/sync/chrome_sync_controller_builder.h
@@ -0,0 +1,211 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SYNC_CHROME_SYNC_CONTROLLER_BUILDER_H_
+#define CHROME_BROWSER_SYNC_CHROME_SYNC_CONTROLLER_BUILDER_H_
+
+#include <memory>
+#include <optional>
+#include <utility>
+#include <vector>
+
+#include "base/check.h"
+#include "base/memory/raw_ptr.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "build/chromeos_buildflags.h"
+#include "components/spellcheck/spellcheck_buildflags.h"
+#include "extensions/buildflags/buildflags.h"
+
+class Profile;
+class SecurityEventRecorder;
+
+namespace syncer {
+class DataTypeController;
+class DataTypeStoreService;
+class SyncService;
+}  // namespace syncer
+
+namespace webapk {
+class WebApkSyncService;
+}  // namespace webapk
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+class ExtensionSyncService;
+class ThemeService;
+
+namespace web_app {
+class WebAppProvider;
+}  // namespace web_app
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+class SpellcheckService;
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+namespace app_list {
+class AppListSyncableService;
+}  // namespace app_list
+
+namespace ash {
+class SyncedPrintersManager;
+
+namespace floating_sso {
+class FloatingSsoService;
+}  // namespace floating_sso
+
+namespace printing::oauth2 {
+class AuthorizationZonesManager;
+}  // namespace printing::oauth2
+
+namespace sync_wifi {
+class WifiConfigurationSyncService;
+}  // namespace sync_wifi
+}  // namespace ash
+
+namespace arc {
+class ArcPackageSyncableService;
+}  // namespace arc
+
+namespace desks_storage {
+class DeskSyncService;
+}  // namespace desks_storage
+
+namespace sync_preferences {
+class PrefServiceSyncable;
+}  // namespace sync_preferences
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+// Class responsible for instantiating sync controllers (DataTypeController)
+// for datatypes / features under chrome/.
+//
+// NOTE: prefer adding new types to browser_sync::CommonControllerBuilder if the
+// type is available in components/, even if it's not enabled on all embedders
+// or platforms.
+//
+// Users of this class need to inject dependencies by invoking all setters (more
+// on this below) and finally invoke `Build()` to instantiate controllers.
+class ChromeSyncControllerBuilder {
+ public:
+  ChromeSyncControllerBuilder();
+  ~ChromeSyncControllerBuilder();
+
+  // Setters to inject dependencies. Each of these setters must be invoked
+  // before invoking `Build()`. In some cases it is allowed to inject nullptr.
+  void SetDataTypeStoreService(
+      syncer::DataTypeStoreService* data_type_store_service);
+  void SetSecurityEventRecorder(SecurityEventRecorder* security_event_recorder);
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  void SetExtensionSyncService(ExtensionSyncService* extension_sync_service);
+  void SetExtensionSystemProfile(Profile* profile);
+  void SetThemeService(ThemeService* theme_service);
+  void SetWebAppProvider(web_app::WebAppProvider* web_app_provider);
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+  void SetSpellcheckService(SpellcheckService* spellcheck_service);
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+
+#if BUILDFLAG(IS_ANDROID)
+  void SetWebApkSyncService(webapk::WebApkSyncService* web_apk_sync_service);
+#endif  // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  void SetAppListSyncableService(
+      app_list::AppListSyncableService* app_list_syncable_service);
+  void SetAuthorizationZonesManager(
+      ash::printing::oauth2::AuthorizationZonesManager*
+          authorization_zones_manager);
+  void SetArcPackageSyncableService(
+      arc::ArcPackageSyncableService* arc_package_syncable_service,
+      Profile* arc_package_profile);
+  void SetDeskSyncService(desks_storage::DeskSyncService* desk_sync_service);
+  void SetFloatingSsoService(
+      ash::floating_sso::FloatingSsoService* floating_sso_service);
+  void SetOsPrefServiceSyncable(
+      sync_preferences::PrefServiceSyncable* os_pref_service_syncable);
+  void SetSyncedPrintersManager(
+      ash::SyncedPrintersManager* synced_printer_manager);
+  void SetWifiConfigurationSyncService(
+      ash::sync_wifi::WifiConfigurationSyncService*
+          wifi_configuration_sync_service);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  // Actually builds the controllers. All setters above must have been called
+  // beforehand (null may or may not be allowed).
+  std::vector<std::unique_ptr<syncer::DataTypeController>> Build(
+      syncer::SyncService* sync_service);
+
+ private:
+  // Minimalistic fork of std::optional that enforces via CHECK that it has a
+  // value when accessing it.
+  template <typename Ptr>
+  class SafeOptional {
+   public:
+    SafeOptional() = default;
+    ~SafeOptional() = default;
+
+    void Set(Ptr ptr) {
+      CHECK(!ptr_.has_value());
+      ptr_.emplace(std::move(ptr));
+    }
+
+    // Set() must have been called before.
+    Ptr value() const {
+      CHECK(ptr_.has_value());
+      return ptr_.value();
+    }
+
+   private:
+    std::optional<Ptr> ptr_;
+  };
+
+  // For all above, nullopt indicates the corresponding setter wasn't invoked.
+  // nullptr indicates the setter was invoked with nullptr.
+  SafeOptional<raw_ptr<syncer::DataTypeStoreService>> data_type_store_service_;
+  SafeOptional<raw_ptr<SecurityEventRecorder>> security_event_recorder_;
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  SafeOptional<raw_ptr<ExtensionSyncService>> extension_sync_service_;
+  // This Profile instance has nothing special and is just the profile being
+  // exercised by the factory. A more tailored name is used simply to limit its
+  // usage beyond extensions.
+  SafeOptional<raw_ptr<Profile>> extension_system_profile_;
+  SafeOptional<raw_ptr<ThemeService>> theme_service_;
+  SafeOptional<raw_ptr<web_app::WebAppProvider>> web_app_provider_;
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+  SafeOptional<raw_ptr<SpellcheckService>> spellcheck_service_;
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+
+#if BUILDFLAG(IS_ANDROID)
+  SafeOptional<raw_ptr<webapk::WebApkSyncService>> web_apk_sync_service_;
+#endif  // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  SafeOptional<raw_ptr<app_list::AppListSyncableService>>
+      app_list_syncable_service_;
+  SafeOptional<raw_ptr<ash::printing::oauth2::AuthorizationZonesManager>>
+      authorization_zones_manager_;
+  SafeOptional<raw_ptr<arc::ArcPackageSyncableService>>
+      arc_package_syncable_service_;
+  // This Profile instance has nothing special and is just the profile being
+  // exercised by the factory. A more tailored name is used simply to limit its
+  // usage beyond ARC.
+  SafeOptional<raw_ptr<Profile>> arc_package_profile_;
+  SafeOptional<raw_ptr<desks_storage::DeskSyncService>> desk_sync_service_;
+  SafeOptional<raw_ptr<ash::floating_sso::FloatingSsoService>>
+      floating_sso_service_;
+  SafeOptional<raw_ptr<sync_preferences::PrefServiceSyncable>>
+      os_pref_service_syncable_;
+  SafeOptional<raw_ptr<ash::SyncedPrintersManager>> synced_printer_manager_;
+  SafeOptional<raw_ptr<ash::sync_wifi::WifiConfigurationSyncService>>
+      wifi_configuration_sync_service_;
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+};
+
+#endif  // CHROME_BROWSER_SYNC_CHROME_SYNC_CONTROLLER_BUILDER_H_
diff --git a/chrome/browser/sync/sync_service_factory.cc b/chrome/browser/sync/sync_service_factory.cc
index 99690c1..be91184 100644
--- a/chrome/browser/sync/sync_service_factory.cc
+++ b/chrome/browser/sync/sync_service_factory.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "base/containers/extend.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
@@ -29,8 +30,10 @@
 #include "chrome/browser/power_bookmarks/power_bookmark_service_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_key.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/reading_list/reading_list_model_factory.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/security_events/security_event_recorder_factory.h"
 #include "chrome/browser/sharing/sharing_message_bridge_factory.h"
@@ -41,6 +44,7 @@
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
 #include "chrome/browser/sync/account_bookmark_sync_service_factory.h"
 #include "chrome/browser/sync/chrome_sync_client.h"
+#include "chrome/browser/sync/chrome_sync_controller_builder.h"
 #include "chrome/browser/sync/data_type_store_service_factory.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/browser/sync/local_or_syncable_bookmark_sync_service_factory.h"
@@ -48,35 +52,51 @@
 #include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/sync/sync_invalidations_service_factory.h"
 #include "chrome/browser/sync/user_event_service_factory.h"
+#include "chrome/browser/tab_group_sync/feature_utils.h"
+#include "chrome/browser/tab_group_sync/tab_group_trial.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/trusted_vault/trusted_vault_service_factory.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
-#include "chrome/browser/web_applications/web_app_provider_factory.h"
 #include "chrome/browser/webdata_services/web_data_service_factory.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/browser_sync/common_controller_builder.h"
 #include "components/password_manager/core/browser/sharing/password_receiver_service.h"
+#include "components/plus_addresses/webdata/plus_address_webdata_service.h"
+#include "components/saved_tab_groups/features.h"
 #include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
+#include "components/spellcheck/browser/pref_names.h"
 #include "components/sync/base/command_line_switches.h"
 #include "components/sync/base/features.h"
 #include "components/sync/service/sync_service_impl.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/variations/service/google_groups_manager.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "extensions/buildflags/buildflags.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/extension_sync_service.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_provider_factory.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
 #include "extensions/browser/api/storage/storage_frontend.h"  // nogncheck
 #include "extensions/browser/extension_system_provider.h"     // nogncheck
 #include "extensions/browser/extensions_browser_client.h"     // nogncheck
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/components/arc/arc_util.h"
 #include "ash/constants/ash_features.h"
 #include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h"
+#include "chrome/browser/ash/app_list/arc/arc_package_syncable_service.h"
+#include "chrome/browser/ash/arc/arc_util.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/floating_sso/floating_sso_service_factory.h"
 #include "chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h"
 #include "chrome/browser/ash/printing/synced_printers_manager_factory.h"
@@ -86,29 +106,255 @@
 
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
     BUILDFLAG(IS_WIN)
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #elif BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h"
+#include "components/saved_tab_groups/features.h"
 #endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
         // BUILDFLAG(IS_WIN)
 
-#if !BUILDFLAG(IS_ANDROID)
-#include "chrome/browser/webauthn/passkey_model_factory.h"
-#else  // !BUILDFLAG(IS_ANDROID)
-#include "base/android/scoped_java_ref.h"
-#endif  // BUILDFLAG(IS_ANDROID)
-
 #if BUILDFLAG(IS_ANDROID)
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/android/webapk/webapk_sync_service.h"
 #include "chrome/browser/android/webapk/webapk_sync_service_factory.h"
-#endif  // BUILDFLAG(IS_ANDROID)
 
 // Must come after other includes, because FromJniType() uses Profile.
-#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/sync/android/jni_headers/SyncServiceFactory_jni.h"
+#else  // BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/webauthn/passkey_model_factory.h"
 #endif  // BUILDFLAG(IS_ANDROID)
 
 namespace {
 
+bool ShouldSyncBrowserTypes() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  return crosapi::browser_util::IsAshBrowserSyncEnabled();
+#else
+  return true;
+#endif
+}
+
+syncer::DataTypeSet GetDisabledCommonDataTypes() {
+  if (!ShouldSyncBrowserTypes()) {
+    // If browser-sync is disabled (on ChromeOS Ash), most "common" data types
+    // are disabled. These types will be synced in Lacros instead.
+    return base::Difference(syncer::UserTypes(),
+                            {syncer::DEVICE_INFO, syncer::USER_CONSENTS});
+  }
+
+  // Common case: No disabled types.
+  return {};
+}
+
+// Returns TabGroupSyncService or null if the feature is disabled.
+// Tab group sync is enabled via separate feature flags on different platforms.
+tab_groups::TabGroupSyncService* GetTabGroupSyncService(Profile* profile) {
+  CHECK(profile);
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_WIN)
+  tab_groups::TabGroupSyncService* service =
+      tab_groups::SavedTabGroupUtils::GetServiceForProfile(profile);
+  CHECK(service);
+  return service;
+#elif BUILDFLAG(IS_ANDROID)
+  const bool enable_tab_group_sync =
+      tab_groups::IsTabGroupSyncEnabled(profile->GetPrefs()) &&
+      !base::FeatureList::IsEnabled(
+          tab_groups::kTabGroupSyncDisableNetworkLayer);
+  tab_groups::TabGroupTrial::OnTabgroupSyncEnabled(enable_tab_group_sync);
+  if (!enable_tab_group_sync) {
+    return nullptr;
+  }
+  tab_groups::TabGroupSyncService* service =
+      tab_groups::TabGroupSyncServiceFactory::GetForProfile(profile);
+  CHECK(service);
+  return service;
+#else
+  return nullptr;
+#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
+        // BUILDFLAG(IS_WIN)
+}
+
+syncer::DataTypeController::TypeVector CreateCommonControllers(
+    Profile* profile,
+    syncer::SyncService* sync_service) {
+  scoped_refptr<autofill::AutofillWebDataService> profile_web_data_service =
+      WebDataServiceFactory::GetAutofillWebDataForProfile(
+          profile, ServiceAccessType::IMPLICIT_ACCESS);
+  scoped_refptr<autofill::AutofillWebDataService> account_web_data_service =
+      WebDataServiceFactory::GetAutofillWebDataForAccount(
+          profile, ServiceAccessType::IMPLICIT_ACCESS);
+
+  // This class assumes that the tasks posted by the profile and account storage
+  // services will execute, in order, on the same sequence.
+  // This DCHECK makes that assumption explicit.
+#if DCHECK_IS_ON()
+  if (account_web_data_service && profile_web_data_service) {
+    profile_web_data_service->GetDBTaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(
+                       [](scoped_refptr<base::SequencedTaskRunner> ac_tr) {
+                         CHECK(ac_tr->RunsTasksInCurrentSequence());
+                       },
+                       account_web_data_service->GetDBTaskRunner()));
+  }
+#endif  // DCHECK_IS_ON()
+
+  browser_sync::CommonControllerBuilder builder;
+  builder.SetAutofillWebDataService(content::GetUIThreadTaskRunner({}),
+                                    profile_web_data_service,
+                                    account_web_data_service);
+  builder.SetBookmarkModel(BookmarkModelFactory::GetForBrowserContext(profile));
+  builder.SetBookmarkSyncService(
+      LocalOrSyncableBookmarkSyncServiceFactory::GetForProfile(profile),
+      AccountBookmarkSyncServiceFactory::GetForProfile(profile));
+  builder.SetConsentAuditor(ConsentAuditorFactory::GetForProfile(profile));
+  builder.SetDataSharingService(
+      data_sharing::DataSharingServiceFactory::GetForProfile(profile));
+  builder.SetDeviceInfoSyncService(
+      DeviceInfoSyncServiceFactory::GetForProfile(profile));
+  builder.SetDualReadingListModel(
+      ReadingListModelFactory::GetAsDualReadingListForBrowserContext(profile));
+  builder.SetFaviconService(FaviconServiceFactory::GetForProfile(
+      profile, ServiceAccessType::IMPLICIT_ACCESS));
+  builder.SetGoogleGroupsManager(
+      GoogleGroupsManagerFactory::GetForBrowserContext(profile));
+  builder.SetHistoryService(HistoryServiceFactory::GetForProfile(
+      profile, ServiceAccessType::EXPLICIT_ACCESS));
+  builder.SetIdentityManager(IdentityManagerFactory::GetForProfile(profile));
+  builder.SetDataTypeStoreService(
+      DataTypeStoreServiceFactory::GetForProfile(profile));
+#if !BUILDFLAG(IS_ANDROID)
+  builder.SetPasskeyModel(
+      base::FeatureList::IsEnabled(syncer::kSyncWebauthnCredentials)
+          ? PasskeyModelFactory::GetForProfile(profile)
+          : nullptr);
+#endif  // !BUILDFLAG(IS_ANDROID)
+  builder.SetPasswordReceiverService(
+      PasswordReceiverServiceFactory::GetForProfile(profile));
+  builder.SetPasswordSenderService(
+      PasswordSenderServiceFactory::GetForProfile(profile));
+  builder.SetPasswordStore(ProfilePasswordStoreFactory::GetForProfile(
+                               profile, ServiceAccessType::IMPLICIT_ACCESS),
+                           AccountPasswordStoreFactory::GetForProfile(
+                               profile, ServiceAccessType::IMPLICIT_ACCESS));
+  builder.SetPlusAddressServices(
+      PlusAddressSettingServiceFactory::GetForBrowserContext(profile),
+      WebDataServiceFactory::GetPlusAddressWebDataForProfile(
+          profile, ServiceAccessType::IMPLICIT_ACCESS));
+  builder.SetPowerBookmarkService(
+      PowerBookmarkServiceFactory::GetForBrowserContext(profile));
+  builder.SetPrefService(profile->GetPrefs());
+  builder.SetPrefServiceSyncable(PrefServiceSyncableFromProfile(profile));
+  builder.SetProductSpecificationsService(
+      commerce::ProductSpecificationsServiceFactory::GetForBrowserContext(
+          profile));
+  builder.SetTabGroupSyncService(GetTabGroupSyncService(profile));
+  builder.SetTemplateURLService(
+#if BUILDFLAG(IS_ANDROID)
+      nullptr
+#else   // BUILDFLAG(IS_ANDROID)
+      ShouldSyncBrowserTypes()
+          ? TemplateURLServiceFactory::GetForProfile(profile)
+          : nullptr
+#endif  // BUILDFLAG(IS_ANDROID)
+  );
+  builder.SetSendTabToSelfSyncService(
+      SendTabToSelfSyncServiceFactory::GetForProfile(profile));
+  builder.SetSessionSyncService(
+      SessionSyncServiceFactory::GetForProfile(profile));
+  builder.SetSharingMessageBridge(
+      ShouldSyncBrowserTypes()
+          ? SharingMessageBridgeFactory::GetForBrowserContext(profile)
+          : nullptr);
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+  builder.SetSupervisedUserSettingsService(
+      SupervisedUserSettingsServiceFactory::GetForKey(
+          profile->GetProfileKey()));
+#endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
+  builder.SetUserEventService(
+      browser_sync::UserEventServiceFactory::GetForProfile(profile));
+
+  return builder.Build(GetDisabledCommonDataTypes(), sync_service,
+                       chrome::GetChannel());
+}
+
+syncer::DataTypeController::TypeVector CreateChromeControllers(
+    Profile* profile,
+    syncer::SyncService* sync_service) {
+  ChromeSyncControllerBuilder builder;
+
+  builder.SetDataTypeStoreService(
+      DataTypeStoreServiceFactory::GetForProfile(profile));
+  builder.SetSecurityEventRecorder(
+      SecurityEventRecorderFactory::GetForProfile(profile));
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  builder.SetExtensionSyncService(ExtensionSyncService::Get(profile));
+  builder.SetExtensionSystemProfile(profile);
+  builder.SetThemeService(ThemeServiceFactory::GetForProfile(profile));
+  builder.SetWebAppProvider(
+      web_app::AreWebAppsEnabled(profile)
+          ? web_app::WebAppProvider::GetForWebApps(profile)
+          : nullptr);
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+  builder.SetSpellcheckService(
+      profile->GetPrefs()->GetBoolean(spellcheck::prefs::kSpellCheckEnable)
+          ? SpellcheckServiceFactory::GetForContext(profile)
+          : nullptr);
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+
+#if BUILDFLAG(IS_ANDROID)
+  builder.SetWebApkSyncService(
+      base::FeatureList::IsEnabled(syncer::kWebApkBackupAndRestoreBackend)
+          ? webapk::WebApkSyncService::GetForProfile(profile)
+          : nullptr);
+#endif  // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  const bool arc_enabled =
+      arc::IsArcAllowedForProfile(profile) && !arc::IsArcAppSyncFlowDisabled();
+
+  builder.SetAppListSyncableService(
+      app_list::AppListSyncableServiceFactory::GetForProfile(profile));
+  builder.SetAuthorizationZonesManager(
+      ash::features::IsOAuthIppEnabled()
+          ? ash::printing::oauth2::AuthorizationZonesManagerFactory::
+                GetForBrowserContext(profile)
+          : nullptr);
+  builder.SetArcPackageSyncableService(
+      arc_enabled ? arc::ArcPackageSyncableService::Get(profile) : nullptr,
+      arc_enabled ? profile : nullptr);
+  builder.SetDeskSyncService(DeskSyncServiceFactory::GetForProfile(profile));
+  builder.SetFloatingSsoService(
+      ash::features::IsFloatingSsoAllowed()
+          ? ash::floating_sso::FloatingSsoServiceFactory::GetForProfile(profile)
+          : nullptr);
+  builder.SetOsPrefServiceSyncable(PrefServiceSyncableFromProfile(profile));
+  builder.SetSyncedPrintersManager(
+      ash::SyncedPrintersManagerFactory::GetForBrowserContext(profile));
+  builder.SetWifiConfigurationSyncService(
+      WifiConfigurationSyncServiceFactory::ShouldRunInProfile(profile)
+          ? WifiConfigurationSyncServiceFactory::GetForProfile(profile,
+                                                               /*create=*/true)
+          : nullptr);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  return builder.Build(sync_service);
+}
+
+syncer::DataTypeController::TypeVector CreateControllers(
+    Profile* profile,
+    syncer::SyncService* sync_service) {
+  syncer::DataTypeController::TypeVector controllers =
+      CreateCommonControllers(profile, sync_service);
+  base::Extend(controllers, CreateChromeControllers(profile, sync_service));
+  return controllers;
+}
+
 std::unique_ptr<KeyedService> BuildSyncService(
     content::BrowserContext* context) {
   syncer::SyncServiceImpl::InitParams init_params;
@@ -129,11 +375,11 @@
   init_params.debug_identifier = profile->GetDebugName();
 
   bool local_sync_backend_enabled = false;
-// Only check the local sync backend pref on the supported platforms of
-// Windows, Mac and Linux.
-// TODO(crbug.com/40118868): Reassess whether the following block needs to be
-// included in lacros-chrome once build flag switch of lacros-chrome is
-// complete.
+  // Only check the local sync backend pref on the supported platforms of
+  // Windows, Mac and Linux.
+  // TODO(crbug.com/40118868): Reassess whether the following block needs to be
+  // included in lacros-chrome once build flag switch of lacros-chrome is
+  // complete.
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \
     (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
   syncer::SyncPrefs prefs(profile->GetPrefs());
@@ -166,14 +412,9 @@
     AboutSigninInternalsFactory::GetForProfile(profile);
   }
 
-  browser_sync::ChromeSyncClient* client_ptr =
-      static_cast<browser_sync::ChromeSyncClient*>(
-          init_params.sync_client.get());
-
   auto sync_service =
       std::make_unique<syncer::SyncServiceImpl>(std::move(init_params));
-  sync_service->Initialize(
-      client_ptr->CreateDataTypeControllers(sync_service.get()));
+  sync_service->Initialize(CreateControllers(profile, sync_service.get()));
 
   // Notify the PasswordStore of complete initialisation to resolve a circular
   // dependency.
@@ -215,7 +456,7 @@
   return sync_service;
 }
 
-}  // anonymous namespace
+}  // namespace
 
 // static
 SyncServiceFactory* SyncServiceFactory::GetInstance() {
diff --git a/chrome/browser/sync/sync_service_factory_unittest.cc b/chrome/browser/sync/sync_service_factory_unittest.cc
index 00eaff2..925067c 100644
--- a/chrome/browser/sync/sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/bind.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
@@ -21,6 +22,7 @@
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/data_sharing/public/features.h"
 #include "components/saved_tab_groups/features.h"
+#include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/sync/base/command_line_switches.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/base/features.h"
@@ -29,6 +31,11 @@
 #include "extensions/buildflags/buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+#include "chrome/browser/spellchecker/spellcheck_factory.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_features.h"
 #include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h"
@@ -66,6 +73,17 @@
     // Some services will only be created if there is a WebDataService.
     builder.AddTestingFactory(WebDataServiceFactory::GetInstance(),
                               WebDataServiceFactory::GetDefaultFactory());
+
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+    builder.AddTestingFactory(
+        SpellcheckServiceFactory::GetInstance(),
+        base::BindRepeating(base::BindLambdaForTesting(
+            [](content::BrowserContext* browser_context) {
+              return std::unique_ptr<KeyedService>(
+                  std::make_unique<SpellcheckService>(browser_context));
+            })));
+#endif  // BUILDFLAG(ENABLE_SPELLCHECK)
+
     profile_ = builder.Build();
   }
 
diff --git a/chrome/browser/tab_group/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java b/chrome/browser/tab_group/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java
index 10eb99b9..2d0dd5a 100644
--- a/chrome/browser/tab_group/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java
+++ b/chrome/browser/tab_group/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java
@@ -308,12 +308,12 @@
             }
 
             if (!skipUpdateTabModel) {
-                tabsIncludingDestination.add(destinationTab);
                 originalIndexes.add(
                         TabModelUtils.getTabIndexById(getTabModel(), destinationTab.getId()));
-                originalRootIds.add(destinationRootId);
                 originalTabGroupIds.add(destinationTab.getTabGroupId());
             }
+            tabsIncludingDestination.add(destinationTab);
+            originalRootIds.add(destinationRootId);
 
             Token destinationTabGroupId =
                     getOrCreateTabGroupIdWithDefault(destinationTab, sourceTab.getTabGroupId());
@@ -328,11 +328,11 @@
                 if (!skipUpdateTabModel) {
                     int index = TabModelUtils.getTabIndexById(getTabModel(), tab.getId());
                     assert index != TabModel.INVALID_TAB_INDEX;
-                    tabsIncludingDestination.add(tab);
                     originalIndexes.add(index);
-                    originalRootIds.add(tab.getRootId());
                     originalTabGroupIds.add(tab.getTabGroupId());
                 }
+                tabsIncludingDestination.add(tab);
+                originalRootIds.add(tab.getRootId());
                 @Nullable Token tabGroupId = tab.getTabGroupId();
                 if (tabGroupId != null) {
                     @Nullable
@@ -380,6 +380,13 @@
                             destinationGroupTitle,
                             destinationGroupColorId,
                             destinationGroupTitleCollapsed);
+                } else {
+                    for (int i = 0; i < tabsIncludingDestination.size(); i++) {
+                        Tab tab = tabsIncludingDestination.get(i);
+                        int rootId = originalRootIds.get(i);
+                        if (tab.getRootId() == rootId) continue;
+                        deleteTabGroupVisualData(rootId);
+                    }
                 }
 
                 for (Pair<Integer, Token> removedGroup : removedGroups) {
@@ -520,6 +527,13 @@
                         destinationGroupTitle,
                         destinationGroupColorId,
                         destinationGroupTitleCollapsed);
+            } else {
+                for (int i = 0; i < mergedTabs.size(); i++) {
+                    Tab tab = mergedTabs.get(i);
+                    int rootId = originalRootIds.get(i);
+                    if (tab.getRootId() == rootId) continue;
+                    deleteTabGroupVisualData(rootId);
+                }
             }
 
             for (Pair<Integer, Token> removedGroup : removedGroups) {
@@ -1537,6 +1551,18 @@
         return TabGroupCollapsedUtils.getTabGroupCollapsed(rootId);
     }
 
+    /** Delete the title, color and collapsed state of a tab group. */
+    public void deleteTabGroupVisualData(int rootId) {
+        deleteTabGroupTitle(rootId);
+
+        if (ChromeFeatureList.sTabGroupParityAndroid.isEnabled()) {
+            deleteTabGroupColor(rootId);
+        }
+        if (ChromeFeatureList.sTabStripGroupCollapse.isEnabled()) {
+            deleteTabGroupCollapsed(rootId);
+        }
+    }
+
     /** Returns the sync ID associated with the tab group. */
     public String getTabGroupSyncId(int rootId) {
         return TabGroupSyncIdUtils.getTabGroupSyncId(rootId);
diff --git a/chrome/browser/tab_group/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java b/chrome/browser/tab_group/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java
index 1b85663..7113ed8 100644
--- a/chrome/browser/tab_group/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java
+++ b/chrome/browser/tab_group/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java
@@ -47,6 +47,7 @@
 import org.mockito.Captor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
@@ -2058,6 +2059,27 @@
     }
 
     @Test
+    public void mergeGroupToGroupNonAdjacent_doNotNotifyFilterObserver() {
+        SharedPreferences.Editor titleEditor = Mockito.mock(SharedPreferences.Editor.class);
+        when(mSharedPreferencesTitle.edit()).thenReturn(titleEditor);
+        when(titleEditor.remove(anyString())).thenReturn(titleEditor);
+
+        mTabGroupModelFilter.mergeTabsToGroup(mTab2.getId(), mTab5.getId(), true);
+        verify(mTabGroupModelFilterObserver, never())
+                .didCreateNewGroup(mTab2, mTabGroupModelFilter);
+        verify(mTabGroupModelFilterObserver, never())
+                .didCreateGroup(
+                        anyList(),
+                        anyList(),
+                        anyList(),
+                        anyList(),
+                        anyString(),
+                        anyInt(),
+                        anyBoolean());
+        verify(titleEditor, times(2)).remove(String.valueOf(TAB2_ROOT_ID));
+    }
+
+    @Test
     public void mergeGroupToTabAdjacent_notifyFilterObserver() {
         // Override the setup behaviour for color SharedPreferences since after #didCreateNewGroup
         // is emitted, a color will have been set.
diff --git a/chrome/browser/tabpersistence/BUILD.gn b/chrome/browser/tabpersistence/BUILD.gn
index a8fba29..c8c3241 100644
--- a/chrome/browser/tabpersistence/BUILD.gn
+++ b/chrome/browser/tabpersistence/BUILD.gn
@@ -41,6 +41,7 @@
     "//base:base_java_test_support",
     "//base:base_junit_test_support",
     "//base/test:test_support_java",
+    "//chrome/browser/android/crypto:java",
     "//chrome/browser/tab:java",
     "//chrome/browser/tabpersistence:flatbuffer_java",
     "//chrome/test/android:chrome_java_unit_test_support",
diff --git a/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManager.java b/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManager.java
index 21689e99..3280e09 100644
--- a/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManager.java
+++ b/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManager.java
@@ -126,9 +126,10 @@
     /**
      * @param stateFolder folder {@link TabState} files are stored in
      * @param id {@link Tab} identifier
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      * @return {@link TabState} corresponding to Tab with id
      */
-    public static TabState restoreTabState(File stateFolder, int id) {
+    public static TabState restoreTabState(File stateFolder, int id, CipherFactory cipherFactory) {
         // If the FlatBuffer schema is enabled, try to restore using that. There are no guarantees,
         // however - for example if the flag was just turned on there won't have been the
         // opportunity to save any FlatBuffer based {@link TabState} files yet. So we
@@ -136,7 +137,7 @@
         if (isFlatBufferSchemaEnabled()) {
             TabState tabState = null;
             try {
-                tabState = restoreTabState(stateFolder, id, true);
+                tabState = restoreTabState(stateFolder, id, cipherFactory, true);
             } catch (Exception e) {
                 // TODO(crbug.com/341122002) Add in metrics
                 Log.d(TAG, "Error restoring TabState using FlatBuffer", e);
@@ -151,7 +152,7 @@
         }
         // Flatbuffer flag is off or we couldn't restore the TabState using a FlatBuffer based
         // file e.g. file doesn't exist for the Tab or is corrupt.
-        TabState tabState = restoreTabState(stateFolder, id, false);
+        TabState tabState = restoreTabState(stateFolder, id, cipherFactory, false);
         if (tabState == null) {
             RecordHistogram.recordEnumeratedHistogram(
                     "Tabs.TabState.RestoreMethod",
@@ -172,11 +173,13 @@
      *
      * @param stateFolder Folder containing the TabState files.
      * @param id ID of the Tab to restore.
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      * @param useFlatBuffer whether to restore using the FlatBuffer based TabState file or not.
      * @return TabState that has been restored, or null if it failed.
      */
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    public static TabState restoreTabState(File stateFolder, int id, boolean useFlatBuffer) {
+    public static TabState restoreTabState(
+            File stateFolder, int id, CipherFactory cipherFactory, boolean useFlatBuffer) {
         // First try finding an unencrypted file.
         boolean encrypted = false;
         File file = getTabStateFile(stateFolder, id, encrypted, useFlatBuffer);
@@ -192,7 +195,7 @@
 
         // If one of them passed, open the file input stream and read the state contents.
         long startTime = SystemClock.elapsedRealtime();
-        TabState tabState = restoreTabStateInternal(file, encrypted);
+        TabState tabState = restoreTabStateInternal(file, encrypted, cipherFactory);
         if (tabState != null) {
             RecordHistogram.recordTimesHistogram(
                     "Tabs.TabState.LoadTime", SystemClock.elapsedRealtime() - startTime);
@@ -205,15 +208,17 @@
      *
      * @param tabFile Location of the TabState file.
      * @param isEncrypted Whether the Tab state is encrypted or not.
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      * @return TabState that has been restored, or null if it failed.
      */
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    public static TabState restoreTabStateInternal(File tabFile, boolean isEncrypted) {
+    public static TabState restoreTabStateInternal(
+            File tabFile, boolean isEncrypted, CipherFactory cipherFactory) {
         TabState tabState = null;
         try {
             // TODO(b/307795775) investigate what strongly typed exceptions the FlatBuffer
             // code might throw and log metrics.
-            tabState = readState(tabFile, isEncrypted);
+            tabState = readState(tabFile, isEncrypted, cipherFactory);
         } catch (FileNotFoundException exception) {
             Log.e(TAG, "Failed to restore tab state for tab: " + tabFile);
             recordRestoreTabStateException(RestoreTabStateException.FILE_NOT_FOUND_EXCEPTION);
@@ -258,18 +263,19 @@
      *
      * @param file file with serialized {@link TabState}
      * @param encrypted Whether the file is encrypted or not.
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      * @return TabState that has been restored, or null if it failed.
      */
-    private static TabState readState(File file, boolean encrypted)
+    private static TabState readState(File file, boolean encrypted, CipherFactory cipherFactory)
             throws IOException, FileNotFoundException {
         if (file.getName().startsWith(FLATBUFFER_PREFIX)) {
-            return readStateFlatBuffer(file, encrypted);
+            return readStateFlatBuffer(file, encrypted, cipherFactory);
         }
         FileInputStream input = new FileInputStream(file);
         DataInputStream stream = null;
         try {
             if (encrypted) {
-                Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
+                Cipher cipher = cipherFactory.getCipher(Cipher.DECRYPT_MODE);
                 if (cipher != null) {
                     stream = new DataInputStream(new CipherInputStream(input, cipher));
                 }
@@ -420,7 +426,8 @@
         }
     }
 
-    private static TabState readStateFlatBuffer(File file, boolean encrypted) throws IOException {
+    private static TabState readStateFlatBuffer(
+            File file, boolean encrypted, CipherFactory cipherFactory) throws IOException {
         FileInputStream fileInputStream = null;
         CipherInputStream cipherInputStream = null;
         DataInputStream dataInputStream = null;
@@ -428,7 +435,7 @@
             fileInputStream = new FileInputStream(file);
             FlatBufferTabStateSerializer serializer = new FlatBufferTabStateSerializer(encrypted);
             if (encrypted) {
-                Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
+                Cipher cipher = cipherFactory.getCipher(Cipher.DECRYPT_MODE);
                 if (cipher == null) {
                     Log.e(
                             TAG,
@@ -470,15 +477,23 @@
      * @param tabState TabState to store in a file
      * @param tabId identifier for the Tab
      * @param isEncrypted whether the stored Tab is encrypted or not
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      */
     public static void saveState(
-            File directory, TabState tabState, int tabId, boolean isEncrypted) {
+            File directory,
+            TabState tabState,
+            int tabId,
+            boolean isEncrypted,
+            CipherFactory cipherFactory) {
         // Save regular hand-written based TabState file when the FlatBuffer flag is both on and
         // off.
         // We must always have a safe fallback to hand-written based TabState to be able to roll out
         // FlatBuffers safely.
         saveStateInternal(
-                getTabStateFile(directory, tabId, isEncrypted, false), tabState, isEncrypted);
+                getTabStateFile(directory, tabId, isEncrypted, false),
+                tabState,
+                isEncrypted,
+                cipherFactory);
     }
 
     /**
@@ -488,13 +503,21 @@
      * @param tabState TabState to store in a file
      * @param tabId identifier for the Tab
      * @param isEncrypted whether the stored Tab is encrypted or not
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      * @return true if migration was successful.
      */
     public static boolean migrateTabState(
-            File directory, TabState tabState, int tabId, boolean isEncrypted) {
+            File directory,
+            TabState tabState,
+            int tabId,
+            boolean isEncrypted,
+            CipherFactory cipherFactory) {
         try {
             saveStateInternal(
-                    getTabStateFile(directory, tabId, isEncrypted, true), tabState, isEncrypted);
+                    getTabStateFile(directory, tabId, isEncrypted, true),
+                    tabState,
+                    isEncrypted,
+                    cipherFactory);
             return true;
         } catch (Exception e) {
             // TODO(crbug.com/341122002) Add in metrics
@@ -520,9 +543,11 @@
      * @param file File to write the tab's state to.
      * @param state State object obtained from from {@link Tab#getState()}.
      * @param encrypted Whether or not the TabState should be encrypted.
+     * @param cipherFactory The {@link CipherFactory} used for encrypting and decrypting files.
      */
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    public static void saveStateInternal(File file, TabState state, boolean encrypted) {
+    public static void saveStateInternal(
+            File file, TabState state, boolean encrypted, CipherFactory cipherFactory) {
         if (state == null || state.contentsState == null) return;
         long startTime = SystemClock.elapsedRealtime();
 
@@ -537,13 +562,14 @@
         FileOutputStream fileOutputStream = null;
         try {
             if (file.getName().startsWith(FLATBUFFER_PREFIX)) {
-                saveStateFlatBuffer(file, state, encrypted, contentsStateBytes, startTime);
+                saveStateFlatBuffer(
+                        file, state, encrypted, cipherFactory, contentsStateBytes, startTime);
                 return;
             }
             fileOutputStream = new FileOutputStream(file);
 
             if (encrypted) {
-                Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
+                Cipher cipher = cipherFactory.getCipher(Cipher.ENCRYPT_MODE);
                 if (cipher != null) {
                     dataOutputStream =
                             new DataOutputStream(
@@ -601,6 +627,7 @@
             File file,
             TabState state,
             boolean encrypted,
+            CipherFactory cipherFactory,
             byte[] contentsStateBytes,
             long startTime) {
         FileOutputStream fileOutputStream = null;
@@ -613,7 +640,7 @@
             FlatBufferTabStateSerializer serializer = new FlatBufferTabStateSerializer(encrypted);
             ByteBuffer data = serializer.serialize(state, contentsStateBytes);
             if (encrypted) {
-                Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
+                Cipher cipher = cipherFactory.getCipher(Cipher.ENCRYPT_MODE);
                 if (cipher == null) {
                     Log.e(TAG, "Cannot save TabState FlatBuffer file because cipher is null");
                     return;
diff --git a/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManagerUnitTest.java b/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManagerUnitTest.java
index 87f2226..5a7df25 100644
--- a/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManagerUnitTest.java
+++ b/chrome/browser/tabpersistence/android/java/src/org/chromium/chrome/browser/tabpersistence/TabStateFileManagerUnitTest.java
@@ -10,6 +10,7 @@
 import androidx.annotation.Nullable;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -21,6 +22,7 @@
 import org.chromium.base.Token;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.HistogramWatcher;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.TabState;
 import org.chromium.chrome.browser.tab.TabUserAgent;
@@ -59,15 +61,24 @@
 
     @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
 
+    private CipherFactory mCipherFactory;
+
+    @Before
+    public void setUp() {
+        mCipherFactory = CipherFactory.getInstance();
+    }
+
     @Test
     public void testSaveTabStateWithMemoryMappedContentsState_WithoutTabGroupId()
             throws IOException {
         Token tabGroupId = null;
         File file = createTestTabStateFile();
         TabState state = createTabStateWithMappedByteBuffer(file, tabGroupId);
-        TabStateFileManager.saveStateInternal(file, state, false);
+        TabStateFileManager.saveStateInternal(file, state, false, mCipherFactory);
 
-        validateTestTabState(TabStateFileManager.restoreTabStateInternal(file, false), tabGroupId);
+        validateTestTabState(
+                TabStateFileManager.restoreTabStateInternal(file, false, mCipherFactory),
+                tabGroupId);
     }
 
     @Test
@@ -75,9 +86,11 @@
         Token tabGroupId = new Token(TAB_GROUP_ID_TOKEN_HIGH, TAB_GROUP_ID_TOKEN_LOW);
         File file = createTestTabStateFile();
         TabState state = createTabStateWithMappedByteBuffer(file, tabGroupId);
-        TabStateFileManager.saveStateInternal(file, state, false);
+        TabStateFileManager.saveStateInternal(file, state, false, mCipherFactory);
 
-        validateTestTabState(TabStateFileManager.restoreTabStateInternal(file, false), tabGroupId);
+        validateTestTabState(
+                TabStateFileManager.restoreTabStateInternal(file, false, mCipherFactory),
+                tabGroupId);
     }
 
     @Test
@@ -90,9 +103,10 @@
         WebContentsState contentsState = new WebContentsState(buffer);
         contentsState.setVersion(WebContentsState.CONTENTS_STATE_CURRENT_VERSION);
         TabState state = createTabState(contentsState);
-        TabStateFileManager.saveStateInternal(file, state, /* encrypted= */ false);
+        TabStateFileManager.saveStateInternal(file, state, /* encrypted= */ false, mCipherFactory);
         validateTestTabState(
-                TabStateFileManager.restoreTabStateInternal(file, /* isEncrypted= */ false),
+                TabStateFileManager.restoreTabStateInternal(
+                        file, /* isEncrypted= */ false, mCipherFactory),
                 contentsState);
     }
 
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_credit_card_sheet_item.xml b/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_credit_card_sheet_item.xml
index 4f930b2..11c5893 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_credit_card_sheet_item.xml
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_credit_card_sheet_item.xml
@@ -57,13 +57,24 @@
             android:maxLines="1"
             android:textAppearance="@style/TextAppearance.TextMedium.Secondary"
             android:visibility="gone" />
-        <!-- This line will hold either the information that the card is virtual or the expiration date -->
+        <!-- This line will display card benefits when available. Otherwise, it will show either
+             the virtual card status or the expiration date. -->
         <TextView
-            android:id="@+id/description_line_2"
+            android:id="@+id/first_line_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:ellipsize="end"
             android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.TextMedium.Secondary" />
+            android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/>
+        <!-- If card benefits are displayed on the first line, this line will show either the
+             virtual card status or the expiration date. -->
+        <TextView
+            android:id="@+id/second_line_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearance.TextMedium.Secondary"
+            android:visibility="gone" />
     </LinearLayout>
 </LinearLayout>
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java
index 7bf7473..0fc5fe9d 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java
@@ -32,6 +32,7 @@
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.MINOR_TEXT;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.NETWORK_NAME;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.ON_CREDIT_CARD_CLICK_ACTION;
+import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.SECOND_LINE_LABEL;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.DISMISS_HANDLER;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties.SCAN_CREDIT_CARD_CALLBACK;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties.SHOW_PAYMENT_METHOD_SETTINGS_CALLBACK;
@@ -162,30 +163,49 @@
                     VISA.getCardNameForAutofillDisplay(),
                     VISA.getObfuscatedLastFourDigits(),
                     VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
+                    /* applyDeactivatedStyle= */ false);
+    private static final AutofillSuggestion VISA_SUGGESTION_WITH_CARD_BENEFITS =
+            createCreditCardSuggestion(
+                    VISA.getCardNameForAutofillDisplay(),
+                    VISA.getObfuscatedLastFourDigits(),
+                    /* subLabel= */ "2% cashback on travel",
+                    VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion NICKNAMED_VISA_SUGGESTION =
             createCreditCardSuggestion(
                     NICKNAMED_VISA.getCardNameForAutofillDisplay(),
                     NICKNAMED_VISA.getObfuscatedLastFourDigits(),
                     NICKNAMED_VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion MASTERCARD_SUGGESTION =
             createCreditCardSuggestion(
                     MASTERCARD.getCardNameForAutofillDisplay(),
                     MASTERCARD.getObfuscatedLastFourDigits(),
                     MASTERCARD.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion NON_ACCEPTABLE_VIRTUAL_CARD_SUGGESTION =
             createCreditCardSuggestion(
                     VIRTUAL_CARD.getCardNameForAutofillDisplay(),
                     VIRTUAL_CARD.getObfuscatedLastFourDigits(),
                     /* subLabel= */ "Merchant doesn't accept this virtual card",
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ true);
     private static final AutofillSuggestion ACCEPTABLE_VIRTUAL_CARD_SUGGESTION =
             createCreditCardSuggestion(
                     VIRTUAL_CARD.getCardNameForAutofillDisplay(),
                     VIRTUAL_CARD.getObfuscatedLastFourDigits(),
                     /* subLabel= */ "Virtual Card",
+                    /* secondarySubLabel= */ "",
+                    /* applyDeactivatedStyle= */ false);
+    private static final AutofillSuggestion VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS =
+            createCreditCardSuggestion(
+                    VIRTUAL_CARD.getCardNameForAutofillDisplay(),
+                    VIRTUAL_CARD.getObfuscatedLastFourDigits(),
+                    /* subLabel= */ "2% cashback on travel",
+                    /* secondarySubLabel= */ "Virtual card",
                     /* applyDeactivatedStyle= */ false);
 
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@@ -259,7 +279,7 @@
         assertThat(getModelsOfType(itemList, HEADER).size(), is(1));
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(itemList, VISA_SUGGESTION);
+                getCardSuggestionModel(itemList, VISA_SUGGESTION);
         assertTrue(cardSuggestionModel.isPresent());
         assertThat(cardSuggestionModel.get().get(MAIN_TEXT), is(VISA_SUGGESTION.getLabel()));
         assertThat(
@@ -286,7 +306,7 @@
         assertThat(getModelsOfType(itemList, HEADER).size(), is(1));
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(itemList, VISA_SUGGESTION);
+                getCardSuggestionModel(itemList, VISA_SUGGESTION);
         assertTrue(cardSuggestionModel.isPresent());
         assertThat(cardSuggestionModel.get().get(MAIN_TEXT), is(VISA_SUGGESTION.getLabel()));
         assertThat(
@@ -294,8 +314,7 @@
         assertThat(
                 cardSuggestionModel.get().get(FIRST_LINE_LABEL), is(VISA_SUGGESTION.getSublabel()));
 
-        cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(itemList, MASTERCARD_SUGGESTION);
+        cardSuggestionModel = getCardSuggestionModel(itemList, MASTERCARD_SUGGESTION);
         assertThat(cardSuggestionModel.get().get(MAIN_TEXT), is(MASTERCARD_SUGGESTION.getLabel()));
         assertThat(
                 cardSuggestionModel.get().get(MINOR_TEXT),
@@ -323,17 +342,74 @@
         assertThat(getModelsOfType(itemList, HEADER).size(), is(1));
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(
-                        itemList, NON_ACCEPTABLE_VIRTUAL_CARD_SUGGESTION);
+                getCardSuggestionModel(itemList, NON_ACCEPTABLE_VIRTUAL_CARD_SUGGESTION);
         assertTrue(cardSuggestionModel.isPresent());
         assertTrue(cardSuggestionModel.get().get(APPLY_DEACTIVATED_STYLE));
 
-        cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(itemList, MASTERCARD_SUGGESTION);
+        cardSuggestionModel = getCardSuggestionModel(itemList, MASTERCARD_SUGGESTION);
         assertFalse(cardSuggestionModel.get().get(APPLY_DEACTIVATED_STYLE));
     }
 
     @Test
+    public void testShowCreditCardSuggestionsWithCardBenefits() throws TimeoutException {
+        mCoordinator.showSheet(
+                List.of(MASTERCARD, VISA, VIRTUAL_CARD),
+                List.of(
+                        MASTERCARD_SUGGESTION,
+                        VISA_SUGGESTION_WITH_CARD_BENEFITS,
+                        VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS),
+                /* shouldShowScanCreditCard= */ false);
+
+        ModelList itemList = mTouchToFillPaymentMethodModel.get(SHEET_ITEMS);
+        assertThat(getModelsOfType(itemList, CREDIT_CARD).size(), is(3));
+
+        assertThat(getModelsOfType(itemList, HEADER).size(), is(1));
+
+        Optional<PropertyModel> cardSuggestionModel =
+                getCardSuggestionModel(itemList, MASTERCARD_SUGGESTION);
+        assertTrue(cardSuggestionModel.isPresent());
+        assertThat(cardSuggestionModel.get().get(MAIN_TEXT), is(MASTERCARD_SUGGESTION.getLabel()));
+        assertThat(
+                cardSuggestionModel.get().get(MINOR_TEXT),
+                is(MASTERCARD_SUGGESTION.getSecondaryLabel()));
+        assertThat(
+                cardSuggestionModel.get().get(FIRST_LINE_LABEL),
+                is(MASTERCARD_SUGGESTION.getSublabel()));
+        // If card benefits are not present, the second line in labels is not visible.
+        assertNull(cardSuggestionModel.get().get(SECOND_LINE_LABEL));
+
+        cardSuggestionModel = getCardSuggestionModel(itemList, VISA_SUGGESTION_WITH_CARD_BENEFITS);
+        assertTrue(cardSuggestionModel.isPresent());
+        assertThat(
+                cardSuggestionModel.get().get(MAIN_TEXT),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getLabel()));
+        assertThat(
+                cardSuggestionModel.get().get(MINOR_TEXT),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getSecondaryLabel()));
+        assertThat(
+                cardSuggestionModel.get().get(FIRST_LINE_LABEL),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getSublabel()));
+        assertThat(
+                cardSuggestionModel.get().get(SECOND_LINE_LABEL),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getSecondarySublabel()));
+
+        cardSuggestionModel =
+                getCardSuggestionModel(itemList, VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS);
+        assertThat(
+                cardSuggestionModel.get().get(MAIN_TEXT),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getLabel()));
+        assertThat(
+                cardSuggestionModel.get().get(MINOR_TEXT),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getSecondaryLabel()));
+        assertThat(
+                cardSuggestionModel.get().get(FIRST_LINE_LABEL),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getSublabel()));
+        assertThat(
+                cardSuggestionModel.get().get(SECOND_LINE_LABEL),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getSecondarySublabel()));
+    }
+
+    @Test
     public void testScanNewCardIsShownForCreditCards() {
         mCoordinator.showSheet(
                 List.of(VISA, MASTERCARD),
@@ -382,7 +458,7 @@
         assertThat(mTouchToFillPaymentMethodModel.get(VISIBLE), is(true));
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(
+                getCardSuggestionModel(
                         mTouchToFillPaymentMethodModel.get(SHEET_ITEMS), VISA_SUGGESTION);
         assertNotNull(cardSuggestionModel.get().get(ON_CREDIT_CARD_CLICK_ACTION));
 
@@ -407,7 +483,7 @@
         assertThat(mTouchToFillPaymentMethodModel.get(VISIBLE), is(true));
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(
+                getCardSuggestionModel(
                         mTouchToFillPaymentMethodModel.get(SHEET_ITEMS), VISA_SUGGESTION);
         assertNotNull(cardSuggestionModel.get().get(ON_CREDIT_CARD_CLICK_ACTION));
 
@@ -433,7 +509,7 @@
         assertThat(mTouchToFillPaymentMethodModel.get(VISIBLE), is(true));
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(
+                getCardSuggestionModel(
                         mTouchToFillPaymentMethodModel.get(SHEET_ITEMS),
                         ACCEPTABLE_VIRTUAL_CARD_SUGGESTION);
         assertNotNull(cardSuggestionModel.get().get(ON_CREDIT_CARD_CLICK_ACTION));
@@ -546,7 +622,7 @@
         ModelList itemList = mTouchToFillPaymentMethodModel.get(SHEET_ITEMS);
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(itemList, NICKNAMED_VISA_SUGGESTION);
+                getCardSuggestionModel(itemList, NICKNAMED_VISA_SUGGESTION);
         assertTrue(cardSuggestionModel.isPresent());
         assertEquals("visa", cardSuggestionModel.get().get(NETWORK_NAME));
     }
@@ -559,7 +635,7 @@
         ModelList itemList = mTouchToFillPaymentMethodModel.get(SHEET_ITEMS);
 
         Optional<PropertyModel> cardSuggestionModel =
-                getCardSuggestionModelBySuggestionLabel(itemList, VISA_SUGGESTION);
+                getCardSuggestionModel(itemList, VISA_SUGGESTION);
         assertTrue(cardSuggestionModel.isPresent());
         assertTrue(cardSuggestionModel.get().get(NETWORK_NAME).isEmpty());
     }
@@ -693,13 +769,23 @@
                 .collect(Collectors.toList());
     }
 
-    private static Optional<PropertyModel> getCardSuggestionModelBySuggestionLabel(
+    private static Optional<PropertyModel> getCardSuggestionModel(
             ModelList items, AutofillSuggestion suggestion) {
         return StreamSupport.stream(items.spliterator(), false)
                 .filter(
                         item ->
                                 item.type == CREDIT_CARD
-                                        && item.model.get(MAIN_TEXT).equals(suggestion.getLabel()))
+                                        && item.model.get(MAIN_TEXT).equals(suggestion.getLabel())
+                                        && item.model
+                                                .get(MINOR_TEXT)
+                                                .equals(suggestion.getSecondaryLabel())
+                                        && item.model
+                                                .get(FIRST_LINE_LABEL)
+                                                .equals(suggestion.getSublabel())
+                                        && (suggestion.getSecondarySublabel() == null
+                                                || item.model
+                                                        .get(SECOND_LINE_LABEL)
+                                                        .equals(suggestion.getSecondarySublabel())))
                 .findFirst()
                 .map(item -> item.model);
     }
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java
index fd2df66..2df3d28 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java
@@ -13,6 +13,7 @@
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.NETWORK_NAME;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.NON_TRANSFORMING_CREDIT_CARD_SUGGESTION_KEYS;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.ON_CREDIT_CARD_CLICK_ACTION;
+import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.SECOND_LINE_LABEL;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties.SCAN_CREDIT_CARD_CALLBACK;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties.SHOULD_SHOW_SCAN_CREDIT_CARD;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties.SHOW_PAYMENT_METHOD_SETTINGS_CALLBACK;
@@ -317,7 +318,10 @@
                         // line, and for non-virtual cards, show the expiration date.
                         // If the merchant has opted-out for the virtual card, on the second
                         // line we convey that merchant does not accept this virtual card.
+                        // For cards with benefits, show the benefits on the second line and
+                        // the expiration date or virtual card status on the third line.
                         .with(FIRST_LINE_LABEL, suggestion.getSublabel())
+                        .with(SECOND_LINE_LABEL, suggestion.getSecondarySublabel())
                         .with(ON_CREDIT_CARD_CLICK_ACTION, () -> this.onSelectedCreditCard(card))
                         .with(ITEM_COLLECTION_INFO, itemCollectionInfo)
                         .with(APPLY_DEACTIVATED_STYLE, suggestion.applyDeactivatedStyle());
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java
index c3bbc13..a753289 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java
@@ -79,6 +79,8 @@
                 new PropertyModel.ReadableObjectPropertyKey<>("minor_text");
         static final PropertyModel.ReadableObjectPropertyKey<String> FIRST_LINE_LABEL =
                 new PropertyModel.ReadableObjectPropertyKey<>("first_line_label");
+        static final PropertyModel.ReadableObjectPropertyKey<String> SECOND_LINE_LABEL =
+                new PropertyModel.ReadableObjectPropertyKey<>("second_line_label");
         static final PropertyModel.ReadableObjectPropertyKey<Runnable> ON_CREDIT_CARD_CLICK_ACTION =
                 new PropertyModel.ReadableObjectPropertyKey<>("on_credit_card_click_action");
         static final PropertyModel.ReadableBooleanPropertyKey APPLY_DEACTIVATED_STYLE =
@@ -92,6 +94,7 @@
             MAIN_TEXT,
             MINOR_TEXT,
             FIRST_LINE_LABEL,
+            SECOND_LINE_LABEL,
             ON_CREDIT_CARD_CLICK_ACTION,
             APPLY_DEACTIVATED_STYLE,
             ITEM_COLLECTION_INFO
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java
index efe27554..347576a 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java
@@ -167,12 +167,21 @@
                     VISA.getCardNameForAutofillDisplay(),
                     VISA.getObfuscatedLastFourDigits(),
                     VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
+                    /* applyDeactivatedStyle= */ false);
+    private static final AutofillSuggestion VISA_SUGGESTION_WITH_CARD_BENEFITS =
+            createCreditCardSuggestion(
+                    VISA.getCardNameForAutofillDisplay(),
+                    VISA.getObfuscatedLastFourDigits(),
+                    /* subLabel= */ "2% cashback on travel",
+                    VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion MASTERCARD_SUGGESTION =
             createCreditCardSuggestion(
                     MASTERCARD.getCardNameForAutofillDisplay(),
                     MASTERCARD.getObfuscatedLastFourDigits(),
                     MASTERCARD.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion SERVER_MASTERCARD_SUGGESTION =
             createCreditCardSuggestion(
@@ -180,12 +189,14 @@
                     SERVER_MASTERCARD.getObfuscatedLastFourDigits(),
                     SERVER_MASTERCARD.getFormattedExpirationDate(
                             ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion DISCOVER_SUGGESTION =
             createCreditCardSuggestion(
                     DISCOVER.getCardNameForAutofillDisplay(),
                     DISCOVER.getObfuscatedLastFourDigits(),
                     DISCOVER.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion AMERICAN_EXPRESS_SUGGESTION =
             createCreditCardSuggestion(
@@ -193,19 +204,29 @@
                     AMERICAN_EXPRESS.getObfuscatedLastFourDigits(),
                     AMERICAN_EXPRESS.getFormattedExpirationDate(
                             ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion ACCEPTABLE_MASTERCARD_VIRTUAL_CARD_SUGGESTION =
             createCreditCardSuggestion(
                     MASTERCARD_VIRTUAL_CARD.getCardNameForAutofillDisplay(),
                     MASTERCARD_VIRTUAL_CARD.getObfuscatedLastFourDigits(),
                     /* subLabel= */ "Virtual card",
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion NON_ACCEPTABLE_MASTERCARD_VIRTUAL_CARD_SUGGESTION =
             createCreditCardSuggestion(
                     MASTERCARD_VIRTUAL_CARD.getCardNameForAutofillDisplay(),
                     MASTERCARD_VIRTUAL_CARD.getObfuscatedLastFourDigits(),
                     /* subLabel= */ "Merchant doesn't accept this virtual card",
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ true);
+    private static final AutofillSuggestion MASTERCARD_VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS =
+            createCreditCardSuggestion(
+                    MASTERCARD_VIRTUAL_CARD.getCardNameForAutofillDisplay(),
+                    MASTERCARD_VIRTUAL_CARD.getObfuscatedLastFourDigits(),
+                    /* subLabel= */ "2% cashback on travel",
+                    /* secondarySubLabel= */ "Virtual card",
+                    /* applyDeactivatedStyle= */ false);
 
     private BottomSheetController mBottomSheetController;
     private TouchToFillPaymentMethodCoordinator mCoordinator;
@@ -454,6 +475,27 @@
     @Test
     @MediumTest
     @Feature({"RenderTest"})
+    public void testShowsServerAndVirtualCardsWithCardBenefits() throws IOException {
+        runOnUiThreadBlocking(
+                () -> {
+                    mCoordinator.showSheet(
+                            List.of(VISA, MASTERCARD_VIRTUAL_CARD),
+                            List.of(
+                                    VISA_SUGGESTION_WITH_CARD_BENEFITS,
+                                    MASTERCARD_VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS),
+                            /* shouldShowScanCreditCard= */ true);
+                });
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        View bottomSheetView = mActivityTestRule.getActivity().findViewById(R.id.bottom_sheet);
+        mRenderTestRule.render(
+                bottomSheetView,
+                "touch_to_fill_credit_card_sheet_shows_real_and_virtual_cards_with_card_benefits");
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"RenderTest"})
     @RequiresRestart("crbug.com/344665938")
     public void testScanNewCardButtonIsHidden() throws IOException {
         runOnUiThreadBlocking(
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java
index adf876f4..2033236 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java
@@ -12,6 +12,7 @@
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.MINOR_TEXT;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.NETWORK_NAME;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.ON_CREDIT_CARD_CLICK_ACTION;
+import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.SECOND_LINE_LABEL;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.DISMISS_HANDLER;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties.SCAN_CREDIT_CARD_CALLBACK;
 import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties.SHOULD_SHOW_SCAN_CREDIT_CARD;
@@ -137,7 +138,15 @@
         TextView mainText = view.findViewById(R.id.main_text);
         TextView minorText = view.findViewById(R.id.minor_text);
         ImageView icon = view.findViewById(R.id.favicon);
-        TextView descriptionLabel = view.findViewById(R.id.description_line_2);
+        TextView firstLineLabel = view.findViewById(R.id.first_line_label);
+        TextView secondLineLabel = view.findViewById(R.id.second_line_label);
+        // If card benefits are displayed on the first line, the second line will show
+        // primary label with the expiration date or the virtual card status.
+        TextView primaryLabel = firstLineLabel;
+        if (model.get(SECOND_LINE_LABEL) != null) {
+            secondLineLabel.setVisibility(View.VISIBLE);
+            primaryLabel = secondLineLabel;
+        }
         if (propertyKey == CARD_IMAGE) {
             icon.setImageDrawable(model.get(CARD_IMAGE));
         } else if (propertyKey == NETWORK_NAME) {
@@ -151,28 +160,30 @@
         } else if (propertyKey == MINOR_TEXT) {
             minorText.setText(model.get(MINOR_TEXT));
         } else if (propertyKey == FIRST_LINE_LABEL) {
-            descriptionLabel.setText(model.get(FIRST_LINE_LABEL));
+            firstLineLabel.setText(model.get(FIRST_LINE_LABEL));
+        } else if (propertyKey == SECOND_LINE_LABEL) {
+            secondLineLabel.setText(model.get(SECOND_LINE_LABEL));
         } else if (propertyKey == ON_CREDIT_CARD_CLICK_ACTION) {
             view.setOnClickListener(unusedView -> model.get(ON_CREDIT_CARD_CLICK_ACTION).run());
         } else if (propertyKey == ITEM_COLLECTION_INFO) {
             FillableItemCollectionInfo collectionInfo = model.get(ITEM_COLLECTION_INFO);
             if (collectionInfo != null) {
-                descriptionLabel.setAccessibilityDelegate(
+                primaryLabel.setAccessibilityDelegate(
                         new TextViewCollectionInfoAccessibilityDelegate(collectionInfo));
             }
         } else if (propertyKey == APPLY_DEACTIVATED_STYLE) {
             if (model.get(APPLY_DEACTIVATED_STYLE)) {
                 view.setEnabled(false);
                 // When merchants have opted out of virtual cards, we convey it
-                // via a message in description. Since this message is
+                // via a message in primary label. Since this message is
                 // important, we remove the max lines limit to avoid truncation.
-                descriptionLabel.setMaxLines(Integer.MAX_VALUE);
+                primaryLabel.setMaxLines(Integer.MAX_VALUE);
                 mainText.setTextAppearance(R.style.TextAppearance_TextMedium_Disabled);
                 minorText.setTextAppearance(R.style.TextAppearance_TextMedium_Disabled);
                 icon.setAlpha(GRAYED_OUT_OPACITY_ALPHA);
             } else {
                 view.setEnabled(true);
-                descriptionLabel.setMaxLines(1);
+                primaryLabel.setMaxLines(1);
                 mainText.setTextAppearance(R.style.TextAppearance_TextMedium_Primary);
                 minorText.setTextAppearance(R.style.TextAppearance_TextMedium_Primary);
                 icon.setAlpha(COMPLETE_OPACITY_ALPHA);
@@ -255,6 +266,7 @@
                 || propertyKey == MAIN_TEXT
                 || propertyKey == MINOR_TEXT
                 || propertyKey == FIRST_LINE_LABEL
+                || propertyKey == SECOND_LINE_LABEL
                 || propertyKey == IBAN_VALUE
                 || propertyKey == IBAN_NICKNAME
                 || propertyKey == ITEM_COLLECTION_INFO
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java
index 9bd79c4..3588ca7 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java
@@ -89,12 +89,17 @@
             @JniType("std::u16string") String label,
             @JniType("std::u16string") String secondaryLabel,
             @JniType("std::u16string") String subLabel,
+            @JniType("std::u16string") String secondarySubLabel,
             boolean applyDeactivatedStyle) {
-        return new AutofillSuggestion.Builder()
-                .setLabel(label)
-                .setSecondaryLabel(secondaryLabel)
-                .setSubLabel(subLabel)
-                .setApplyDeactivatedStyle(applyDeactivatedStyle)
-                .build();
+        AutofillSuggestion.Builder builder =
+                new AutofillSuggestion.Builder()
+                        .setLabel(label)
+                        .setSecondaryLabel(secondaryLabel)
+                        .setSubLabel(subLabel)
+                        .setApplyDeactivatedStyle(applyDeactivatedStyle);
+        if (!secondarySubLabel.isEmpty()) {
+            builder.setSecondarySubLabel(secondarySubLabel);
+        }
+        return builder.build();
     }
 }
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java
index 5c9e1a2c..2c89bb6 100644
--- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java
+++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java
@@ -143,30 +143,49 @@
                     VISA.getCardNameForAutofillDisplay(),
                     VISA.getObfuscatedLastFourDigits(),
                     VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
+                    /* applyDeactivatedStyle= */ false);
+    private static final AutofillSuggestion VISA_SUGGESTION_WITH_CARD_BENEFITS =
+            createCreditCardSuggestion(
+                    VISA.getCardNameForAutofillDisplay(),
+                    VISA.getObfuscatedLastFourDigits(),
+                    /* subLabel= */ "2% cashback on travel",
+                    VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion NICKNAMED_VISA_SUGGESTION =
             createCreditCardSuggestion(
                     NICKNAMED_VISA.getCardNameForAutofillDisplay(),
                     NICKNAMED_VISA.getObfuscatedLastFourDigits(),
                     NICKNAMED_VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion MASTERCARD_SUGGESTION =
             createCreditCardSuggestion(
                     MASTERCARD.getName(),
                     MASTERCARD.getNumber(),
                     MASTERCARD.getFormattedExpirationDate(ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion VIRTUAL_CARD_SUGGESTION =
             createCreditCardSuggestion(
                     VIRTUAL_CARD.getCardNameForAutofillDisplay(),
                     VIRTUAL_CARD.getObfuscatedLastFourDigits(),
                     /* subLabel= */ "Virtual card",
+                    /* secondarySubLabel= */ "",
+                    /* applyDeactivatedStyle= */ false);
+    private static final AutofillSuggestion VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS =
+            createCreditCardSuggestion(
+                    VIRTUAL_CARD.getCardNameForAutofillDisplay(),
+                    VIRTUAL_CARD.getObfuscatedLastFourDigits(),
+                    /* subLabel= */ "2% cashback on travel",
+                    /* secondarySubLabel= */ "Virtual card",
                     /* applyDeactivatedStyle= */ false);
     private static final AutofillSuggestion NON_ACCEPTABLE_VIRTUAL_CARD_SUGGESTION =
             createCreditCardSuggestion(
                     VIRTUAL_CARD.getCardNameForAutofillDisplay(),
                     VIRTUAL_CARD.getObfuscatedLastFourDigits(),
                     /* subLabel= */ "Merchant doesn't accept this virtual card",
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ true);
     private static final AutofillSuggestion LONG_CARD_NAME_CARD_SUGGESTION =
             createCreditCardSuggestion(
@@ -174,6 +193,7 @@
                     LONG_CARD_NAME_CARD.getObfuscatedLastFourDigits(),
                     LONG_CARD_NAME_CARD.getFormattedExpirationDate(
                             ContextUtils.getApplicationContext()),
+                    /* secondarySubLabel= */ "",
                     /* applyDeactivatedStyle= */ false);
     private static final Iban LOCAL_IBAN =
             Iban.createLocal(
@@ -294,7 +314,7 @@
         assertThat(getSuggestionMainTextAt(0).getText(), is(VISA_SUGGESTION.getLabel()));
         assertThat(getSuggestionMinorTextAt(0).getText(), is(VISA_SUGGESTION.getSecondaryLabel()));
         assertThat(
-                getSuggestionLabelAt(0).getText(),
+                getSuggestionFirstLineLabelAt(0).getText(),
                 is(VISA.getFormattedExpirationDate(ContextUtils.getApplicationContext())));
 
         assertThat(getSuggestionMainTextAt(1).getText(), is(MASTERCARD_SUGGESTION.getLabel()));
@@ -302,14 +322,16 @@
                 getSuggestionMinorTextAt(1).getText(),
                 is(MASTERCARD_SUGGESTION.getSecondaryLabel()));
         assertThat(
-                getSuggestionLabelAt(1).getText(),
+                getSuggestionFirstLineLabelAt(1).getText(),
                 is(MASTERCARD.getFormattedExpirationDate(ContextUtils.getApplicationContext())));
 
         assertThat(getSuggestionMainTextAt(2).getText(), is(VIRTUAL_CARD_SUGGESTION.getLabel()));
         assertThat(
                 getSuggestionMinorTextAt(2).getText(),
                 is(VIRTUAL_CARD_SUGGESTION.getSecondaryLabel()));
-        assertThat(getSuggestionLabelAt(2).getText(), is(VIRTUAL_CARD_SUGGESTION.getSublabel()));
+        assertThat(
+                getSuggestionFirstLineLabelAt(2).getText(),
+                is(VIRTUAL_CARD_SUGGESTION.getSublabel()));
     }
 
     @Test
@@ -563,26 +585,14 @@
                                             createCardSuggestionModel(
                                                     VISA,
                                                     VISA_SUGGESTION,
-                                                    new FillableItemCollectionInfo(1, 1))));
+                                                    new FillableItemCollectionInfo(
+                                                            /* position= */ 1, /* total= */ 1))));
                     mTouchToFillPaymentMethodModel.set(VISIBLE, true);
                 });
         BottomSheetTestSupport.waitForOpen(mBottomSheetController);
 
-        TextView descriptionLine =
-                mTouchToFillPaymentMethodView
-                        .getContentView()
-                        .findViewById(R.id.description_line_2);
-        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
-        descriptionLine.onInitializeAccessibilityNodeInfo(info);
-        assertEquals(
-                descriptionLine
-                        .getContext()
-                        .getString(
-                                R.string.autofill_payment_method_a11y_item_collection_info,
-                                descriptionLine.getText(),
-                                1,
-                                1),
-                info.getContentDescription());
+        assertContentDescriptionEquals(
+                getSuggestionFirstLineLabelAt(0), /* position= */ 1, /* total= */ 1);
     }
 
     @Test
@@ -598,26 +608,103 @@
                                             createCardSuggestionModel(
                                                     VIRTUAL_CARD,
                                                     VIRTUAL_CARD_SUGGESTION,
-                                                    new FillableItemCollectionInfo(1, 1))));
+                                                    new FillableItemCollectionInfo(
+                                                            /* position= */ 1, /* total= */ 1))));
                     mTouchToFillPaymentMethodModel.set(VISIBLE, true);
                 });
         BottomSheetTestSupport.waitForOpen(mBottomSheetController);
 
-        TextView descriptionLine =
-                mTouchToFillPaymentMethodView
-                        .getContentView()
-                        .findViewById(R.id.description_line_2);
-        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
-        descriptionLine.onInitializeAccessibilityNodeInfo(info);
-        assertEquals(
-                descriptionLine
-                        .getContext()
-                        .getString(
-                                R.string.autofill_payment_method_a11y_item_collection_info,
-                                descriptionLine.getText(),
-                                1,
-                                1),
-                info.getContentDescription());
+        assertContentDescriptionEquals(
+                getSuggestionFirstLineLabelAt(0), /* position= */ 1, /* total= */ 1);
+    }
+
+    @Test
+    @MediumTest
+    public void testFirstAndSecondLineLabelsOfCreditCardSuggestion_CardBenefitsPresent() {
+        runOnUiThreadBlocking(
+                () -> {
+                    mTouchToFillPaymentMethodModel
+                            .get(SHEET_ITEMS)
+                            .add(
+                                    new ListItem(
+                                            CREDIT_CARD,
+                                            createCardSuggestionModel(
+                                                    VISA,
+                                                    VISA_SUGGESTION_WITH_CARD_BENEFITS,
+                                                    new FillableItemCollectionInfo(
+                                                            /* position= */ 1, /* total= */ 1))));
+                    mTouchToFillPaymentMethodModel.set(VISIBLE, true);
+                });
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        assertThat(
+                getSuggestionMainTextAt(0).getText(),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getLabel()));
+        assertThat(
+                getSuggestionMinorTextAt(0).getText(),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getSecondaryLabel()));
+        assertThat(
+                getSuggestionFirstLineLabelAt(0).getText(),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getSublabel()));
+        TextView secondLineLabel = getSuggestionSecondLineLabelAt(0);
+        assertThat(
+                secondLineLabel.getText(),
+                is(VISA_SUGGESTION_WITH_CARD_BENEFITS.getSecondarySublabel()));
+        assertContentDescriptionEquals(secondLineLabel, /* position= */ 1, /* total= */ 1);
+    }
+
+    @Test
+    @MediumTest
+    public void testSecondLineLabelOfCreditCardSuggestion_HiddenWithoutCardBenefits() {
+        runOnUiThreadBlocking(
+                () -> {
+                    mTouchToFillPaymentMethodModel
+                            .get(SHEET_ITEMS)
+                            .add(
+                                    new ListItem(
+                                            CREDIT_CARD,
+                                            createCardSuggestionModel(
+                                                    VISA, VISA_SUGGESTION, mItemCollectionInfo)));
+                    mTouchToFillPaymentMethodModel.set(VISIBLE, true);
+                });
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        assertEquals(getSuggestionSecondLineLabelAt(0).getVisibility(), View.GONE);
+    }
+
+    @Test
+    @MediumTest
+    public void testFirstAndSecondLineLabelsOfVirtualCardSuggestion_CardBenefitsPresent() {
+        runOnUiThreadBlocking(
+                () -> {
+                    mTouchToFillPaymentMethodModel
+                            .get(SHEET_ITEMS)
+                            .add(
+                                    new ListItem(
+                                            CREDIT_CARD,
+                                            createCardSuggestionModel(
+                                                    VIRTUAL_CARD,
+                                                    VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS,
+                                                    new FillableItemCollectionInfo(
+                                                            /* position= */ 1, /* total= */ 1))));
+                    mTouchToFillPaymentMethodModel.set(VISIBLE, true);
+                });
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        assertThat(
+                getSuggestionMainTextAt(0).getText(),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getLabel()));
+        assertThat(
+                getSuggestionMinorTextAt(0).getText(),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getSecondaryLabel()));
+        assertThat(
+                getSuggestionFirstLineLabelAt(0).getText(),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getSublabel()));
+        TextView secondLineLabel = getSuggestionSecondLineLabelAt(0);
+        assertThat(
+                secondLineLabel.getText(),
+                is(VIRTUAL_CARD_SUGGESTION_WITH_CARD_BENEFITS.getSecondarySublabel()));
+        assertContentDescriptionEquals(secondLineLabel, /* position= */ 1, /* total= */ 1);
     }
 
     @Test
@@ -649,7 +736,7 @@
                 getSuggestionMinorTextAt(0).getText(),
                 is(NON_ACCEPTABLE_VIRTUAL_CARD_SUGGESTION.getSecondaryLabel()));
         assertThat(
-                getSuggestionLabelAt(0).getText(),
+                getSuggestionFirstLineLabelAt(0).getText(),
                 is(NON_ACCEPTABLE_VIRTUAL_CARD_SUGGESTION.getSublabel()));
     }
 
@@ -824,8 +911,12 @@
         return getCreditCardSuggestions().getChildAt(index).findViewById(R.id.minor_text);
     }
 
-    private TextView getSuggestionLabelAt(int index) {
-        return getCreditCardSuggestions().getChildAt(index).findViewById(R.id.description_line_2);
+    private TextView getSuggestionFirstLineLabelAt(int index) {
+        return getCreditCardSuggestions().getChildAt(index).findViewById(R.id.first_line_label);
+    }
+
+    private TextView getSuggestionSecondLineLabelAt(int index) {
+        return getCreditCardSuggestions().getChildAt(index).findViewById(R.id.second_line_label);
     }
 
     private @SheetState int getBottomSheetState() {
@@ -852,6 +943,12 @@
                         .with(ITEM_COLLECTION_INFO, collectionInfo)
                         .with(ON_CREDIT_CARD_CLICK_ACTION, actionCallback)
                         .with(APPLY_DEACTIVATED_STYLE, suggestion.applyDeactivatedStyle());
+        if (suggestion.getSecondarySublabel() != null) {
+            creditCardSuggestionModelBuilder.with(
+                    TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties
+                            .SECOND_LINE_LABEL,
+                    suggestion.getSecondarySublabel());
+        }
         if (!card.getBasicCardIssuerNetwork()
                 .equals(card.getCardNameForAutofillDisplay().toLowerCase())) {
             creditCardSuggestionModelBuilder.with(NETWORK_NAME, card.getBasicCardIssuerNetwork());
@@ -877,4 +974,19 @@
                 mock,
                 timeout(ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
     }
+
+    private static void assertContentDescriptionEquals(
+            TextView descriptionLine, int position, int total) {
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+        descriptionLine.onInitializeAccessibilityNodeInfo(info);
+        assertEquals(
+                descriptionLine
+                        .getContext()
+                        .getString(
+                                R.string.autofill_payment_method_a11y_item_collection_info,
+                                descriptionLine.getText(),
+                                position,
+                                total),
+                info.getContentDescription());
+    }
 }
diff --git a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc
index 14c485d6..fb1db74 100644
--- a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc
+++ b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc
@@ -80,12 +80,18 @@
   std::vector<base::android::ScopedJavaLocalRef<jobject>> suggestions_array;
   suggestions_array.reserve(suggestions.size());
   for (const Suggestion& suggestion : suggestions) {
-    CHECK_EQ(suggestion.labels.size(), 1U);
+    CHECK_GT(suggestion.labels.size(), 0U);
     CHECK_EQ(suggestion.labels[0].size(), 1U);
+    std::u16string secondarySubLabel =
+        suggestion.labels.size() > 1 && suggestion.labels[1].size() > 0 &&
+                !suggestion.labels[1][0].value.empty()
+            ? suggestion.labels[1][0].value
+            : u"";
     suggestions_array.push_back(
         Java_TouchToFillPaymentMethodViewBridge_createAutofillSuggestion(
             env, suggestion.main_text.value, suggestion.minor_text.value,
-            suggestion.labels[0][0].value, suggestion.apply_deactivated_style));
+            suggestion.labels[0][0].value, secondarySubLabel,
+            suggestion.apply_deactivated_style));
   }
   Java_TouchToFillPaymentMethodViewBridge_showSheet(
       env, java_object_, std::move(credit_cards_array),
diff --git a/chrome/browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_browsertest.cc b/chrome/browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_browsertest.cc
index 727892ce..5d50e1432 100644
--- a/chrome/browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_browsertest.cc
+++ b/chrome/browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_browsertest.cc
@@ -920,6 +920,51 @@
       1 /*Incognito*/, 1);
 }
 
+IN_PROC_BROWSER_TEST_F(TrustedVaultEncryptionKeysTabHelperBrowserTest,
+                       ShouldNotSetKeysIfCallingFrameIsDeleted_364338802) {
+  const GURL initial_url =
+      https_server()->GetURL("accounts.google.com", "/iframe.html");
+  ASSERT_TRUE(content::NavigateToURL(web_contents(), initial_url));
+
+  const GURL frame_url =
+      https_server()->GetURL("accounts.google.com", "/title1.html");
+  EXPECT_TRUE(NavigateIframeToURL(web_contents(), "test", frame_url));
+  content::RenderFrameHost* child_frame =
+      ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0);
+  ASSERT_TRUE(child_frame);
+
+  // EncryptionKeysApi is created for the child frame as the origin is allowed.
+  ASSERT_TRUE(HasEncryptionKeysApi(child_frame));
+
+  content::WebContentsConsoleObserver console_observer(web_contents());
+  content::RenderFrameDeletedObserver frame_deleted_observer(child_frame);
+
+  // Ensure that deleting the calling frame in the middle of the request doesn't
+  // crash. Keys will not be set successfully.
+  constexpr std::string_view script = R"(
+      var childFrame = document.querySelector("iframe");
+      let trustedVaultKey = new Object();
+      childFrame.contentWindow.Object.defineProperty(
+          trustedVaultKey, "key", { get: () => {
+              document.body.remove(childFrame);
+              return new ArrayBuffer(1);
+      }});
+      trustedVaultKey.key = new ArrayBuffer(1);
+      trustedVaultKey.epoch = 1;
+      childFrame.contentWindow.chrome.setClientEncryptionKeys(
+          () => { console.log("test:OK") },
+          "fake_gaia_id",
+          new Map([['chromesync', [trustedVaultKey]]]));
+    )";
+
+  ASSERT_TRUE(content::ExecJs(web_contents(), script));
+  EXPECT_TRUE(frame_deleted_observer.WaitUntilDeleted());
+  EXPECT_EQ(console_observer.messages().size(), 0u);
+  EXPECT_THAT(FetchTrustedVaultKeysForProfile(
+                  browser()->profile(),
+                  trusted_vault::SecurityDomainId::kChromeSync, FakeAccount()),
+              IsEmpty());
+}
 #endif  // BUILDFLAG(IS_ANDROID)
 
 // Tests that chrome.addTrustedSyncEncryptionRecoveryMethod() works in the main
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 556d5790..2dc0c8d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -977,6 +977,7 @@
       "//chrome/browser/keyboard_accessory/android:public",
       "//chrome/browser/notifications/scheduler/public",
       "//chrome/browser/password_manager/android:utils",
+      "//chrome/browser/password_manager/android/access_loss:public",
       "//chrome/browser/resources/feed_internals:resources",
       "//chrome/browser/touch_to_fill/autofill/android",
       "//chrome/browser/ui/android/autofill/internal:jni_headers",
diff --git a/chrome/browser/ui/android/hats/survey_client_android.cc b/chrome/browser/ui/android/hats/survey_client_android.cc
index 9696f62..fa9f4b5 100644
--- a/chrome/browser/ui/android/hats/survey_client_android.cc
+++ b/chrome/browser/ui/android/hats/survey_client_android.cc
@@ -10,6 +10,7 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
+#include "base/containers/heap_array.h"
 #include "base/ranges/algorithm.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/android/hats/survey_config_android.h"
@@ -58,8 +59,8 @@
   // Parse bit PSDs.
   std::vector<std::string> bits_fields;
   auto bits_values =
-      std::make_unique<bool[]>(product_specific_bits_data.size());
-  int value_iterator = 0;
+      base::HeapArray<bool>::WithSize(product_specific_bits_data.size());
+  size_t value_iterator = 0u;
   base::ranges::for_each(
       product_specific_bits_data.begin(), product_specific_bits_data.end(),
       [&bits_fields, &bits_values,
@@ -70,8 +71,7 @@
   ScopedJavaLocalRef<jobjectArray> jpsd_bits_data_fields =
       base::android::ToJavaArrayOfStrings(env, bits_fields);
   ScopedJavaLocalRef<jbooleanArray> jpsd_bits_data_vals =
-      base::android::ToJavaBooleanArray(env, bits_values.get(),
-                                        bits_fields.size());
+      base::android::ToJavaBooleanArray(env, bits_values);
 
   // Parse string PSDs.
   std::vector<std::string> string_fields;
diff --git a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfCoordinator.java b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfCoordinator.java
index 136eb35b..851aa873 100644
--- a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfCoordinator.java
+++ b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfCoordinator.java
@@ -6,6 +6,7 @@
 
 import android.app.Activity;
 import android.net.Uri;
+import android.os.SystemClock;
 import android.view.LayoutInflater;
 import android.view.View;
 
@@ -75,15 +76,19 @@
         /** Whether the pdf has been loaded successfully. */
         boolean mIsLoadDocumentSuccess;
 
+        /** The timestamp when the pdf document starts to load. */
+        long mDocumentLoadStartTimestamp;
+
         @Override
         public void onLoadDocumentSuccess() {
             mIsLoadDocumentSuccess = true;
-            // TODO: capture metrics
+            PdfUtils.recordPdfLoadTime(SystemClock.elapsedRealtime() - mDocumentLoadStartTimestamp);
+            PdfUtils.recordPdfLoadResult(true);
         }
 
         @Override
         public void onLoadDocumentError(@NonNull Throwable throwable) {
-            // TODO: capture metrics
+            PdfUtils.recordPdfLoadResult(false);
         }
     }
 
@@ -157,6 +162,9 @@
                     transaction.add(mFragmentContainerViewId, mChromePdfViewerFragment);
                     transaction.commitAllowingStateLoss();
                     mFragmentManager.executePendingTransactions();
+                    PdfUtils.recordPdfLoad();
+                    mChromePdfViewerFragment.mDocumentLoadStartTimestamp =
+                            SystemClock.elapsedRealtime();
                     mChromePdfViewerFragment.setDocumentUri(uri);
                 }
             } catch (NullPointerException e) {
diff --git a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
index 0006744c6..227be4f 100644
--- a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
+++ b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
@@ -286,6 +286,18 @@
         }
     }
 
+    static void recordPdfLoad() {
+        RecordHistogram.recordBooleanHistogram("Android.Pdf.DocumentLoad", true);
+    }
+
+    static void recordPdfLoadResult(boolean isLoadSuccess) {
+        RecordHistogram.recordBooleanHistogram("Android.Pdf.DocumentLoadResult", isLoadSuccess);
+    }
+
+    static void recordPdfLoadTime(long duration) {
+        RecordHistogram.recordTimesHistogram("Android.Pdf.DocumentLoadTime", duration);
+    }
+
     private static void recordIsPdfDownloadUrlEncoded(boolean encodeResult) {
         RecordHistogram.recordBooleanHistogram("Android.Pdf.DownloadUrlEncoded", encodeResult);
     }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java
index 96cb5cc..4e65ecd 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java
@@ -164,16 +164,6 @@
         return ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_PAGE_ACTIONS);
     }
 
-    public static boolean isAdaptiveToolbarTranslateEnabled() {
-        return ChromeFeatureList.isEnabled(
-                ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE);
-    }
-
-    public static boolean isAdaptiveToolbarAddToBookmarksEnabled() {
-        return ChromeFeatureList.isEnabled(
-                ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS);
-    }
-
     public static boolean isAdaptiveToolbarPageSummaryEnabled() {
         return ChromeFeatureList.isEnabled(
                 ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_PAGE_SUMMARY);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java
index b0a46240..fca1eb0 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java
@@ -229,10 +229,6 @@
             case AdaptiveToolbarButtonVariant.VOICE:
                 if (mAndroidPermissionDelegate == null) return true;
                 return VoiceRecognitionUtil.isVoiceSearchEnabled(mAndroidPermissionDelegate);
-            case AdaptiveToolbarButtonVariant.TRANSLATE:
-                return AdaptiveToolbarFeatures.isAdaptiveToolbarTranslateEnabled();
-            case AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS:
-                return AdaptiveToolbarFeatures.isAdaptiveToolbarAddToBookmarksEnabled();
             case AdaptiveToolbarButtonVariant.READ_ALOUD:
                 return AdaptiveToolbarFeatures.isAdaptiveToolbarReadAloudEnabled(mProfile);
             case AdaptiveToolbarButtonVariant.PAGE_SUMMARY:
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragment.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragment.java
index aa5a2c7b..7a15983a 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragment.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragment.java
@@ -58,10 +58,6 @@
                 (RadioButtonGroupAdaptiveToolbarPreference)
                         findPreference(PREF_ADAPTIVE_RADIO_GROUP);
         mRadioButtonGroup.setCanUseVoiceSearch(getCanUseVoiceSearch());
-        mRadioButtonGroup.setCanUseTranslate(
-                AdaptiveToolbarFeatures.isAdaptiveToolbarTranslateEnabled());
-        mRadioButtonGroup.setCanUseAddToBookmarks(
-                AdaptiveToolbarFeatures.isAdaptiveToolbarAddToBookmarksEnabled());
         mRadioButtonGroup.setCanUseReadAloud(
                 AdaptiveToolbarFeatures.isAdaptiveToolbarReadAloudEnabled(getProfile()));
         mRadioButtonGroup.setCanUsePageSummary(
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragmentTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragmentTest.java
index 14b536b..0cbe5fc0 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragmentTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarSettingsFragmentTest.java
@@ -59,8 +59,6 @@
 @Config(manifest = Config.NONE)
 @EnableFeatures(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2)
 @DisableFeatures({
-    ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE,
-    ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS,
     ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_PAGE_SUMMARY,
     ChromeFeatureList.READALOUD
 })
@@ -207,141 +205,6 @@
 
     @Test
     @SmallTest
-    @EnableFeatures(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE)
-    public void testTranslateOption_Enabled() {
-        FragmentScenario<AdaptiveToolbarSettingsFragment> scenario = buildFragmentScenario();
-        scenario.onFragment(
-                fragment -> {
-                    mRadioPreference =
-                            (RadioButtonGroupAdaptiveToolbarPreference)
-                                    fragment.findPreference(
-                                            AdaptiveToolbarSettingsFragment
-                                                    .PREF_ADAPTIVE_RADIO_GROUP);
-
-                    // Select Translate.
-                    Assert.assertEquals(
-                            R.id.adaptive_option_translate,
-                            getButton(AdaptiveToolbarButtonVariant.TRANSLATE).getId());
-                    selectButton(AdaptiveToolbarButtonVariant.TRANSLATE);
-                    assertButtonCheckedCorrectly(
-                            "Translate", AdaptiveToolbarButtonVariant.TRANSLATE);
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.TRANSLATE,
-                            mRadioPreference.getSelection());
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.TRANSLATE,
-                            ChromeSharedPreferences.getInstance()
-                                    .readInt(ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS));
-                });
-    }
-
-    @Test
-    @SmallTest
-    @DisableFeatures(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE)
-    public void testTranslateOption_Disabled() {
-        // Set initial preference to translate.
-        ChromeSharedPreferences.getInstance()
-                .writeInt(
-                        ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS,
-                        AdaptiveToolbarButtonVariant.TRANSLATE);
-        FragmentScenario<AdaptiveToolbarSettingsFragment> scenario = buildFragmentScenario();
-        scenario.onFragment(
-                fragment -> {
-                    mRadioPreference =
-                            (RadioButtonGroupAdaptiveToolbarPreference)
-                                    fragment.findPreference(
-                                            AdaptiveToolbarSettingsFragment
-                                                    .PREF_ADAPTIVE_RADIO_GROUP);
-
-                    // Translate option should be hidden, and we should have reverted back to
-                    // "Auto".
-                    Assert.assertEquals(
-                            R.id.adaptive_option_translate,
-                            getButton(AdaptiveToolbarButtonVariant.TRANSLATE).getId());
-                    Assert.assertEquals(
-                            View.GONE,
-                            getButton(AdaptiveToolbarButtonVariant.TRANSLATE).getVisibility());
-                    assertButtonCheckedCorrectly(
-                            "Based on your usage", AdaptiveToolbarButtonVariant.AUTO);
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.AUTO, mRadioPreference.getSelection());
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.AUTO,
-                            ChromeSharedPreferences.getInstance()
-                                    .readInt(ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS));
-                });
-    }
-
-    @Test
-    @SmallTest
-    @EnableFeatures(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS)
-    public void testAddToBookmarksOption_Enabled() {
-        FragmentScenario<AdaptiveToolbarSettingsFragment> scenario = buildFragmentScenario();
-        scenario.onFragment(
-                fragment -> {
-                    mRadioPreference =
-                            (RadioButtonGroupAdaptiveToolbarPreference)
-                                    fragment.findPreference(
-                                            AdaptiveToolbarSettingsFragment
-                                                    .PREF_ADAPTIVE_RADIO_GROUP);
-
-                    // Select Add to bookmarks.
-                    Assert.assertEquals(
-                            R.id.adaptive_option_add_to_bookmarks,
-                            getButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS).getId());
-                    selectButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS);
-                    assertButtonCheckedCorrectly(
-                            "Add to bookmarks", AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS);
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS,
-                            mRadioPreference.getSelection());
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS,
-                            ChromeSharedPreferences.getInstance()
-                                    .readInt(ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS));
-                });
-    }
-
-    @Test
-    @SmallTest
-    @DisableFeatures(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS)
-    public void testAddToBookmarksOption_Disabled() {
-        // Set initial preference to add to bookmarks.
-        ChromeSharedPreferences.getInstance()
-                .writeInt(
-                        ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS,
-                        AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS);
-        FragmentScenario<AdaptiveToolbarSettingsFragment> scenario = buildFragmentScenario();
-        scenario.onFragment(
-                fragment -> {
-                    mRadioPreference =
-                            (RadioButtonGroupAdaptiveToolbarPreference)
-                                    fragment.findPreference(
-                                            AdaptiveToolbarSettingsFragment
-                                                    .PREF_ADAPTIVE_RADIO_GROUP);
-
-                    // Add to bookmarks option should be hidden, and we should have reverted back to
-                    // "Auto".
-                    Assert.assertEquals(
-                            R.id.adaptive_option_add_to_bookmarks,
-                            getButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS).getId());
-                    Assert.assertEquals(
-                            View.GONE,
-                            getButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS)
-                                    .getVisibility());
-                    assertButtonCheckedCorrectly(
-                            "Based on your usage", AdaptiveToolbarButtonVariant.AUTO);
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.AUTO, mRadioPreference.getSelection());
-                    Assert.assertEquals(
-                            AdaptiveToolbarButtonVariant.AUTO,
-                            ChromeSharedPreferences.getInstance()
-                                    .readInt(ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS));
-                });
-    }
-
-    @Test
-    @SmallTest
     @EnableFeatures(ChromeFeatureList.READALOUD)
     public void testReadAloudOption_Enabled() {
         FragmentScenario<AdaptiveToolbarSettingsFragment> scenario = buildFragmentScenario();
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java
index 7fe3fda..bdead2c9 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java
@@ -39,8 +39,6 @@
     private @AdaptiveToolbarButtonVariant int mSelected;
     private @Nullable AdaptiveToolbarStatePredictor mStatePredictor;
     private boolean mCanUseVoiceSearch = true;
-    private boolean mCanUseTranslate;
-    private boolean mCanUseAddToBookmarks;
     private boolean mCanUseReadAloud;
     private boolean mCanUsePageSummary;
 
@@ -104,8 +102,6 @@
                                                     .adaptive_toolbar_button_preference_based_on_your_usage_description,
                                             getButtonString(uiState.autoButtonCaption)));
                     updateVoiceButtonVisibility();
-                    updateTranslateButtonVisibility();
-                    updateAddToBookmarksButtonVisibility();
                     updateReadAloudButtonVisibility();
                     updatePageSummaryButtonVisibility();
                 });
@@ -210,16 +206,6 @@
         updateVoiceButtonVisibility();
     }
 
-    void setCanUseTranslate(boolean canUseTranslate) {
-        mCanUseTranslate = canUseTranslate;
-        updateTranslateButtonVisibility();
-    }
-
-    void setCanUseAddToBookmarks(boolean canUseAddToBookmarks) {
-        mCanUseAddToBookmarks = canUseAddToBookmarks;
-        updateAddToBookmarksButtonVisibility();
-    }
-
     void setCanUseReadAloud(boolean canUseReadAloud) {
         mCanUseReadAloud = canUseReadAloud;
         updateReadAloudButtonVisibility();
@@ -234,14 +220,6 @@
         updateButtonVisibility(mVoiceSearchButton, mCanUseVoiceSearch);
     }
 
-    private void updateTranslateButtonVisibility() {
-        updateButtonVisibility(mTranslateButton, mCanUseTranslate);
-    }
-
-    private void updateAddToBookmarksButtonVisibility() {
-        updateButtonVisibility(mAddToBookmarksButton, mCanUseAddToBookmarks);
-    }
-
     private void updateReadAloudButtonVisibility() {
         updateButtonVisibility(mReadAloudButton, mCanUseReadAloud);
     }
diff --git a/chrome/browser/ui/ash/birch/BUILD.gn b/chrome/browser/ui/ash/birch/BUILD.gn
index adc2f00..f5e4bb7 100644
--- a/chrome/browser/ui/ash/birch/BUILD.gn
+++ b/chrome/browser/ui/ash/birch/BUILD.gn
@@ -128,7 +128,10 @@
 
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
-  sources = [ "birch_browsertest.cc" ]
+  sources = [
+    "birch_browsertest.cc",
+    "birch_coral_provider_browsertest.cc",
+  ]
 
   deps = [
     ":birch",
@@ -141,6 +144,7 @@
     "//chrome/browser/ui/ash",
     "//chrome/browser/ui/ash/main_extra_parts",
     "//chrome/test:test_support",
+    "//chrome/test/base/ash/util:test_support",
     "//components/prefs",
     "//content/test:test_support",
     "//testing/gtest",
diff --git a/chrome/browser/ui/ash/birch/DEPS b/chrome/browser/ui/ash/birch/DEPS
index f7cf8246..1490e7e 100644
--- a/chrome/browser/ui/ash/birch/DEPS
+++ b/chrome/browser/ui/ash/birch/DEPS
@@ -30,3 +30,12 @@
   "+chrome/grit",
   "+chrome/test",
 ]
+
+specific_include_rules = {
+  "birch_coral_provider_browsertest.cc": [
+    "+chrome/browser/apps/platform_apps/app_browsertest_util.h",
+    "+chrome/browser/ash/system_web_apps/system_web_app_manager.h",
+    "+chrome/browser/ui/browser_list.h",
+    "+gmock/gmock.h",
+  ],
+}
diff --git a/chrome/browser/ui/ash/birch/birch_coral_provider_browsertest.cc b/chrome/browser/ui/ash/birch/birch_coral_provider_browsertest.cc
new file mode 100644
index 0000000..0680690
--- /dev/null
+++ b/chrome/browser/ui/ash/birch/birch_coral_provider_browsertest.cc
@@ -0,0 +1,120 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/birch/birch_coral_provider.h"
+
+#include <variant>
+
+#include "ash/birch/birch_model.h"
+#include "ash/constants/ash_features.h"
+#include "ash/constants/ash_pref_names.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/webui/system_apps/public/system_web_app_type.h"
+#include "ash/wm/overview/overview_test_util.h"
+#include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
+#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/test/base/ash/util/ash_test_util.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/test/browser_test.h"
+#include "gmock/gmock.h"
+
+namespace ash {
+
+class BirchCoralProviderTest : public extensions::PlatformAppBrowserTest {
+ public:
+  BirchCoralProviderTest() {
+    scoped_feature_list_.InitWithFeatures(
+        {features::kBirchCoral, features::kTabClusterUI}, {});
+  }
+
+  BirchCoralProviderTest(const BirchCoralProviderTest&) = delete;
+  BirchCoralProviderTest& operator=(const BirchCoralProviderTest&) = delete;
+  ~BirchCoralProviderTest() override = default;
+
+  // extensions::PlatformAppBrowserTest:
+  void SetUpOnMainThread() override {
+    // Enable coral service.
+    Shell::Get()->session_controller()->GetPrimaryUserPrefService()->SetBoolean(
+        prefs::kBirchUseCoral, true);
+
+    ash::SystemWebAppManager::GetForTest(profile())
+        ->InstallSystemAppsForTesting();
+
+    extensions::PlatformAppBrowserTest::SetUpOnMainThread();
+  }
+
+ protected:
+  BirchCoralProvider* GetCoralProvider() const {
+    return static_cast<BirchCoralProvider*>(
+        Shell::Get()->birch_model()->GetCoralProviderForTest());
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Tests that the coral provider collects correct in-session tab and app data.
+IN_PROC_BROWSER_TEST_F(BirchCoralProviderTest, CollectInSessionData) {
+  // Close existing browser windows.
+  CloseAllBrowsers();
+
+  // Create two browsers with different tabs and urls.
+  test::CreateAndShowBrowser(profile(), {GURL("https://examples1.com"),
+                                         GURL("https://examples2.com")});
+  test::CreateAndShowBrowser(profile(), {GURL("https://examples3.com")});
+
+  // Open some SWA windows.
+  test::CreateSystemWebApp(profile(), SystemWebAppType::FILE_MANAGER);
+  test::CreateSystemWebApp(profile(), SystemWebAppType::SETTINGS);
+  test::CreateSystemWebApp(profile(), SystemWebAppType::HELP);
+
+  // Open some PWA windows.
+  test::InstallAndLaunchPWA(profile(), GURL("https://www.youtube.com/"),
+                            /*launch_in_browser=*/false,
+                            /*app_title=*/u"YouTube");
+  test::InstallAndLaunchPWA(profile(), GURL("https://www.gmail.com/"),
+                            /*launch_in_browser=*/false,
+                            /*app_title=*/u"Gmail");
+
+  ash::ToggleOverview();
+  ash::WaitForOverviewEnterAnimation();
+
+  // Check if the collected data as expected.
+  auto* coral_provider = GetCoralProvider();
+  const auto& content_data = coral_provider->request_for_test().content();
+
+  // Extract tab data and app data from content data.
+  std::vector<coral_util::TabData> tab_data;
+  std::vector<coral_util::AppData> app_data;
+  for (const auto& data : content_data) {
+    if (std::holds_alternative<coral_util::TabData>(data)) {
+      tab_data.emplace_back(std::get<coral_util::TabData>(data));
+    } else {
+      app_data.emplace_back(std::get<coral_util::AppData>(data));
+    }
+  }
+
+  // Comparing the collected tab data with the expected tab data.
+  EXPECT_THAT(tab_data,
+              testing::ElementsAreArray(std::vector<coral_util::TabData>{
+                  {.tab_title = "examples1.com", .source = "examples1.com/"},
+                  {.tab_title = "examples2.com", .source = "examples2.com/"},
+                  {.tab_title = "examples3.com", .source = "examples3.com/"}}));
+
+  // Comparing the collected app data with the expected app data in mru order.
+  EXPECT_THAT(
+      app_data,
+      testing::ElementsAreArray(std::vector<coral_util::AppData>{
+          {.app_id = "mgndgikekgjfcpckkfioiadnlibdjbkf", .app_name = "Gmail"},
+          {.app_id = "mgndgikekgjfcpckkfioiadnlibdjbkf", .app_name = "YouTube"},
+          {.app_id = "nbljnnecbjbmifnoehiemkgefbnpoeak", .app_name = "Explore"},
+          {.app_id = "odknhmnlageboeamepcngndbggdpaobj",
+           .app_name = "Settings"},
+          {.app_id = "fkiggjmkendpmbegkagpmagjepfkpmeb",
+           .app_name = "Files"}}));
+}
+
+}  // namespace ash
diff --git a/chrome/browser/ui/ash/desks/BUILD.gn b/chrome/browser/ui/ash/desks/BUILD.gn
index 51dded0..9bbf379 100644
--- a/chrome/browser/ui/ash/desks/BUILD.gn
+++ b/chrome/browser/ui/ash/desks/BUILD.gn
@@ -131,6 +131,7 @@
     "//chrome/browser/ui/ash/system_web_apps",
     "//chrome/browser/web_applications:web_applications_test_support",
     "//chrome/test:test_support",
+    "//chrome/test/base/ash/util:test_support",
     "//chromeos/ui/base",
     "//chromeos/ui/frame",
     "//components/account_id",
diff --git a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
index 907e41a..2eb106b 100644
--- a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
+++ b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
@@ -94,6 +94,7 @@
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
+#include "chrome/test/base/ash/util/ash_test_util.h"
 #include "chrome/test/base/chromeos/ash_browser_test_starter.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -288,54 +289,25 @@
   run_loop.Run();
 }
 
-webapps::AppId CreateSystemWebApp(Profile* profile,
-                                  apps::AppLaunchParams params) {
-  const webapps::AppId app_id = params.app_id;
-  base::RunLoop launch_wait;
-  apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithParams(
-      std::move(params),
-      base::BindLambdaForTesting(
-          [&](apps::LaunchResult&& result) { launch_wait.Quit(); }));
-  launch_wait.Run();
-  return app_id;
-}
-
-// Creates the app launch params for `app_type` for testing.
-apps::AppLaunchParams GetAppLaunchParams(Profile* profile,
-                                         ash::SystemWebAppType app_type) {
-  webapps::AppId app_id = *ash::GetAppIdForSystemWebApp(profile, app_type);
-  return apps::AppLaunchParams(
-      app_id, apps::LaunchContainer::kLaunchContainerWindow,
-      WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest);
-}
-
 webapps::AppId CreateFilesSystemWebApp(Profile* profile) {
-  apps::AppLaunchParams params =
-      GetAppLaunchParams(profile, ash::SystemWebAppType::FILE_MANAGER);
-  return CreateSystemWebApp(profile, std::move(params));
+  return ash::test::CreateSystemWebApp(profile,
+                                       ash::SystemWebAppType::FILE_MANAGER);
 }
 
 webapps::AppId CreateSettingsSystemWebApp(Profile* profile) {
-  apps::AppLaunchParams params =
-      GetAppLaunchParams(profile, ash::SystemWebAppType::SETTINGS);
-  params.restore_id = kSettingsWindowId;
-  return CreateSystemWebApp(profile, std::move(params));
+  return ash::test::CreateSystemWebApp(profile, ash::SystemWebAppType::SETTINGS,
+                                       kSettingsWindowId);
 }
 
 webapps::AppId CreateHelpSystemWebApp(Profile* profile) {
-  apps::AppLaunchParams params =
-      GetAppLaunchParams(profile, ash::SystemWebAppType::HELP);
-  params.restore_id = kHelpWindowId;
-  return CreateSystemWebApp(profile, std::move(params));
+  return ash::test::CreateSystemWebApp(profile, ash::SystemWebAppType::HELP,
+                                       kHelpWindowId);
 }
 
 webapps::AppId CreateOsUrlHandlerSystemWebApp(Profile* profile,
                                               const GURL& override_url) {
-  apps::AppLaunchParams params =
-      GetAppLaunchParams(profile, ash::SystemWebAppType::OS_URL_HANDLER);
-  params.restore_id = kTestWindowId;
-  params.override_url = override_url;
-  return CreateSystemWebApp(profile, std::move(params));
+  return ash::test::CreateOsUrlHandlerSystemWebApp(profile, kTestWindowId,
+                                                   override_url);
 }
 
 void SendKey(ui::KeyboardCode key_code) {
@@ -586,17 +558,9 @@
     LaunchTemplate(desk_template_ptr->uuid());
   }
 
-  Browser* CreateBrowser(
-      const std::vector<GURL>& urls,
-      std::optional<size_t> active_url_index = std::nullopt) {
-    Browser* browser = CreateBrowserImpl(urls, active_url_index);
-    browser->window()->Show();
-    return browser;
-  }
-
   Browser* CreateBrowserWithPinnedTabs(const std::vector<GURL>& urls,
                                        int first_non_pinned_tab_index) {
-    Browser* browser = CreateBrowserImpl(urls, std::nullopt);
+    Browser* browser = ash::test::CreateBrowser(profile(), urls, std::nullopt);
 
     chrome_desks_util::SetBrowserPinnedTabs(first_non_pinned_tab_index,
                                             browser);
@@ -607,30 +571,13 @@
   Browser* CreateBrowserWithTabGroups(
       const std::vector<GURL>& urls,
       const std::vector<tab_groups::TabGroupInfo>& tab_groups) {
-    Browser* browser = CreateBrowserImpl(urls, std::nullopt);
+    Browser* browser = ash::test::CreateBrowser(profile(), urls, std::nullopt);
 
     chrome_desks_util::AttachTabGroupsToBrowserInstance(tab_groups, browser);
     browser->window()->Show();
     return browser;
   }
 
-  Browser* InstallAndLaunchPWA(const GURL& start_url, bool launch_in_browser) {
-    auto web_app_info =
-        web_app::WebAppInstallInfo::CreateWithStartUrlForTesting(start_url);
-    web_app_info->scope = start_url.GetWithoutFilename();
-    if (!launch_in_browser) {
-      web_app_info->user_display_mode =
-          web_app::mojom::UserDisplayMode::kStandalone;
-    }
-    web_app_info->title = u"A Web App";
-    const webapps::AppId app_id =
-        web_app::test::InstallWebApp(profile(), std::move(web_app_info));
-
-    return launch_in_browser
-               ? web_app::LaunchBrowserForWebAppInTab(profile(), app_id)
-               : web_app::LaunchWebAppBrowserAndWait(profile(), app_id);
-  }
-
   // This navigates the browser to a page that will show a close confirmation
   // dialog when closed.
   void SetupBrowserToConfirmClose(Browser* browser) {
@@ -662,30 +609,14 @@
   }
 
  private:
-  Browser* CreateBrowserImpl(const std::vector<GURL>& urls,
-                             std::optional<size_t> active_url_index) {
-    Browser::CreateParams params(Browser::TYPE_NORMAL, profile(),
-                                 /*user_gesture=*/false);
-    Browser* browser = Browser::Create(params);
-    // Create a new tab and make sure the urls have loaded.
-    for (size_t i = 0; i < urls.size(); i++) {
-      content::TestNavigationObserver navigation_observer(urls[i]);
-      navigation_observer.StartWatchingNewWebContents();
-      chrome::AddTabAt(
-          browser, urls[i], /*index=*/-1,
-          /*foreground=*/!active_url_index || active_url_index.value() == i);
-      navigation_observer.Wait();
-    }
-    return browser;
-  }
-
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 // Tests that a browser's urls can be captured correctly in the desk template.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, CaptureBrowserUrlsTest) {
   // Create a new browser and add a few tabs to it.
-  Browser* browser = CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  Browser* browser = ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2)});
   aura::Window* window = browser->window()->GetNativeWindow();
 
   const int32_t browser_window_id =
@@ -1079,8 +1010,8 @@
   // Create a new browser and add a few tabs to it, and specify the active tab
   // index.
   const size_t browser_active_index = 1;
-  Browser* browser = CreateBrowser(
-      {GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)},
+  Browser* browser = ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)},
       /*active_url_index=*/browser_active_index);
 
   // Verify that the active tab is correct.
@@ -1300,14 +1231,16 @@
 
   // Create a new browser and set its bounds.
   std::vector<GURL> browser_urls_1 = {GURL(kExampleUrl1), GURL(kExampleUrl2)};
-  Browser* browser_1 = CreateBrowser(browser_urls_1);
+  Browser* browser_1 =
+      ash::test::CreateAndShowBrowser(profile(), browser_urls_1);
   const gfx::Rect browser_bounds_1 = gfx::Rect(100, 100, 600, 200);
   aura::Window* window_1 = browser_1->window()->GetNativeWindow();
   window_1->SetBounds(browser_bounds_1);
 
   // Create a new minimized browser.
   std::vector<GURL> browser_urls_2 = {GURL(kExampleUrl1)};
-  Browser* browser_2 = CreateBrowser(browser_urls_2);
+  Browser* browser_2 =
+      ash::test::CreateAndShowBrowser(profile(), browser_urls_2);
   const gfx::Rect browser_bounds_2 = gfx::Rect(150, 150, 500, 300);
   aura::Window* window_2 = browser_2->window()->GetNativeWindow();
   window_2->SetBounds(browser_bounds_2);
@@ -1316,7 +1249,8 @@
 
   // Create a new maximized browser.
   std::vector<GURL> browser_urls_3 = {GURL(kExampleUrl2)};
-  Browser* browser_3 = CreateBrowser(browser_urls_3);
+  Browser* browser_3 =
+      ash::test::CreateAndShowBrowser(profile(), browser_urls_3);
   browser_3->window()->Maximize();
 
   EXPECT_EQ(browser_bounds_1, window_1->bounds());
@@ -1355,8 +1289,8 @@
 IN_PROC_BROWSER_TEST_F(DesksClientTest, LaunchTemplateWithPWA) {
   ASSERT_TRUE(DesksClient::Get());
 
-  Browser* pwa_browser =
-      InstallAndLaunchPWA(GURL(kExampleUrl1), /*launch_in_browser=*/false);
+  Browser* pwa_browser = ash::test::InstallAndLaunchPWA(
+      profile(), GURL(kExampleUrl1), /*launch_in_browser=*/false);
   ASSERT_TRUE(pwa_browser->is_type_app());
   aura::Window* pwa_window = pwa_browser->window()->GetNativeWindow();
   const gfx::Rect pwa_bounds(50, 50, 500, 500);
@@ -1403,8 +1337,8 @@
 IN_PROC_BROWSER_TEST_F(DesksClientTest, LaunchTemplateWithMissingPWA) {
   ASSERT_TRUE(DesksClient::Get());
 
-  Browser* pwa_browser =
-      InstallAndLaunchPWA(GURL(kExampleUrl1), /*launch_in_browser=*/false);
+  Browser* pwa_browser = ash::test::InstallAndLaunchPWA(
+      profile(), GURL(kExampleUrl1), /*launch_in_browser=*/false);
   ASSERT_TRUE(pwa_browser->is_type_app());
   aura::Window* pwa_window = pwa_browser->window()->GetNativeWindow();
   const gfx::Rect pwa_bounds(50, 50, 500, 500);
@@ -1449,8 +1383,8 @@
 IN_PROC_BROWSER_TEST_F(DesksClientTest, LaunchTemplateWithOutOfScopeURL) {
   ASSERT_TRUE(DesksClient::Get());
 
-  Browser* pwa_browser =
-      InstallAndLaunchPWA(GURL(kYoutubeUrl), /*launch_in_browser=*/false);
+  Browser* pwa_browser = ash::test::InstallAndLaunchPWA(
+      profile(), GURL(kYoutubeUrl), /*launch_in_browser=*/false);
   ASSERT_TRUE(pwa_browser->is_type_app());
   aura::Window* pwa_window = pwa_browser->window()->GetNativeWindow();
   const std::string* app_name =
@@ -1486,8 +1420,8 @@
 IN_PROC_BROWSER_TEST_F(DesksClientTest, LaunchTemplateWithPWAInBrowser) {
   ASSERT_TRUE(DesksClient::Get());
 
-  Browser* pwa_browser =
-      InstallAndLaunchPWA(GURL(kYoutubeUrl), /*launch_in_browser=*/true);
+  Browser* pwa_browser = ash::test::InstallAndLaunchPWA(
+      profile(), GURL(kYoutubeUrl), /*launch_in_browser=*/true);
   aura::Window* pwa_window = pwa_browser->window()->GetNativeWindow();
   const int32_t pwa_window_id =
       pwa_window->GetProperty(app_restore::kWindowIdKey);
@@ -1587,8 +1521,8 @@
   // Create a new browser and add a few tabs to it, and specify the active tab
   // index.
   const size_t browser_active_index = 1;
-  Browser* browser = CreateBrowser(
-      {GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)},
+  Browser* browser = ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)},
       /*active_url_index=*/browser_active_index);
 
   // Verify that the active tab is correct.
@@ -1639,7 +1573,8 @@
 // Tests that a browser's urls can be captured correctly in the desk template.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, SystemUICaptureBrowserUrlsTest) {
   // Create a new browser and add a few tabs to it.
-  Browser* browser = CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  Browser* browser = ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2)});
   aura::Window* window = browser->window()->GetNativeWindow();
 
   const int32_t browser_window_id =
@@ -2078,14 +2013,16 @@
 IN_PROC_BROWSER_TEST_F(DesksClientTest, SystemUIBrowserWindowRestorationTest) {
   // Create a new browser and set its bounds.
   std::vector<GURL> browser_urls_1 = {GURL(kExampleUrl1), GURL(kExampleUrl2)};
-  Browser* browser_1 = CreateBrowser(browser_urls_1);
+  Browser* browser_1 =
+      ash::test::CreateAndShowBrowser(profile(), browser_urls_1);
   const gfx::Rect browser_bounds_1 = gfx::Rect(100, 100, 600, 200);
   aura::Window* window_1 = browser_1->window()->GetNativeWindow();
   window_1->SetBounds(browser_bounds_1);
 
   // Create a new minimized browser.
   std::vector<GURL> browser_urls_2 = {GURL(kExampleUrl1)};
-  Browser* browser_2 = CreateBrowser(browser_urls_2);
+  Browser* browser_2 =
+      ash::test::CreateAndShowBrowser(profile(), browser_urls_2);
   const gfx::Rect browser_bounds_2 = gfx::Rect(150, 150, 500, 300);
   aura::Window* window_2 = browser_2->window()->GetNativeWindow();
   window_2->SetBounds(browser_bounds_2);
@@ -2094,7 +2031,8 @@
 
   // Create a new maximized browser.
   std::vector<GURL> browser_urls_3 = {GURL(kExampleUrl2)};
-  Browser* browser_3 = CreateBrowser(browser_urls_3);
+  Browser* browser_3 =
+      ash::test::CreateAndShowBrowser(profile(), browser_urls_3);
   browser_3->window()->Maximize();
 
   EXPECT_EQ(browser_bounds_1, window_1->bounds());
@@ -2134,8 +2072,8 @@
 // Tests that saving and launching a template that contains a PWA works as
 // expected.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, SystemUILaunchTemplateWithPWA) {
-  Browser* pwa_browser =
-      InstallAndLaunchPWA(GURL(kExampleUrl1), /*launch_in_browser=*/false);
+  Browser* pwa_browser = ash::test::InstallAndLaunchPWA(
+      profile(), GURL(kExampleUrl1), /*launch_in_browser=*/false);
   ASSERT_TRUE(pwa_browser->is_type_app());
   aura::Window* pwa_window = pwa_browser->window()->GetNativeWindow();
   const gfx::Rect pwa_bounds(50, 50, 500, 500);
@@ -2186,8 +2124,8 @@
 // window works as expected.
 IN_PROC_BROWSER_TEST_F(DesksClientTest,
                        SystemUILaunchTemplateWithPWAInBrowser) {
-  Browser* pwa_browser =
-      InstallAndLaunchPWA(GURL(kYoutubeUrl), /*launch_in_browser=*/true);
+  Browser* pwa_browser = ash::test::InstallAndLaunchPWA(
+      profile(), GURL(kYoutubeUrl), /*launch_in_browser=*/true);
   aura::Window* pwa_window = pwa_browser->window()->GetNativeWindow();
   const int32_t pwa_window_id =
       pwa_window->GetProperty(app_restore::kWindowIdKey);
@@ -2356,8 +2294,10 @@
   CreateFilesSystemWebApp(browser()->profile());
   CreateFilesSystemWebApp(browser()->profile());
 
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)});
+  ash::test::CreateAndShowBrowser(profile(),
+                                  {GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)});
 
   // Save a template.
   ash::ToggleOverview();
@@ -2562,7 +2502,7 @@
   base::HistogramTester histogram_tester;
 
   // Create a new browser.
-  CreateBrowser({});
+  ash::test::CreateAndShowBrowser(profile(), {});
 
   // Save a template.
   ash::ToggleOverview();
@@ -2587,8 +2527,10 @@
   // Create the settings app, which is a system web app.
   CreateSettingsSystemWebApp(browser()->profile());
 
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)});
+  ash::test::CreateAndShowBrowser(profile(),
+                                  {GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)});
 
   // Save and launch a template.
   ash::ToggleOverview();
@@ -2632,7 +2574,7 @@
 
   ash::DeskSwitchAnimationWaiter waiter;
   // Creates a new window.
-  CreateBrowser({});
+  ash::test::CreateAndShowBrowser(profile(), {});
   base::HistogramTester histogram_tester;
   ASSERT_FALSE(DesksClient::Get()->RemoveDesk(
       desk_id, ash::DeskCloseType::kCloseAllWindows));
@@ -2787,7 +2729,7 @@
 // Tests setting first window to show on all desk and then unset it.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, SetWindowProperties) {
   // Create a new browser window.
-  CreateBrowser({});
+  ash::test::CreateAndShowBrowser(profile(), {});
 
   auto* desks_controller = ash::DesksController::Get();
 
@@ -2838,7 +2780,8 @@
 // Tests save an empty desk should fail.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, SaveEmptyDesk) {
   // Create a new browser and add a few tabs to it.
-  Browser* browser = CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  Browser* browser = ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2)});
   aura::Window* window = browser->window()->GetNativeWindow();
 
   const int32_t browser_window_id =
@@ -2866,7 +2809,8 @@
 // Tests save an active desk to library and remove it from desk list.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, SaveActiveDesk) {
   // Create a new browser and add a few tabs to it.
-  Browser* browser = CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  Browser* browser = ash::test::CreateAndShowBrowser(
+      profile(), {GURL(kExampleUrl1), GURL(kExampleUrl2)});
   aura::Window* window = browser->window()->GetNativeWindow();
 
   const int32_t browser_window_id =
@@ -2896,7 +2840,8 @@
   auto* desk_model = DesksClient::Get()->GetDeskModel();
 
   // Create a new browser and add a few tabs to it.
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  ash::test::CreateAndShowBrowser(profile(),
+                                  {GURL(kExampleUrl1), GURL(kExampleUrl2)});
 
   std::unique_ptr<ash::DeskTemplate> desk_template =
       CaptureActiveDeskAndSaveTemplate(ash::DeskTemplateType::kSaveAndRecall);
@@ -2913,7 +2858,8 @@
   EXPECT_EQ(ash::DesksController::Get()->GetNumberOfDesks(), 1);
 
   // Create a new browser and add a few tabs to it.
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  ash::test::CreateAndShowBrowser(profile(),
+                                  {GURL(kExampleUrl1), GURL(kExampleUrl2)});
 
   std::unique_ptr<ash::DeskTemplate> desk_template =
       CaptureActiveDeskAndSaveTemplate(ash::DeskTemplateType::kSaveAndRecall);
@@ -2922,7 +2868,8 @@
   EXPECT_EQ(ash::DesksController::Get()->GetNumberOfDesks(), 1);
 
   // Restart browser process.
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  ash::test::CreateAndShowBrowser(profile(),
+                                  {GURL(kExampleUrl1), GURL(kExampleUrl2)});
   base::RunLoop loop;
   DesksClient::Get()->LaunchDeskTemplate(
       desk_template->uuid(),
@@ -2999,7 +2946,8 @@
 // for saved desks functionality.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, FloatingWorkspaceOnSavedDesksUI) {
   // Create a new browser and add a few tabs to it.
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
+  ash::test::CreateAndShowBrowser(profile(),
+                                  {GURL(kExampleUrl1), GURL(kExampleUrl2)});
   std::unique_ptr<ash::DeskTemplate> desk_template =
       CaptureActiveDeskAndSaveTemplate(
           ash::DeskTemplateType::kFloatingWorkspace);
@@ -3390,7 +3338,8 @@
 
 IN_PROC_BROWSER_TEST_F(SnapGroupDesksClientTest, DesksTemplates) {
   // Create 1 other window to create a snap group.
-  Browser* browser2 = CreateBrowser({GURL(kExampleUrl2)});
+  Browser* browser2 =
+      ash::test::CreateAndShowBrowser(profile(), {GURL(kExampleUrl2)});
   aura::Window* w1 = browser()->window()->GetNativeWindow();
   aura::Window* w2 = browser2->window()->GetNativeWindow();
 
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
index 5c799f7..492eb3e 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
@@ -18,6 +18,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
+#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
 #include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h"
@@ -34,6 +35,7 @@
 #include "components/autofill/core/browser/ui/suggestion_hiding_reason.h"
 #include "components/autofill/core/browser/ui/suggestion_type.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "components/password_manager/core/browser/features/password_features.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/strings/grit/components_strings.h"
@@ -284,8 +286,28 @@
   delegate_->DidAcceptSuggestion(
       suggestion, AutofillSuggestionDelegate::SuggestionMetadata{.row = index});
 
-  if (suggestion.type == SuggestionType::kPasswordEntry &&
-      base::FeatureList::IsEnabled(
+  if (suggestion.type != SuggestionType::kPasswordEntry) {
+    // Returning early because the code below triggers the UI which is shown
+    // after accepting passwords.
+    return;
+  }
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::
+              kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning)) {
+    Profile* profile =
+        Profile::FromBrowserContext(web_contents_->GetBrowserContext());
+    if (!access_loss_warning_bridge_) {
+      access_loss_warning_bridge_ =
+          std::make_unique<PasswordAccessLossWarningBridgeImpl>();
+    }
+    if (profile && access_loss_warning_bridge_->ShouldShowAccessLossNoticeSheet(
+                       profile->GetPrefs())) {
+      access_loss_warning_bridge_->MaybeShowAccessLossNoticeSheet(
+          profile->GetPrefs(), web_contents_->GetTopLevelNativeWindow(),
+          profile);
+    }
+  }
+  if (base::FeatureList::IsEnabled(
           password_manager::features::
               kUnifiedPasswordManagerLocalPasswordsMigrationWarning)) {
     show_pwd_migration_warning_callback_.Run(
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
index 5d62fb78..ac40710a 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h"
 #include "chrome/browser/ui/autofill/autofill_popup_hide_helper.h"
 #include "chrome/browser/ui/autofill/next_idle_barrier.h"
@@ -172,6 +173,10 @@
   // `FillingProduct` is.
   FillingProduct suggestions_filling_product_ = FillingProduct::kNone;
 
+  // Bridge used to show the data loss warning (expected to be shown after
+  // filling user's credentials).
+  std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge_;
+
   base::WeakPtrFactory<AutofillKeyboardAccessoryControllerImpl>
       self_deletion_weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h
index f8011a6..e7ca5b1b 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_IMPL_TEST_API_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_IMPL_TEST_API_H_
 
+#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
@@ -39,6 +40,15 @@
     return controller_->view_.get();
   }
 
+  void SetAccessLossWarningBridge(
+      std::unique_ptr<PasswordAccessLossWarningBridge> bridge) {
+    controller_->access_loss_warning_bridge_ = std::move(bridge);
+  }
+
+  PasswordAccessLossWarningBridge* access_loss_warning_bridge() {
+    return controller_->access_loss_warning_bridge_.get();
+  }
+
  private:
   const raw_ref<AutofillKeyboardAccessoryControllerImpl> controller_;
 };
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
index 52bf656..c041965 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h"
 #include "components/autofill/core/browser/address_data_manager.h"
 #include "components/autofill/core/browser/ui/suggestion_hiding_reason.h"
+#include "components/password_manager/core/browser/features/password_features.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -318,7 +319,7 @@
   ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
 
   // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
   EXPECT_CALL(client().show_pwd_migration_warning_callback(),
               Run(_, _,
                   password_manager::metrics_util::
@@ -335,7 +336,7 @@
   ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
 
   // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
   EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run);
   task_environment()->FastForwardBy(base::Milliseconds(500));
   client().popup_controller(manager()).AcceptSuggestion(0);
@@ -350,7 +351,7 @@
   ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
 
   // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
   EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run).Times(0);
   task_environment()->FastForwardBy(base::Milliseconds(500));
   client().popup_controller(manager()).AcceptSuggestion(0);
@@ -364,12 +365,91 @@
   ShowSuggestions(manager(), {SuggestionType::kAddressEntry});
 
   // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
   EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run).Times(0);
   task_environment()->FastForwardBy(base::Milliseconds(500));
   client().popup_controller(manager()).AcceptSuggestion(0);
 }
 
+TEST_F(AutofillKeyboardAccessoryControllerImplTest,
+       AcceptPwdSuggestionInvokesAccessLossWarningAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning);
+  ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
+  EXPECT_CALL(*client().access_loss_warning_bridge(),
+              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs()))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(
+      *client().access_loss_warning_bridge(),
+      MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile()));
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
+TEST_F(AutofillKeyboardAccessoryControllerImplTest,
+       AcceptUsernameSuggestionInvokesAccessLossWarningAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning);
+  ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
+  EXPECT_CALL(*client().access_loss_warning_bridge(),
+              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs()))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(
+      *client().access_loss_warning_bridge(),
+      MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile()));
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
+TEST_F(AutofillKeyboardAccessoryControllerImplTest,
+       AcceptPwdSuggestionNoAccessLossWarningIfDisabledAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning);
+  ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
+  EXPECT_CALL(*client().access_loss_warning_bridge(),
+              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs()))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(
+      *client().access_loss_warning_bridge(),
+      MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile()))
+      .Times(0);
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
+TEST_F(AutofillKeyboardAccessoryControllerImplTest,
+       AcceptAddressNoPwdAccessLossWarningAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning);
+  ShowSuggestions(manager(), {SuggestionType::kAddressEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
+  EXPECT_CALL(*client().access_loss_warning_bridge(),
+              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs()))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(
+      *client().access_loss_warning_bridge(),
+      MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile()))
+      .Times(0);
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
 // When a suggestion is accepted, the popup is hidden inside
 // `delegate->DidAcceptSuggestion()`. On Android, some code is still being
 // executed after hiding. This test makes sure no use-after-free, null pointer
diff --git a/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h b/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h
index 5b99e87..f5fd35e 100644
--- a/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h
+++ b/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/test/mock_callback.h"
+#include "chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h"
@@ -50,6 +51,9 @@
               ->GetWeakPtr();
       test_api(cast_popup_controller())
           .SetView(std::make_unique<MockAutofillKeyboardAccessoryView>());
+      test_api(cast_popup_controller())
+          .SetAccessLossWarningBridge(
+              std::make_unique<MockPasswordAccessLossWarningBridge>());
       manager_of_last_controller_ = manager.GetWeakPtr();
       ON_CALL(cast_popup_controller(), Hide)
           .WillByDefault(
@@ -69,6 +73,14 @@
     return show_pwd_migration_warning_callback_;
   }
 
+  MockPasswordAccessLossWarningBridge* access_loss_warning_bridge() {
+    return popup_controller_
+               ? static_cast<MockPasswordAccessLossWarningBridge*>(
+                     test_api(cast_popup_controller())
+                         .access_loss_warning_bridge())
+               : nullptr;
+  }
+
  private:
   void DoHide(SuggestionHidingReason reason) {
     if (popup_controller_) {
diff --git a/chrome/browser/ui/managed_ui.cc b/chrome/browser/ui/managed_ui.cc
index c59b64e..ba53640 100644
--- a/chrome/browser/ui/managed_ui.cc
+++ b/chrome/browser/ui/managed_ui.cc
@@ -437,8 +437,10 @@
 #else
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
   std::string custom_management_label =
-      g_browser_process->local_state()->GetString(
-          prefs::kEnterpriseCustomLabel);
+      g_browser_process->local_state()
+          ? g_browser_process->local_state()->GetString(
+                prefs::kEnterpriseCustomLabel)
+          : std::string();
   if (!custom_management_label.empty()) {
     return custom_management_label;
   }
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc
index c28029a..4d20493 100644
--- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc
+++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller_delegate.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "components/send_tab_to_self/metrics_util.h"
 #include "components/send_tab_to_self/send_tab_to_self_entry.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
@@ -28,24 +29,40 @@
   // TODO(crbug.com/40180897): Any entries that were never shown are lost.
   // This is consistent with current behavior and we don't have UI for
   // showing multiple entries with this iteration.
-  if (new_entries.empty())
-    return;
-
-  if (GetActiveDelegate()) {
-    ShowToolbarButton(*new_entries.at(0));
+  if (new_entries.empty()) {
     return;
   }
 
-  const bool had_entry_pending_notification = entry_ != nullptr;
-
   // Select semi-randomly the first new entry from the list because there is no
   // UI to show multiple entries.
-  const SendTabToSelfEntry* new_entry_pending_notification =
-      new_entries.front();
+  const SendTabToSelfEntry* new_entry = new_entries.front();
 
-  // |entry_| might already be set, but it's better to overwrite it with a
-  // fresher value.
-  entry_ = std::make_unique<SendTabToSelfEntry>(
+  // If the active browser matches `profile_`, show the toolbar icon.
+  // Otherwise, we will store this entry and wait to show on the next active
+  // appropriate browser.
+  if (features::IsToolbarPinningEnabled()) {
+    auto* browser = chrome::FindLastActiveWithProfile(profile_);
+    if (browser && browser->IsActive()) {
+      ShowToolbarButton(*new_entry);
+      return;
+    }
+  } else {
+    if (GetActiveDelegate()) {
+      ShowToolbarButton(*new_entry);
+      return;
+    }
+  }
+
+  StorePendingEntry(new_entry);
+}
+
+void SendTabToSelfToolbarIconController::StorePendingEntry(
+    const SendTabToSelfEntry* new_entry_pending_notification) {
+  const bool had_entry_pending_notification = pending_entry_ != nullptr;
+
+  // |pending_entry_| might already be set, but it's better to overwrite
+  // it with a fresher value.
+  pending_entry_ = std::make_unique<SendTabToSelfEntry>(
       new_entry_pending_notification->GetGUID(),
       new_entry_pending_notification->GetURL(),
       new_entry_pending_notification->GetTitle(),
@@ -56,8 +73,9 @@
   // Prevent adding the observer several times. This might happen when the
   // window is inactive and this method is called more than once (i.e. the
   // server sends multiple entry batches).
-  if (!had_entry_pending_notification)
+  if (!had_entry_pending_notification) {
     BrowserList::AddObserver(this);
+  }
 }
 
 void SendTabToSelfToolbarIconController::DismissEntries(
@@ -71,19 +89,33 @@
 
 void SendTabToSelfToolbarIconController::OnBrowserSetLastActive(
     Browser* browser) {
-  if (!GetActiveDelegate())
-    return;
+  if (features::IsToolbarPinningEnabled()) {
+    if (!GetActiveDelegate() || browser->profile() != profile_.get()) {
+      return;
+    }
+  } else {
+    if (!GetActiveDelegate()) {
+      return;
+    }
+  }
   BrowserList::RemoveObserver(this);
 
-  // Reset |entry_| because it's used to determine if the BrowserListObserver is
-  // added in DisplayNewEntries().
-  std::unique_ptr<SendTabToSelfEntry> entry = std::move(entry_);
+  // Reset |pending_entry_| because it's used to determine if the
+  // BrowserListObserver is added in `DisplayNewEntries()`.
+  std::unique_ptr<SendTabToSelfEntry> entry = std::move(pending_entry_);
 
-  if (!profile_ || !entry)
+  if (!profile_ || !entry) {
     return;
-  if (browser == chrome::FindBrowserWithProfile(profile_)) {
+  }
+
+  if (features::IsToolbarPinningEnabled()) {
     ShowToolbarButton(*entry);
-    entry_ = nullptr;
+    pending_entry_ = nullptr;
+  } else {
+    if (browser == chrome::FindBrowserWithProfile(profile_)) {
+      ShowToolbarButton(*entry);
+      pending_entry_ = nullptr;
+    }
   }
 }
 
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.h b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.h
index b4a9db91..f81267b 100644
--- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.h
+++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.h
@@ -51,10 +51,18 @@
 
   void LogNotificationDismissed();
 
+  void ClearDelegateListForTesting() { delegate_list_.clear(); }
+
  private:
+  void StorePendingEntry(
+      const SendTabToSelfEntry* new_entry_pending_notification);
+
   raw_ptr<Profile, DanglingUntriaged> profile_;
 
-  std::unique_ptr<SendTabToSelfEntry> entry_;
+  // In the case that we cannot immediately display a new entry
+  // (e.g. the active browser is incognito or a different profile), we store it
+  // here and wait until an appropriate browser becomes active to display it.
+  std::unique_ptr<SendTabToSelfEntry> pending_entry_;
 
   std::vector<raw_ptr<SendTabToSelfToolbarIconControllerDelegate>>
       delegate_list_;
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller_browsertest.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller_browsertest.cc
new file mode 100644
index 0000000..0218ed4
--- /dev/null
+++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller_browsertest.cc
@@ -0,0 +1,98 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.h"
+
+#include "chrome/browser/send_tab_to_self/receiving_ui_handler_registry.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller_delegate.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_icon_view.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/send_tab_to_self/send_tab_to_self_entry.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ozone_buildflags.h"
+
+namespace send_tab_to_self {
+
+namespace {
+
+class MockSendTabToSelfToolbarIconView : public SendTabToSelfToolbarIconView {
+ public:
+  explicit MockSendTabToSelfToolbarIconView(BrowserView* browser_view)
+      : SendTabToSelfToolbarIconView(browser_view) {}
+
+  MOCK_METHOD(void, Show, (const SendTabToSelfEntry& entry), (override));
+};
+
+}  // namespace
+
+class SendTabToSelfToolbarIconControllerTest : public InProcessBrowserTest {
+ public:
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+    controller()->ClearDelegateListForTesting();
+  }
+
+  void WaitUntilBrowserBecomeActiveOrLastActive(Browser* browser) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+    ui_test_utils::WaitUntilBrowserBecomeActive(browser);
+#else
+    ui_test_utils::WaitForBrowserSetLastActive(browser);
+#endif
+  }
+
+  BrowserView* browser_view() {
+    return BrowserView::GetBrowserViewForBrowser(browser());
+  }
+
+  SendTabToSelfToolbarIconController* controller() {
+    return send_tab_to_self::ReceivingUiHandlerRegistry::GetInstance()
+        ->GetToolbarButtonControllerForProfile(browser()->profile());
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(SendTabToSelfToolbarIconControllerTest,
+                       DisplayNewEntry) {
+  MockSendTabToSelfToolbarIconView mock_icon(browser_view());
+  ASSERT_TRUE(browser()->IsActive());
+
+  SendTabToSelfEntry entry("a", GURL("http://www.example-a.com"), "a site",
+                           base::Time(), "device a", "device b");
+
+  EXPECT_CALL(mock_icon, Show(testing::_)).Times(1);
+  controller()->DisplayNewEntries({&entry});
+}
+
+// This test cannot work on Wayland because the platform does not allow clients
+// to position top level windows, activate them, and set focus.
+#if !(BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_OZONE_WAYLAND))
+IN_PROC_BROWSER_TEST_F(SendTabToSelfToolbarIconControllerTest,
+                       StorePendingNewEntry) {
+  MockSendTabToSelfToolbarIconView mock_icon(browser_view());
+  ASSERT_TRUE(browser()->IsActive());
+
+  Browser* incognito_browser = CreateIncognitoBrowser();
+  WaitUntilBrowserBecomeActiveOrLastActive(incognito_browser);
+
+  SendTabToSelfEntry entry("a", GURL("http://www.example-a.com"), "a site",
+                           base::Time(), "device a", "device b");
+
+  EXPECT_CALL(mock_icon, Show(testing::_)).Times(0);
+  EXPECT_FALSE(browser()->IsActive());
+  controller()->DisplayNewEntries({&entry});
+
+  EXPECT_CALL(mock_icon, Show(testing::_)).Times(1);
+  browser_view()->Activate();
+  WaitUntilBrowserBecomeActiveOrLastActive(browser());
+}
+#endif
+
+}  // namespace send_tab_to_self
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
index dc69b72..4077670 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
@@ -324,7 +324,6 @@
                         saved_group.local_group_id().value());
 
   std::map<content::WebContents*, base::Uuid> contents_guid_mapping;
-
   std::transform(
       tab_guid_mapping.begin(), tab_guid_mapping.end(),
       std::inserter(contents_guid_mapping, contents_guid_mapping.end()),
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
index efed03ce..17cf3cb 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
@@ -63,16 +63,27 @@
     return;
   }
 
-  auto group_web_contents_map_pair = CreateSavedTabGroupAndTabMapping(group_id);
+  auto group_and_tab_guid_mapping = CreateSavedTabGroupAndTabMapping(group_id);
 
-  SavedTabGroup copy_group = group_web_contents_map_pair.first;
-  std::map<content::WebContents*, base::Uuid> copy_web_contents_to_uuid_map =
-      group_web_contents_map_pair.second;
+  SavedTabGroup copy_group = group_and_tab_guid_mapping.first;
+  std::map<tabs::TabModel*, base::Uuid>& tab_guid_mapping =
+      group_and_tab_guid_mapping.second;
   service_->AddGroup(std::move(copy_group));
 
+  std::map<content::WebContents*, base::Uuid> contents_guid_mapping;
+  std::transform(
+      tab_guid_mapping.begin(), tab_guid_mapping.end(),
+      std::inserter(contents_guid_mapping, contents_guid_mapping.end()),
+      [](const std::pair<tabs::TabModel*, base::Uuid>& pair) {
+        // Transform the TabModel* to WebContents*
+        content::WebContents* web_contents = pair.first->contents();
+
+        // Return a pair with the transformed key and the same UUID value
+        return std::make_pair(web_contents, pair.second);
+      });
+
   std::optional<SavedTabGroup> group = service_->GetGroup(group_id);
-  ConnectToLocalTabGroup(group.value(),
-                         std::move(copy_web_contents_to_uuid_map));
+  ConnectToLocalTabGroup(group.value(), std::move(contents_guid_mapping));
 }
 
 void SavedTabGroupModelListener::OnTabGroupWillBeRemoved(
@@ -330,7 +341,7 @@
   browser->tab_strip_model()->RemoveObserver(this);
 }
 
-std::pair<SavedTabGroup, std::map<content::WebContents*, base::Uuid>>
+std::pair<SavedTabGroup, std::map<tabs::TabModel*, base::Uuid>>
 SavedTabGroupModelListener::CreateSavedTabGroupAndTabMapping(
     const tab_groups::TabGroupId& group_id) {
   Browser* browser =
@@ -350,22 +361,20 @@
           profile_));
 
   const gfx::Range tab_range = tab_group->ListTabs();
-  std::map<content::WebContents*, base::Uuid> opened_web_contents_to_uuid;
+  std::map<tabs::TabModel*, base::Uuid> tab_guid_mapping;
   for (auto i = tab_range.start(); i < tab_range.end(); ++i) {
-    content::WebContents* web_contents = tab_strip_model->GetWebContentsAt(i);
-    CHECK(web_contents);
+    tabs::TabModel* tab = tab_strip_model->GetTabAtIndex(i);
+    CHECK(tab);
 
     tab_groups::SavedTabGroupTab saved_tab_group_tab =
         tab_groups::SavedTabGroupUtils::CreateSavedTabGroupTabFromWebContents(
-            web_contents, saved_tab_group.saved_guid());
+            tab->contents(), saved_tab_group.saved_guid());
 
-    opened_web_contents_to_uuid.emplace(web_contents,
-                                        saved_tab_group_tab.saved_tab_guid());
+    tab_guid_mapping.emplace(tab, saved_tab_group_tab.saved_tab_guid());
     saved_tab_group.AddTabLocally(std::move(saved_tab_group_tab));
   }
 
-  return std::pair(std::move(saved_tab_group),
-                   std::move(opened_web_contents_to_uuid));
+  return std::pair(std::move(saved_tab_group), std::move(tab_guid_mapping));
 }
 
 }  // namespace tab_groups
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
index a183e027..f83e526f 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
@@ -107,7 +107,7 @@
   // group to their saved tab guid. This mapping will be used in
   // ConnectToLocalTabGroup in order to observe any changes to the tabs over
   // time.
-  std::pair<SavedTabGroup, std::map<content::WebContents*, base::Uuid>>
+  std::pair<SavedTabGroup, std::map<tabs::TabModel*, base::Uuid>>
   CreateSavedTabGroupAndTabMapping(const tab_groups::TabGroupId& group_id);
 
   // The LocalTabGroupListeners for each saved tab group that's currently open.
diff --git a/chrome/browser/ui/toasts/BUILD.gn b/chrome/browser/ui/toasts/BUILD.gn
index d6e6017d..65e161b 100644
--- a/chrome/browser/ui/toasts/BUILD.gn
+++ b/chrome/browser/ui/toasts/BUILD.gn
@@ -40,6 +40,7 @@
     "//chrome/browser/ui/views/side_panel",
     "//components/vector_icons:vector_icons",
     "//ui/base/metadata",
+    "//ui/compositor",
   ]
 }
 
diff --git a/chrome/browser/ui/toasts/toast_controller.cc b/chrome/browser/ui/toasts/toast_controller.cc
index 485c1ee7d..1350fd9 100644
--- a/chrome/browser/ui/toasts/toast_controller.cc
+++ b/chrome/browser/ui/toasts/toast_controller.cc
@@ -153,8 +153,9 @@
   views::Widget* const toast_widget =
       views::BubbleDialogDelegateView::CreateBubble(std::move(toast));
   toast_observer_.Observe(toast_widget);
+  toast_widget->SetVisibilityChangedAnimationsEnabled(false);
   toast_widget->ShowInactive();
-  // TODO(crbug.com/358615317): Make the toast animate in.
+  toast_->AnimateIn();
 }
 
 std::u16string ToastController::FormatString(
diff --git a/chrome/browser/ui/toasts/toast_view.cc b/chrome/browser/ui/toasts/toast_view.cc
index c14a1a6a7..3257dd6 100644
--- a/chrome/browser/ui/toasts/toast_view.cc
+++ b/chrome/browser/ui/toasts/toast_view.cc
@@ -14,14 +14,32 @@
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/compositor/layer.h"
 #include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/animation/animation_builder.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_client_view.h"
 #include "ui/views/window/dialog_delegate.h"
 
+namespace {
+constexpr int kAnimationEntryDuration = 300;
+constexpr int kAnimationExitDuration = 150;
+constexpr int kAnimationHeightOffset = 50;
+constexpr float kAnimationHeightScale = 0.5;
+
+gfx::Transform GetScaleTransformation(gfx::Rect bounds) {
+  gfx::Transform transform;
+  transform.Translate(0,
+                      bounds.CenterPoint().y() * (1 - kAnimationHeightScale));
+  transform.Scale(1, kAnimationHeightScale);
+  return transform;
+}
+}  // namespace
+
 namespace toasts {
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ToastView, kToastViewId);
 
@@ -30,6 +48,7 @@
                      const gfx::VectorIcon& icon,
                      bool has_close_button)
     : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::NONE),
+      AnimationDelegateViews(this),
       toast_text_(toast_text),
       icon_(icon),
       has_close_button_(has_close_button) {
@@ -125,6 +144,49 @@
       total_vertical_margins - top_margin, right_margin));
 }
 
+void ToastView::AnimationProgressed(const gfx::Animation* animation) {
+  const double value = gfx::Tween::CalculateValue(
+      height_animation_tween_, height_animation_.GetCurrentValue());
+  const gfx::Rect current_bounds = gfx::Tween::RectValueBetween(
+      value, starting_widget_bounds_, target_widget_bounds_);
+  GetWidget()->SetBounds(current_bounds);
+}
+
+void ToastView::AnimateIn() {
+  if (!gfx::Animation::ShouldRenderRichAnimation()) {
+    return;
+  }
+
+  target_widget_bounds_ = GetWidget()->GetWindowBoundsInScreen();
+  starting_widget_bounds_ =
+      target_widget_bounds_ - gfx::Vector2d{0, kAnimationHeightOffset};
+  height_animation_tween_ = gfx::Tween::ACCEL_5_70_DECEL_90;
+  height_animation_.SetDuration(base::Milliseconds(kAnimationEntryDuration));
+  height_animation_.Start();
+
+  views::View* const bubble_frame_view = GetBubbleFrameView();
+  bubble_frame_view->SetPaintToLayer();
+  bubble_frame_view->layer()->SetFillsBoundsOpaquely(false);
+  bubble_frame_view->SetTransform(
+      GetScaleTransformation(bubble_frame_view->bounds()));
+  bubble_frame_view->layer()->SetOpacity(0);
+  GetDialogClientView()->SetBackground(
+      views::CreateThemedSolidBackground(ui::kColorToastBackground));
+  GetDialogClientView()->SetPaintToLayer();
+  GetDialogClientView()->layer()->SetOpacity(0);
+  views::AnimationBuilder()
+      .Once()
+      .SetDuration(base::Milliseconds(kAnimationEntryDuration))
+      .SetTransform(bubble_frame_view, gfx::Transform(),
+                    height_animation_tween_)
+      .At(base::TimeDelta())
+      .SetDuration(base::Milliseconds(50))
+      .SetOpacity(bubble_frame_view, 1)
+      .Then()
+      .SetDuration(base::Milliseconds(150))
+      .SetOpacity(GetDialogClientView(), 1);
+}
+
 void ToastView::Close(ToastCloseReason reason) {
   // TODO(crbug.com/358610872): Log toast close reason metric.
   views::Widget::ClosedReason widget_closed_reason =
@@ -139,8 +201,10 @@
     default:
       break;
   }
-  // TODO(crbug.com/358615317): Make the toast animate out.
-  GetWidget()->CloseWithReason(widget_closed_reason);
+  AnimateOut(
+      base::BindOnce(&views::Widget::CloseWithReason,
+                     base::Unretained(GetWidget()), widget_closed_reason),
+      reason != ToastCloseReason::kPreempted);
 }
 
 gfx::Rect ToastView::GetBubbleBounds() {
@@ -173,6 +237,41 @@
   return toast_text_;
 }
 
+void ToastView::AnimateOut(base::OnceClosure callback,
+                           bool show_height_animation) {
+  if (!gfx::Animation::ShouldRenderRichAnimation()) {
+    std::move(callback).Run();
+    return;
+  }
+
+  views::View* const bubble_frame_view = GetBubbleFrameView();
+
+  if (show_height_animation) {
+    starting_widget_bounds_ = GetWidget()->GetWindowBoundsInScreen();
+    target_widget_bounds_ =
+        starting_widget_bounds_ - gfx::Vector2d{0, kAnimationHeightOffset};
+    height_animation_tween_ = gfx::Tween::ACCEL_30_DECEL_20_85;
+    height_animation_.SetDuration(base::Milliseconds(kAnimationExitDuration));
+    height_animation_.Start();
+
+    views::AnimationBuilder()
+        .Once()
+        .SetDuration(base::Milliseconds(kAnimationExitDuration))
+        .SetTransform(bubble_frame_view,
+                      GetScaleTransformation(bubble_frame_view->bounds()),
+                      height_animation_tween_);
+  }
+
+  views::AnimationBuilder()
+      .OnEnded(std::move(callback))
+      .Once()
+      .SetDuration(base::Milliseconds(100))
+      .SetOpacity(GetDialogClientView(), 0)
+      .Then()
+      .SetDuration(base::Milliseconds(50))
+      .SetOpacity(bubble_frame_view, 0);
+}
+
 BEGIN_METADATA(ToastView)
 END_METADATA
 
diff --git a/chrome/browser/ui/toasts/toast_view.h b/chrome/browser/ui/toasts/toast_view.h
index 47d1340c..ddb50187 100644
--- a/chrome/browser/ui/toasts/toast_view.h
+++ b/chrome/browser/ui/toasts/toast_view.h
@@ -32,7 +32,8 @@
 };
 
 // The view for toasts.
-class ToastView : public views::BubbleDialogDelegateView {
+class ToastView : public views::BubbleDialogDelegateView,
+                  public views::AnimationDelegateViews {
   METADATA_HEADER(ToastView, views::BubbleDialogDelegateView)
 
  public:
@@ -52,6 +53,11 @@
   // views::BubbleDialogDelegateView:
   void Init() override;
 
+  // AnimationDelegateViews:
+  void AnimationProgressed(const gfx::Animation* animation) override;
+
+  void AnimateIn();
+
   // Animates out the toast, then closes the toast widget.
   void Close(ToastCloseReason close_reason);
 
@@ -66,6 +72,13 @@
   std::u16string GetAccessibleWindowTitle() const override;
 
  private:
+  void AnimateOut(base::OnceClosure callback, bool show_height_animation);
+
+  gfx::LinearAnimation height_animation_{this};
+  gfx::Rect starting_widget_bounds_;
+  gfx::Rect target_widget_bounds_;
+  gfx::Tween::Type height_animation_tween_;
+
   const std::u16string toast_text_;
   const raw_ref<const gfx::VectorIcon> icon_;
   const bool has_close_button_;
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index bd59450..57fb7d5 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -869,6 +869,19 @@
 // - Developer tools.
 // - Option to enable profiling.
 void ToolsMenuModel::Build(Browser* browser) {
+  if (base::FeatureList::IsEnabled(features::kTabOrganizationAppMenuItem) &&
+      TabOrganizationUtils::GetInstance()->IsEnabled(browser->profile())) {
+    auto* const tab_organization_service =
+        TabOrganizationServiceFactory::GetForProfile(browser->profile());
+    if (tab_organization_service) {
+      AddItemWithStringIdAndVectorIcon(
+          this, IDC_ORGANIZE_TABS, IDS_TAB_ORGANIZE_MENU, kAutoTabGroupsIcon);
+      SetIsNewFeatureAt(
+          GetIndexOfCommandId(IDC_ORGANIZE_TABS).value(),
+          browser->window()->MaybeShowNewBadgeFor(features::kTabOrganization));
+    }
+  }
+
   AddItemWithStringIdAndVectorIcon(this, IDC_NAME_WINDOW, IDS_NAME_WINDOW,
                                    kNameWindowIcon);
 
@@ -1876,18 +1889,6 @@
         kShowSearchCompanion);
   }
 #endif
-  if (base::FeatureList::IsEnabled(features::kTabOrganizationAppMenuItem) &&
-      TabOrganizationUtils::GetInstance()->IsEnabled(browser_->profile())) {
-    auto* const tab_organization_service =
-        TabOrganizationServiceFactory::GetForProfile(browser_->profile());
-    if (tab_organization_service) {
-      AddItemWithStringIdAndVectorIcon(
-          this, IDC_ORGANIZE_TABS, IDS_TAB_ORGANIZE_MENU, kAutoTabGroupsIcon);
-      SetIsNewFeatureAt(GetIndexOfCommandId(IDC_ORGANIZE_TABS).value(),
-                        browser()->window()->MaybeShowNewBadgeFor(
-                            features::kTabOrganization));
-    }
-  }
 
   AddItemWithStringIdAndVectorIcon(this, IDC_SHOW_TRANSLATE, IDS_SHOW_TRANSLATE,
                                    kTranslateIcon);
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
index 5c94c1f..793de080 100644
--- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -372,9 +372,10 @@
   TabOrganizationUtils::GetInstance()->SetIgnoreOptGuideForTesting(true);
   AppMenuModel model(this, browser());
   model.Init();
+  ToolsMenuModel toolModel(&model, browser());
   size_t organize_tabs_index =
-      model.GetIndexOfCommandId(IDC_ORGANIZE_TABS).value();
-  EXPECT_TRUE(model.IsEnabledAt(organize_tabs_index));
+      toolModel.GetIndexOfCommandId(IDC_ORGANIZE_TABS).value();
+  EXPECT_TRUE(toolModel.IsEnabledAt(organize_tabs_index));
 }
 
 TEST_F(TestAppMenuModelCR2023, ModelHasIcons) {
diff --git a/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc b/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
index c70cac7..a901ec1 100644
--- a/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
@@ -10,18 +10,21 @@
 
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
 #include "base/notreached.h"
 #include "base/observer_list.h"
+#include "base/strings/strcat.h"
 #include "base/values.h"
 #include "chrome/browser/companion/core/constants.h"
 #include "chrome/browser/companion/core/features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/actions/chrome_action_id.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/views/side_panel/companion/companion_utils.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_factory.h"
 #include "chrome/browser/ui/toolbar/toolbar_pref_names.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "chrome/browser/ui/views/side_panel/companion/companion_utils.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
@@ -86,10 +89,21 @@
   }
 
   const bool is_pinned = Contains(action_id);
+  const std::optional<std::string> metrics_name =
+      actions::ActionIdMap::ActionIdToString(action_id);
+  CHECK(metrics_name.has_value());
   if (!is_pinned && should_pin) {
     PinAction(action_id);
+    base::RecordComputedAction(base::StrCat(
+        {"Actions.PinnedToolbarButton.Pinned.", metrics_name.value()}));
+    base::RecordAction(
+        base::UserMetricsAction("Actions.PinnedToolbarButton.Pinned"));
   } else if (is_pinned && !should_pin) {
     UnpinAction(action_id);
+    base::RecordComputedAction(base::StrCat(
+        {"Actions.PinnedToolbarButton.Unpinned.", metrics_name.value()}));
+    base::RecordAction(
+        base::UserMetricsAction("Actions.PinnedToolbarButton.Unpinned"));
   }
 }
 
diff --git a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
index 2f5b9e6..c78bb82 100644
--- a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
@@ -8,6 +8,7 @@
 #include <type_traits>
 
 #include "base/metrics/user_metrics.h"
+#include "base/strings/strcat.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_actions.h"
@@ -399,6 +400,13 @@
     actions::ActionItem* action_item) {
   base::RecordAction(
       base::UserMetricsAction("Actions.PinnedToolbarButtonActivation"));
+  std::optional<actions::ActionId> action_id = action_item->GetActionId();
+  CHECK(action_id.has_value());
+  const std::optional<std::string> metrics_name =
+      actions::ActionIdMap::ActionIdToString(action_id.value());
+  CHECK(metrics_name.has_value());
+  base::RecordComputedAction(base::StrCat(
+      {"Actions.PinnedToolbarButtonActivation.", metrics_name.value()}));
 
   base::AutoReset<bool> needs_delayed_destruction =
       action_view_->SetNeedsDelayedDestruction(true);
diff --git a/chrome/browser/ui/webui/managed_ui_handler_unittest.cc b/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
index 9dcc1514..2f04d0d 100644
--- a/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
@@ -86,19 +86,18 @@
   std::unique_ptr<content::TestWebUIDataSource> source_;
 };
 
-// TODO(crbug.com/355288951): fix these tests.
-TEST_F(ManagedUIHandlerTest, DISABLED_ManagedUIDisabledByDefault) {
+TEST_F(ManagedUIHandlerTest, ManagedUIDisabledByDefault) {
   InitializeHandler();
   EXPECT_FALSE(IsSourceManaged());
 }
 
-TEST_F(ManagedUIHandlerTest, DISABLED_ManagedUIEnabledWhenManaged) {
+TEST_F(ManagedUIHandlerTest, ManagedUIEnabledWhenManaged) {
   profile_policy_connector()->OverrideIsManagedForTesting(true);
   InitializeHandler();
   EXPECT_TRUE(IsSourceManaged());
 }
 
-TEST_F(ManagedUIHandlerTest, DISABLED_ManagedUIBecomesEnabledByProfile) {
+TEST_F(ManagedUIHandlerTest, ManagedUIBecomesEnabledByProfile) {
   InitializeHandler();
   EXPECT_FALSE(IsSourceManaged());
 
diff --git a/chrome/browser/ui/webui/searchbox/searchbox_handler.cc b/chrome/browser/ui/webui/searchbox/searchbox_handler.cc
index 374a553..8f384fea 100644
--- a/chrome/browser/ui/webui/searchbox/searchbox_handler.cc
+++ b/chrome/browser/ui/webui/searchbox/searchbox_handler.cc
@@ -311,14 +311,16 @@
       const omnibox::AnswerData& answer_data =
           match.answer_template->answers(0);
       const omnibox::FormattedString& headline = answer_data.headline();
-      const std::string& headline_text = headline.text();
-      // Grab the substring of headline starting after the first fragment text
-      // ends. Not making use of the first fragment because it contains the same
-      // data as `match.contents` but with HTML tags.
-      const std::u16string headline_substr =
-          base::UTF8ToUTF16(headline_text.substr(
-              headline.fragments(0).text().size(),
-              headline_text.size() - headline.fragments(0).text().size()));
+      std::u16string headline_substr;
+      if (headline.fragments_size() > 0) {
+        const std::string& headline_text = headline.text();
+        // Grab the substring of headline starting after the first fragment text
+        // ends. Not making use of the first fragment because it contains the
+        // same data as `match.contents` but with HTML tags.
+        headline_substr = base::UTF8ToUTF16(headline_text.substr(
+            headline.fragments(0).text().size(),
+            headline_text.size() - headline.fragments(0).text().size()));
+      }
 
       const auto& subhead_text =
           base::UTF8ToUTF16(answer_data.subhead().text());
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
index 914a525..fd2174d 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.h"
 
+#include "base/metrics/user_metrics.h"
+#include "base/strings/strcat.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/actions/chrome_action_id.h"
@@ -320,6 +322,15 @@
       break;
     default:
       model_->UpdatePinnedState(chrome_action.value(), pin);
+      const std::optional<std::string> metrics_name =
+          actions::ActionIdMap::ActionIdToString(chrome_action.value());
+      CHECK(metrics_name.has_value());
+      base::RecordComputedAction(base::StrCat(
+          {"Actions.PinnedToolbarButton.", pin ? "Pinned" : "Unpinned",
+           ".ByCustomizeChromeSidePanel.", metrics_name.value()}));
+      base::RecordComputedAction(base::StrCat({"Actions.PinnedToolbarButton.",
+                                               pin ? "Pinned" : "Unpinned",
+                                               ".ByCustomizeChromeSidePanel"}));
   }
 }
 
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler_unittest.cc
index 30f84d13..98a4fef 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler_unittest.cc
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/test/mock_callback.h"
 #include "chrome/browser/companion/core/features.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/ui/actions/chrome_actions.h"
 #include "chrome/browser/ui/browser_actions.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_factory.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -100,6 +101,7 @@
 
   void SetUp() override {
     SetupFeatureList();
+    InitializeActionIdStringMapping();
     BrowserWithTestWindowTest::SetUp();
 
     mock_pinned_toolbar_actions_model_ =
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler_unittest.cc
index 320a143..b0fdfb1 100644
--- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler_unittest.cc
@@ -218,10 +218,6 @@
       1u);
 }
 
-// Until the kReadAloudAutoVoiceSwitching flag is enabled on all platforms,
-// there is slightly different behavior that needs to be tested on ChromeOS
-// vs. other platforms.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(ReadAnythingUntrustedPageHandlerTest,
        OnHandlerConstructed_WithReadAloud_SendsStoredReadAloudInfo) {
   // Build the voice and lang info.
@@ -332,67 +328,5 @@
   EXPECT_THAT(*voices,
               base::test::DictionaryHasValue(kLang2, base::Value(kVoice)));
 }
-#else
-TEST_F(ReadAnythingUntrustedPageHandlerTest,
-       OnHandlerConstructed_WithReadAloud_SendsStoredReadAloudInfo) {
-  // Build the voice and lang info.
-  const char kVoice[] = "Maria";
-  const char kLang1[] = "en";
-  const char kLang2[] = "fr";
-  const char kLang3[] = "it";
-  base::Value::List langs;
-  langs.Append(kLang1);
-  langs.Append(kLang2);
-  langs.Append(kLang3);
-
-  // Set the values in prefs.
-  double expected_speech_rate = 1.2;
-  read_anything::mojom::HighlightGranularity expected_highlight_granularity =
-      read_anything::mojom::HighlightGranularity::kOff;
-  PrefService* prefs = profile()->GetPrefs();
-  prefs->SetDouble(prefs::kAccessibilityReadAnythingSpeechRate,
-                   expected_speech_rate);
-  prefs->SetString(prefs::kAccessibilityReadAnythingVoiceName, kVoice);
-  prefs->SetList(prefs::kAccessibilityReadAnythingLanguagesEnabled,
-                 std::move(langs));
-  prefs->SetInteger(prefs::kAccessibilityReadAnythingHighlightGranularity, 1);
-
-  // Verify the values passed to the page are correct.
-  EXPECT_CALL(page_, OnSettingsRestoredFromPrefs(
-                         _, _, _, _, _, _, _, expected_speech_rate, _, _,
-                         expected_highlight_granularity))
-      .Times(1)
-      .WillOnce(testing::WithArgs<8, 9>(testing::Invoke(
-          [&](base::Value::Dict voices, base::Value::List langs) {
-            EXPECT_THAT(voices, base::test::DictionaryHasValue(
-                                    "", base::Value(kVoice)));
-            EXPECT_EQ(3u, langs.size());
-            EXPECT_EQ(langs[0].GetString(), kLang1);
-            EXPECT_EQ(langs[1].GetString(), kLang2);
-            EXPECT_EQ(langs[2].GetString(), kLang3);
-          })));
-
-  handler_ = std::make_unique<TestReadAnythingUntrustedPageHandler>(
-      page_.BindAndGetRemote(), test_web_ui_.get());
-}
-
-TEST_F(ReadAnythingUntrustedPageHandlerTest,
-       OnVoiceChange_StoresLatestInPrefs) {
-  const char kLang1[] = "hi";
-  const char kLang2[] = "ja";
-  const char kVoice1[] = "Ariel";
-  const char kVoice2[] = "Sebastian";
-  handler_ = std::make_unique<TestReadAnythingUntrustedPageHandler>(
-      page_.BindAndGetRemote(), test_web_ui_.get());
-
-  OnVoiceChange(kVoice1, kLang1);
-  OnVoiceChange(kVoice2, kLang2);
-
-  std::string voice = profile()->GetPrefs()->GetString(
-      prefs::kAccessibilityReadAnythingVoiceName);
-  ASSERT_EQ(voice, kVoice2);
-}
-
-#endif  // IS_CHROME_OS_ASH
 
 }  // namespace
diff --git a/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc b/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc
index fcfc3f7e..9d93db9c 100644
--- a/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc
+++ b/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/segmentation_platform/segmentation_platform_service_factory.h"
+#include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/visited_url_ranking/url_deduplication/search_engine_url_strip_handler.h"
 #include "chrome/common/channel_info.h"
@@ -24,6 +25,7 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/history_clusters/core/config.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/sync_device_info/device_info_sync_service.h"
 #include "components/url_deduplication/url_deduplication_helper.h"
 #include "components/visited_url_ranking/internal/history_url_visit_data_fetcher.h"
 #include "components/visited_url_ranking/internal/session_url_visit_data_fetcher.h"
@@ -77,6 +79,7 @@
   DependsOn(SessionSyncServiceFactory::GetInstance());
   DependsOn(BookmarkModelFactory::GetInstance());
   DependsOn(HistoryServiceFactory::GetInstance());
+  DependsOn(DeviceInfoSyncServiceFactory::GetInstance());
 }
 
 VisitedURLRankingServiceFactory::~VisitedURLRankingServiceFactory() = default;
@@ -136,9 +139,12 @@
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile, ServiceAccessType::IMPLICIT_ACCESS);
   if (hs) {
+    syncer::DeviceInfoSyncService* device_info_sync_service =
+        DeviceInfoSyncServiceFactory::GetForProfile(profile);
     data_fetchers.emplace(
         Fetcher::kHistory,
-        std::make_unique<visited_url_ranking::HistoryURLVisitDataFetcher>(hs));
+        std::make_unique<visited_url_ranking::HistoryURLVisitDataFetcher>(
+            hs, device_info_sync_service));
   }
 
   // TODO(crbug.com/349317344): Move transformers map to a shareable helper
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 1f05c844..d162648 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -118,6 +118,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/gfx/native_widget_types.h"
 #include "url/url_constants.h"
 #include "url/url_util.h"
 
@@ -1300,20 +1301,29 @@
 
 #if BUILDFLAG(IS_MAC)
   {
+    NSWindow* window = nullptr;
     content::WebContents* web_contents =
         content::WebContents::FromRenderFrameHost(GetRenderFrameHost());
-    // Not all contexts in which this code runs have a BrowserWindow.
-    // Notably the dialog containing a WebContents that is used for signing
-    // into a new profile does not. Thus the NSWindow is fetched more directly.
-    const views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(
-        web_contents->GetNativeView());
-    if (widget) {
-      const gfx::NativeWindow window = widget->GetNativeWindow();
-      if (window) {
-        discovery_factory->set_nswindow(
-            reinterpret_cast<uintptr_t>(window.GetNativeNSWindow()));
+    BrowserWindow* browser_window =
+        BrowserWindow::FindBrowserWindowWithWebContents(web_contents);
+    if (browser_window) {
+      window = browser_window->GetNativeWindow().GetNativeNSWindow();
+    }
+    if (!window) {
+      // Not all contexts in which this code runs have a BrowserWindow.
+      // Notably the dialog containing a WebContents that is used for signing
+      // into a new profile does not. Thus the NSWindow is fetched more
+      // directly.
+      const views::Widget* widget =
+          views::Widget::GetTopLevelWidgetForNativeView(
+              web_contents->GetNativeView());
+      if (widget) {
+        window = widget->GetNativeWindow().GetNativeNSWindow();
       }
     }
+    if (window) {
+      discovery_factory->set_nswindow(reinterpret_cast<uintptr_t>(window));
+    }
   }
 #endif
 
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 5cd60315..59a253f 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1725890118-14bf2d585a1060566a1149c7bd130a3cf5303966-a5ef4add19d54114e93c4d5961886de22457c271.profdata
+chrome-mac-arm-main-1725911957-d6559fd3d4100ee9887808b7f4d9541e99f20206-c791a4048c09bea65037bcfe806d178cfd27e548.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d6296e8..f717b41 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1725883182-f2669f763ab2a6f5b6e1578f6089d876239c12e4-f865bb36e73d0176fda35b7bbbf6326cde24fb97.profdata
+chrome-win32-main-1725904596-9a2c2bd76c11810e875a41676a96a75fb468e691-8657dcac1fc3418467121adbb7e32735bf2853f2.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 1ab14a2..1c5c19b8 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1725883182-5b4980dd2852ffd628237c4e68d72e41de17cb0d-f865bb36e73d0176fda35b7bbbf6326cde24fb97.profdata
+chrome-win64-main-1725904596-53b332dd12e5ce022fdd42f1d796891f918d7b81-8657dcac1fc3418467121adbb7e32735bf2853f2.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 8f3ff1f..95c3b45 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -1079,7 +1079,7 @@
 // Safety Hub Extension Reivew Panel.
 BASE_FEATURE(kSafetyHubExtensionsNoPrivacyPracticesTrigger,
              "SafetyHubExtensionsNoPrivacyPracticesTrigger",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 // Enables offstore extensions to be shown in the Safety Hub Extension
 // review panel.
 BASE_FEATURE(kSafetyHubExtensionsOffStoreTrigger,
diff --git a/chrome/enterprise_companion/BUILD.gn b/chrome/enterprise_companion/BUILD.gn
index 519ece2..1e69a6f2 100644
--- a/chrome/enterprise_companion/BUILD.gn
+++ b/chrome/enterprise_companion/BUILD.gn
@@ -57,7 +57,7 @@
     "app/app_client_base.cc",
     "app/app_client_base.h",
     "app/app_fetch_policies.cc",
-    "app/app_install.cc",
+    "app/app_installer.cc",
     "app/app_server.cc",
     "app/app_shutdown.cc",
     "crash_client.cc",
@@ -189,7 +189,7 @@
   testonly = true
 
   sources = [
-    "app/app_install_unittest.cc",
+    "app/app_installer_unittest.cc",
     "app/app_shutdown_unittest.cc",
     "crash_client_unittest.cc",
     "dm_client_unittest.cc",
@@ -310,7 +310,10 @@
     "//base",
   ]
 
-  visibility = [ ":*" ]
+  visibility = [
+    ":*",
+    "//chrome/updater:*",
+  ]
 
   if (is_linux) {
     sources += [ "installer_paths_linux.cc" ]
@@ -348,7 +351,10 @@
     "//base",
     "//url",
   ]
-  visibility = [ ":*" ]
+  visibility = [
+    ":*",
+    "//chrome/updater:*",
+  ]
   defines = [ "ENTERPRISE_COMPANION_TEST_ONLY" ]
 }
 
diff --git a/chrome/enterprise_companion/README.md b/chrome/enterprise_companion/README.md
index 7d72e40ac..27d8dd0 100644
--- a/chrome/enterprise_companion/README.md
+++ b/chrome/enterprise_companion/README.md
@@ -1,33 +1,219 @@
 # Chrome Enterprise Companion App
 
-Chrome Enterprise Companion App (CECA) is an elevated daemon for MacOS and
-Windows that handles the enterprise device management features which are not
-feasible to implement in browser.
+## Background
 
-The mission of CECA is to empower development of client-side enterprise features
-and reduce complexity by decoupling enterprise functionality from the updater
-client.
+Chrome Enterprise Companion App (CECA) is an elevated daemon for MacOS and
+Windows that handles enterprise device management features which are not
+feasible to implement in the browser.
+
+Originally, this project was developed to separate Chrome Browser Enterprise
+Cloud Management functionality from the ChromiumUpdater (//chrome/updater),
+allowing the development of related features to be decoupled from this high-risk
+surface.
+
+## Overview
+
+CECA is a program that performs enrollment and policy fetching for cloud-managed
+Chrome browsers.
 
 ## Design
 
-### Event Logging
+Once installed, CECA operates as a daemon and is interacted with via the IPC
+interface it exposes.  The server process hosts an engine that conducts most of
+the work, it is interacted with by client processes that issue commands to it.
 
-CECA collects service-related data and transmits that to a remote logging service
-via the EventLogger interface. The collected data is represented by the proto
-files in //chrome/enterprise_companion/proto.
+![Chrome Enterprise Companion App architecture diagram](images/architecture.svg)
 
-To support batching of request and rate-limiting, logs recorded by individual
-EventLogger instances are flushed to an EventLoggerManager. Flushing occurs
-either when the EventLogger is destroyed or when requested explicitly.
+CECA is installed system-wide and is launched by the Chromium Updater. When
+launched, the application attempts to acquire a single cross-process lock. If
+acquired, the application begins accepting incoming IPC connections and
+servicing RPCs from client processes. The application runs until it is requested
+to shut down via RPC.
 
-The manager handles the serialization and transmission of log events to the
-remote endpoint. If an EventLogger flushes while the manager is rate-limited,
-the logs will be queued and transmitted as soon as the manager is able.
+## RPC Interface
 
-The EventLogger interface is intended to record both the start and stop of
-operations. Calling a logging method indicates the start of an operation while
-invoking the returned callback signifies the end.
+CECA’s functionality is driven by RPCs from client processes. Mojo provides the
+IDL, C++ bindings, and underlying IPC system. The interface definition is
+located in the mojom/ subdirectory.
 
-The EventLoggerManager will wait 15 minutes between requests. Alternatively, the
-logging service may respond with timeout, in which case the larger of the two
-values is used.
+CECA listens for incoming Mojo invitations on a platform-dependent interface
+(i.e. a named pipe on Windows, a mach port on Mac, or a socket on Linux).
+Clients are able to locate this interface via a statically defined name. Upon
+receiving an invitation, CECA may accept or reject it. If accepted, a Mojo
+connection is established and clients may perform RPCs. This process is
+abstracted by //components/named_mojo_ipc_server.
+
+### IPC Security
+
+Although the scope of the RPC interface is limited, as CECA is an elevated
+process (running as SYSTEM on Windows, root on Mac and Linux), it is prudent
+that only authorized callers are allowed. The IPC interface is protected
+differently on each platform. On Windows, a security descriptor is configured on
+the interface’s named pipe allowing only access from SYSTEM. On Mac, an
+audit_token is used to verify that the caller has the same euid as the server.
+On Linux, the credentials of the calling process are read via SO_PEERCRED and
+the caller’s UID is compared to the server’s.
+
+## Policy Agent Functionality
+
+CECA’s main functionality is to act as a policy agent for Chrome Browser
+Enterprise Cloud Management. This consists of two primary responsibilities:
+machine enrollment and policy fetching.
+
+### Background
+
+Chrome Browser Enterprise Cloud Management allows system administrators to
+configure policies which control the behavior of the Chromium Updater and
+Browser. Administrators are provided enrollment tokens which can be used to
+authenticate a device as being managed by that organization. A policy agent uses
+the enrollment token to register the device with the Device Management Server
+(DM server). Upon enrollment, the DM Server provides the policy agent with a
+Device Management Token (DM token) that identifies the device and the
+organization it belongs to in future communication.
+
+After enrollment, policy agents may request policies from DM Server,
+authenticating themselves via the DM token.
+
+### Implementation
+
+CECA acts as a policy agent for the Chromium Updater and Chrome Browser. When
+the Chromium Updater performs its scheduled periodic tasks, it will request a
+policy fetch from CECA, launching the daemon if it is not already running. CECA
+will determine if the device is already enrolled via the presence of a DM token
+in storage. If not enrolled, CECA will look for an enrollment token in storage
+and attempt registration before continuing with the request. Next, CECA requests
+policies from DM Server, serializing the responses to a policy cache on disk
+which is subsequently read from by the Chromium Updater and Chrome Browser.
+
+### Device Management Storage
+
+The enrollment token, DM token, and fetched policies are persisted on device.
+Token storage and the policy cache are collectively referred to as DM storage
+and are abstracted by device_management_storage/. The storage is implemented as
+follows:
+
+#### Windows
+
+The enrollment token is searched in the order:
+
+1. The `EnrollmentToken` `REG_SZ` value from
+`HKLM\Software\Policies\{COMPANY_SHORTNAME}\CloudManagement`
+
+1. The `CloudManagementEnrollmentToken` `REG_SZ` value from
+`HKLM\Software\Policies\{COMPANY_SHORTNAME}\{BROWSER_NAME}`
+
+1. The `CloudManagementEnrollmentToken` `REG_SZ` value from
+`{CLIENTSTATE}\{UpdaterAppID} (the runtime enrollment token)`
+
+1. The `CloudManagementEnrollmentToken` `REG_SZ` value from
+`{CLIENTSTATE}\{430FD4D0-B729-4F61-AA34-91526481799D}` (the legacy runtime
+enrollment token)
+
+The DM token is stored in:
+
+* The `dmtoken` `REG_BINARY` value at path:
+`HKLM\Software\WOW6432Node\{COMPANY_SHORTNAME}\Enrollment\`
+
+* The `dmtoken` `REG_BINARY` value at path:
+`HKLM64\Software\{COMPANY_SHORTNAME}\{BROWSER_NAME}\Enrollment\`. This is for
+backward compatibility.
+
+The `EnrollmentMandatory` REG_DWORD value is also read from `HKLM\Software\Policies\{COMPANY_SHORTNAME}\CloudManagement`.
+
+#### Mac
+
+The enrollment token is searched in the order:
+
+1. Managed Preference value with key `CloudManagementEnrollmentToken` in domain
+`{MAC_BROWSER_BUNDLE_IDENTIFIER}`.
+
+2. Managed Preference value with key `EnrollmentToken` in domain
+`{MAC_BROWSER_BUNDLE_IDENTIFIER}`.
+
+File `/Library/{COMPANY_SHORTNAME}/{BROWSER_NAME}/CloudManagementEnrollmentToken`.
+
+The DM token is stored in:
+`/Library/Application Support/{COMPANY_SHORTNAME}/CloudManagement`.
+
+#### Linux
+
+The enrollment token is stored in:
+`/opt/{COMPANY_SHORTNAME}/{PRODUCT_FULLNAME}/CloudManagementEnrollmentToken`
+
+The DM token is stored in:
+`/opt/{COMPANY_SHORTNAME}/{PRODUCT_FULLNAME}/CloudManagement`
+
+## Installation
+
+CECA bundles an installer into its executable which can be invoked via the
+`--install` command-line flag. When the installer launches, it instructs the
+currently running server process to shutdown via RPC, if one is running. It then
+acquires the cross-process lock before copying itself to the installation
+directory.
+
+On Windows the application is distributed for both x86 and x86_64. If an
+existing installation for a different architecture is present, the installer
+will remove it before installing itself. The application is installed to
+`%PROGRAMFILES%` or `%PROGRAMFILESX86%` under
+`{COMPANY_SHORTNAME}\{PRODUCT_FULLNAME}`. E.g.
+`C:\Program Files\Google\ChromeEnterpriseCompanion`.
+
+On Mac the application is distributed via a PKG installer which bundles the
+application binary and a postinstall script which launches CECA with the
+`--install` flag. The application is installed to
+`/Library/Application Support/{COMPANY_SHORTNAME}/{PRODUCT_FULLNAME}`.
+
+On Linux the application is installed to
+`/opt/{COMPANY_SHORTNAME_LOWERCASE}/{PRODUCT_FULLNAME_DASHED_LOWERCASE}`.
+
+CECA similarly bundles an uninstaller via the `--uninstall` command-line flag.
+When the Chromium Updater is uninstalled, CECA is too.
+
+## Networking
+
+CECA requires networking for its communication with the DM server and
+transmission of telemetry. For compatibility with existing code in
+//components/policy/, the Chromium network stack is used.
+
+Special care is taken to ensure that CECA can navigate through mandatory proxy
+configurations. On Windows, the logged-in user is guessed via the owner of
+`explorer.exe` and impersonated for the lifetime of the networking thread. On
+Mac, the logged-in user is guessed via querying the System Configuration dynamic
+store for console users and networking is delegated to a subprocess launched in
+their bootstrap namespace (i.e. via `launchctl asuser`).
+
+## Event Logging
+
+CECA records information about the health of the service and transmits it to a
+remote logging endpoint over HTTPS. This information is used to monitor and
+improve the application. The information transmitted is defined by
+`enterprise_companion_event.proto`. Upon the first logging transmission, the
+server will respond with a logging cookie which identifies the device in future
+transmissions. This cookie is persisted in a file named `logging_cookie` in the
+application’s install directory.
+
+## Crash Reporting
+
+CECA uses Crashpad for crash reporting. Each CECA process spawns a crash handler
+child process. CECA may upload its crash reports if and only if the Chromium
+Updater is permitted to send usage stats. CECA may attach its log file to the
+crash reports it uploads. Each crash handler process is capable of uploading
+crashes.
+
+## Testing
+
+CECA defines a unit test target (`enterprise_companion_tests`) and an
+integration test target (`enterprise_companion_integration_tests`). Running the
+unit tests does not require any special permissions and the suites may be run
+concurrently. The integration tests must be run by an elevated user (an
+Administrator on Windows, root on Mac or Linux) and are executed serially.
+
+The integration tests operate on a CECA binary instrumented for testing. The
+application-under-test binary’s target is `enterprise_companion_test`. The test
+binary allows for global constants to be overridden via an `overrides.json` file
+placed in the installation directory. This allows the integration tests to
+provide values such as the DM server URL, event logger timeout, and named pipe
+security descriptor. Additionally, the test binary allows alternative
+cryptographic keys to be used for validating responses from the DM server, thus
+allowing the integration tests to correctly mock responses.
+
diff --git a/chrome/enterprise_companion/app/app.h b/chrome/enterprise_companion/app/app.h
index 58936a5b..c5c4a9e 100644
--- a/chrome/enterprise_companion/app/app.h
+++ b/chrome/enterprise_companion/app/app.h
@@ -53,12 +53,17 @@
     const mojo::NamedPlatformChannel::ServerName& server_name =
         GetServerName());
 
-std::unique_ptr<App> CreateAppInstall(
-    base::OnceCallback<EnterpriseCompanionStatus()> shutdown_remote_task =
-        base::BindOnce([] { return CreateAppShutdown()->Run(); }),
+// AppInstaller is used to implement the install/uninstall apps. It uses
+// caller-provided tasks to shut down the remote server and acquires the global
+// singleton lock. Then, it runs the provided task (e.g. `Install` or
+// `Uninstall`).
+std::unique_ptr<App> CreateAppInstaller(
+    base::OnceCallback<EnterpriseCompanionStatus()> shutdown_remote_task,
     base::OnceCallback<std::unique_ptr<ScopedLock>(base::TimeDelta timeout)>
-        lock_provider = base::BindOnce(&CreateScopedLock),
-    base::OnceCallback<bool()> task = base::BindOnce(&Install));
+        lock_provider,
+    base::OnceCallback<bool()> install_task);
+
+std::unique_ptr<App> CreateAppInstall();
 
 std::unique_ptr<App> CreateAppUninstall();
 
diff --git a/chrome/enterprise_companion/app/app_install.cc b/chrome/enterprise_companion/app/app_installer.cc
similarity index 78%
rename from chrome/enterprise_companion/app/app_install.cc
rename to chrome/enterprise_companion/app/app_installer.cc
index 0050b310..7bcbc2f 100644
--- a/chrome/enterprise_companion/app/app_install.cc
+++ b/chrome/enterprise_companion/app/app_installer.cc
@@ -20,9 +20,9 @@
 
 constexpr base::TimeDelta kAcquireLockTimeout = base::Seconds(5);
 
-class AppInstall : public App {
+class AppInstaller : public App {
  public:
-  AppInstall(
+  AppInstaller(
       base::OnceCallback<EnterpriseCompanionStatus()> shutdown_remote_task,
       base::OnceCallback<std::unique_ptr<ScopedLock>(base::TimeDelta timeout)>
           lock_provider,
@@ -30,7 +30,9 @@
       : shutdown_remote_task_(std::move(shutdown_remote_task)),
         lock_provider_(std::move(lock_provider)),
         install_task_(std::move(install_task)) {}
-  ~AppInstall() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
+  ~AppInstaller() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
 
  private:
   void FirstTaskRun() override {
@@ -67,18 +69,24 @@
 
 }  // namespace
 
-std::unique_ptr<App> CreateAppInstall(
+std::unique_ptr<App> CreateAppInstaller(
     base::OnceCallback<EnterpriseCompanionStatus()> shutdown_remote_task,
     base::OnceCallback<std::unique_ptr<ScopedLock>(base::TimeDelta timeout)>
         lock_provider,
-    base::OnceCallback<bool()> install_task) {
-  return std::make_unique<AppInstall>(std::move(shutdown_remote_task),
-                                      std::move(lock_provider),
-                                      std::move(install_task));
+    base::OnceCallback<bool()> task) {
+  return std::make_unique<AppInstaller>(std::move(shutdown_remote_task),
+                                        std::move(lock_provider),
+                                        std::move(task));
+}
+
+std::unique_ptr<App> CreateAppInstall() {
+  return std::make_unique<AppInstaller>(
+      base::BindOnce([] { return CreateAppShutdown()->Run(); }),
+      base::BindOnce(&CreateScopedLock), base::BindOnce(&Install));
 }
 
 std::unique_ptr<App> CreateAppUninstall() {
-  return CreateAppInstall(
+  return std::make_unique<AppInstaller>(
       base::BindOnce([] { return CreateAppShutdown()->Run(); }),
       base::BindOnce(&CreateScopedLock), base::BindOnce(&Uninstall));
 }
diff --git a/chrome/enterprise_companion/app/app_install_unittest.cc b/chrome/enterprise_companion/app/app_installer_unittest.cc
similarity index 79%
rename from chrome/enterprise_companion/app/app_install_unittest.cc
rename to chrome/enterprise_companion/app/app_installer_unittest.cc
index fd348f8..177ac697 100644
--- a/chrome/enterprise_companion/app/app_install_unittest.cc
+++ b/chrome/enterprise_companion/app/app_installer_unittest.cc
@@ -42,61 +42,61 @@
 
 }  // namespace
 
-class AppInstallTest : public ::testing::Test {
+class AppInstallerTest : public ::testing::Test {
  private:
   base::test::TaskEnvironment environment_;
 };
 
-TEST_F(AppInstallTest, ShutdownRemote) {
+TEST_F(AppInstallerTest, ShutdownRemote) {
   base::MockCallback<base::OnceCallback<EnterpriseCompanionStatus()>>
       mock_shutdown_callback;
   EXPECT_CALL(mock_shutdown_callback, Run())
       .WillOnce(Return(EnterpriseCompanionStatus::Success()));
 
   EnterpriseCompanionStatus status =
-      CreateAppInstall(mock_shutdown_callback.Get(),
-                       base::BindOnce(&CreateLockForTest),
-                       /*install_task=*/base::BindOnce([] { return true; }))
+      CreateAppInstaller(mock_shutdown_callback.Get(),
+                         base::BindOnce(&CreateLockForTest),
+                         /*task=*/base::BindOnce([] { return true; }))
           ->Run();
 
   EXPECT_TRUE(status.ok());
 }
 
-TEST_F(AppInstallTest, LockContested) {
+TEST_F(AppInstallerTest, LockContested) {
   EnterpriseCompanionStatus status =
-      CreateAppInstall(
+      CreateAppInstaller(
           /*shutdown_remote_task=*/base::BindOnce(
               &EnterpriseCompanionStatus::Success),
           /*lock_provider=*/base::BindOnce([](base::TimeDelta) {
             return base::WrapUnique<ScopedLock>(nullptr);
           }),
-          /*install_task=*/base::BindOnce([] { return true; }))
+          /*task=*/base::BindOnce([] { return true; }))
           ->Run();
 
   EXPECT_EQ(status,
             EnterpriseCompanionStatus(ApplicationError::kCannotAcquireLock));
 }
 
-TEST_F(AppInstallTest, InstallFails) {
+TEST_F(AppInstallerTest, InstallFails) {
   EnterpriseCompanionStatus status =
-      CreateAppInstall(
+      CreateAppInstaller(
           /*shutdown_remote_task=*/base::BindOnce(
               &EnterpriseCompanionStatus::Success),
           /*lock_provider=*/base::BindOnce(&CreateLockForTest),
-          /*install_task=*/base::BindOnce([] { return false; }))
+          /*task=*/base::BindOnce([] { return false; }))
           ->Run();
 
   EXPECT_EQ(status,
             EnterpriseCompanionStatus(ApplicationError::kInstallationFailed));
 }
 
-TEST_F(AppInstallTest, InstallSuccess) {
+TEST_F(AppInstallerTest, InstallSuccess) {
   EnterpriseCompanionStatus status =
-      CreateAppInstall(
+      CreateAppInstaller(
           /*shutdown_remote_task=*/base::BindOnce(
               &EnterpriseCompanionStatus::Success),
           /*lock_provider=*/base::BindOnce(&CreateLockForTest),
-          /*install_task=*/base::BindOnce([] { return true; }))
+          /*task=*/base::BindOnce([] { return true; }))
           ->Run();
 
   EXPECT_TRUE(status.ok());
diff --git a/chrome/enterprise_companion/images/architecture.svg b/chrome/enterprise_companion/images/architecture.svg
new file mode 100644
index 0000000..7125862
--- /dev/null
+++ b/chrome/enterprise_companion/images/architecture.svg
@@ -0,0 +1 @@
+<svg version="1.1" viewBox="0.0 0.0 960.0 540.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><clipPath id="g2fd1984f7da_0_0.0"><path d="m0 0l960.0 0l0 540.0l-960.0 0l0 -540.0z" clip-rule="nonzero"/></clipPath><g clip-path="url(#g2fd1984f7da_0_0.0)"><path fill="#ffffff" d="m0 0l960.0 0l0 540.0l-960.0 0z" fill-rule="evenodd"/><path fill="#d9ead3" d="m216.30446 197.02296l120.66142 0l0 41.795273l-120.66142 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m216.30446 197.02296l120.66142 0l0 41.795273l-120.66142 0z" fill-rule="evenodd"/><path fill="#000000" d="m264.88467 219.32872l1.390625 0.34375q-0.4375 1.703125 -1.578125 2.609375q-1.125 0.890625 -2.765625 0.890625q-1.6875 0 -2.75 -0.6875q-1.0625 -0.6875 -1.625 -2.0q-0.546875 -1.3125 -0.546875 -2.8125q0 -1.640625 0.625 -2.859375q0.625 -1.21875 1.78125 -1.84375q1.15625 -0.640625 2.546875 -0.640625q1.5625 0 2.640625 0.8125q1.078125 0.796875 1.5 2.25l-1.375 0.3125q-0.359375 -1.140625 -1.0625 -1.65625q-0.6875 -0.53125 -1.734375 -0.53125q-1.21875 0 -2.03125 0.578125q-0.8125 0.578125 -1.140625 1.5625q-0.328125 0.96875 -0.328125 2.015625q0 1.328125 0.390625 2.328125q0.390625 1.0 1.21875 1.5q0.828125 0.484375 1.78125 0.484375q1.171875 0 1.96875 -0.671875q0.8125 -0.671875 1.09375 -1.984375zm3.131134 3.671875l0 -10.484375l7.59375 0l0 1.234375l-6.203125 0l0 3.203125l5.796875 0l0 1.234375l-5.796875 0l0 3.578125l6.4375 0l0 1.234375l-7.828125 0zm17.22873 -3.671875l1.390625 0.34375q-0.4375 1.703125 -1.578125 2.609375q-1.125 0.890625 -2.765625 0.890625q-1.6875 0 -2.75 -0.6875q-1.0625 -0.6875 -1.625 -2.0q-0.546875 -1.3125 -0.546875 -2.8125q0 -1.640625 0.625 -2.859375q0.625 -1.21875 1.78125 -1.84375q1.15625 -0.640625 2.546875 -0.640625q1.5625 0 2.640625 0.8125q1.078125 0.796875 1.5 2.25l-1.375 0.3125q-0.359375 -1.140625 -1.0625 -1.65625q-0.6875 -0.53125 -1.734375 -0.53125q-1.21875 0 -2.03125 0.578125q-0.8125 0.578125 -1.140625 1.5625q-0.328125 0.96875 -0.328125 2.015625q0 1.328125 0.390625 2.328125q0.390625 1.0 1.21875 1.5q0.828125 0.484375 1.78125 0.484375q1.171875 0 1.96875 -0.671875q0.8125 -0.671875 1.09375 -1.984375zm1.9592896 3.671875l4.015625 -10.484375l1.5 0l4.296875 10.484375l-1.578125 0l-1.234375 -3.171875l-4.375 0l-1.15625 3.171875l-1.46875 0zm3.015625 -4.3125l3.5625 0l-1.09375 -2.90625q-0.5 -1.3125 -0.75 -2.171875q-0.203125 1.015625 -0.5625 2.0l-1.15625 3.078125z" fill-rule="nonzero"/><path fill="#eeeeee" d="m230.51805 31.208473l0 0c-0.97288513 -5.038681 2.2213287 -10.026669 8.227234 -12.847378c6.00589 -2.8207073 13.770187 -2.9794455 19.998184 -0.40885353l0 0c2.2061462 -2.929698 6.2440186 -4.9524527 10.892273 -5.456419c4.6482544 -0.5039673 9.360931 0.5700464 12.712494 2.897172l0 0c1.879364 -2.656252 5.569519 -4.440914 9.760986 -4.7206955c4.1914673 -0.27978134 8.291107 0.9849148 10.844086 3.3453083l0 0c3.3953247 -2.8156214 8.797394 -4.001115 13.868652 -3.0435104c5.071289 0.95760345 8.90094 3.8863096 9.831848 7.5188513l0 0c4.159851 0.7996483 7.6249084 2.8324604 9.499939 5.573221c1.8750305 2.7407627 1.9760742 5.9206104 0.27703857 8.717976l0 0c4.096222 3.7571678 5.0544434 8.76355 2.5170288 13.150848c-2.537384 4.3873024 -8.189178 7.49638 -14.846222 8.166988c-0.046936035 4.1176376 -3.2512817 7.8959312 -8.377991 9.878567c-5.1266785 1.9826317 -11.375153 1.8600044 -16.336975 -0.32061386l0 0c-2.1134644 4.931587 -8.062195 8.560196 -15.276093 9.318146c-7.213928 0.7579422 -14.39978 -1.490654 -18.453003 -5.774315l0 0c-4.968445 2.111435 -10.930145 2.7196655 -16.540268 1.6875c-5.610138 -1.0321579 -10.396133 -3.6177826 -13.278381 -7.1735954l0 0c-5.0771027 0.418705 -9.985977 -1.4350891 -12.290344 -4.6413574c-2.304367 -3.2062683 -1.5136871 -7.082466 1.9796295 -9.704857l0 0c-4.5289154 -1.8785515 -6.8398438 -5.606228 -5.727722 -9.239189c1.1121216 -3.6329575 5.395279 -6.3479595 10.615967 -6.7292366z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m225.52945 47.371098l0 0c2.137207 0.8864975 4.606186 1.2886314 7.075424 1.1524124m3.2341766 13.194122c1.0618744 -0.08757019 2.102707 -0.27301407 3.0956573 -0.551548m26.721512 6.0374146c-0.7468567 -0.78930664 -1.3721619 -1.6327438 -1.8652649 -2.515953m35.595642 -1.0280266l0 0c0.38531494 -0.89910126 0.63497925 -1.8244705 0.744812 -2.7606735m23.969208 -6.796936c0.049957275 -4.3838615 -3.4831543 -8.39777 -9.081787 -10.317635m21.410858 -10.999737c-0.90667725 1.4927864 -2.290802 2.8170204 -4.0438843 3.868866m-5.7322083 -18.160456l0 0c0.15447998 0.60282135 0.22598267 1.2147026 0.21350098 1.8271637m-23.913605 -6.3023224l0 0c-0.84695435 0.7023573 -1.5447693 1.4872332 -2.0716553 2.3301868m-18.5336 -0.9551058l0 0c-0.45135498 0.6379461 -0.78842163 1.3130026 -1.0033875 2.0096178m-22.601746 0.5496807l0 0c1.3178406 0.5439358 2.5370178 1.1986217 3.6307678 1.9496727m-31.85582 11.306631l0 0c0.13409424 0.6944599 0.34596252 1.3803596 0.6336365 2.0512772" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m230.51805 31.208473l0 0c-0.97288513 -5.038681 2.2213287 -10.026669 8.227234 -12.847378c6.00589 -2.8207073 13.770187 -2.9794455 19.998184 -0.40885353l0 0c2.2061462 -2.929698 6.2440186 -4.9524527 10.892273 -5.456419c4.6482544 -0.5039673 9.360931 0.5700464 12.712494 2.897172l0 0c1.879364 -2.656252 5.569519 -4.440914 9.760986 -4.7206955c4.1914673 -0.27978134 8.291107 0.9849148 10.844086 3.3453083l0 0c3.3953247 -2.8156214 8.797394 -4.001115 13.868652 -3.0435104c5.071289 0.95760345 8.90094 3.8863096 9.831848 7.5188513l0 0c4.159851 0.7996483 7.6249084 2.8324604 9.499939 5.573221c1.8750305 2.7407627 1.9760742 5.9206104 0.27703857 8.717976l0 0c4.096222 3.7571678 5.0544434 8.76355 2.5170288 13.150848c-2.537384 4.3873024 -8.189178 7.49638 -14.846222 8.166988c-0.046936035 4.1176376 -3.2512817 7.8959312 -8.377991 9.878567c-5.1266785 1.9826317 -11.375153 1.8600044 -16.336975 -0.32061386l0 0c-2.1134644 4.931587 -8.062195 8.560196 -15.276093 9.318146c-7.213928 0.7579422 -14.39978 -1.490654 -18.453003 -5.774315l0 0c-4.968445 2.111435 -10.930145 2.7196655 -16.540268 1.6875c-5.610138 -1.0321579 -10.396133 -3.6177826 -13.278381 -7.1735954l0 0c-5.0771027 0.418705 -9.985977 -1.4350891 -12.290344 -4.6413574c-2.304367 -3.2062683 -1.5136871 -7.082466 1.9796295 -9.704857l0 0c-4.5289154 -1.8785515 -6.8398438 -5.606228 -5.727722 -9.239189c1.1121216 -3.6329575 5.395279 -6.3479595 10.615967 -6.7292366z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m225.52945 47.371098l0 0c2.137207 0.8864975 4.606186 1.2886314 7.075424 1.1524124m3.2341766 13.194122c1.0618744 -0.08757019 2.102707 -0.27301407 3.0956573 -0.551548m26.721512 6.0374146c-0.7468567 -0.78930664 -1.3721619 -1.6327438 -1.8652649 -2.515953m35.595642 -1.0280266l0 0c0.38531494 -0.89910126 0.63497925 -1.8244705 0.744812 -2.7606735m23.969208 -6.796936c0.049957275 -4.3838615 -3.4831543 -8.39777 -9.081787 -10.317635m21.410858 -10.999737c-0.90667725 1.4927864 -2.290802 2.8170204 -4.0438843 3.868866m-5.7322083 -18.160456l0 0c0.15447998 0.60282135 0.22598267 1.2147026 0.21350098 1.8271637m-23.913605 -6.3023224l0 0c-0.84695435 0.7023573 -1.5447693 1.4872332 -2.0716553 2.3301868m-18.5336 -0.9551058l0 0c-0.45135498 0.6379461 -0.78842163 1.3130026 -1.0033875 2.0096178m-22.601746 0.5496807l0 0c1.3178406 0.5439358 2.5370178 1.1986217 3.6307678 1.9496727m-31.85582 11.306631l0 0c0.13409424 0.6944599 0.34596252 1.3803596 0.6336365 2.0512772" fill-rule="evenodd"/><path fill="#000000" d="m265.39542 36.29518l0 -10.484375l3.625 0q1.21875 0 1.859375 0.140625q0.90625 0.203125 1.546875 0.75q0.828125 0.703125 1.234375 1.796875q0.40625 1.09375 0.40625 2.5q0 1.1875 -0.28125 2.109375q-0.265625 0.921875 -0.703125 1.53125q-0.4375 0.609375 -0.96875 0.953125q-0.515625 0.34375 -1.25 0.53125q-0.71875 0.171875 -1.671875 0.171875l-3.796875 0zm1.390625 -1.234375l2.25 0q1.03125 0 1.625 -0.1875q0.59375 -0.203125 0.9375 -0.546875q0.5 -0.5 0.765625 -1.328125q0.28125 -0.84375 0.28125 -2.03125q0 -1.640625 -0.546875 -2.515625q-0.53125 -0.890625 -1.3125 -1.1875q-0.546875 -0.21875 -1.796875 -0.21875l-2.203125 0l0 8.015625zm9.162415 1.234375l0 -10.484375l2.078125 0l2.484375 7.421875q0.34375 1.03125 0.5 1.546875q0.1875 -0.5625 0.5625 -1.671875l2.515625 -7.296875l1.859375 0l0 10.484375l-1.328125 0l0 -8.78125l-3.046875 8.78125l-1.265625 0l-3.03125 -8.9375l0 8.9375l-1.328125 0z" fill-rule="nonzero"/><path fill="#000000" d="m254.73958 50.92018l1.3125153 -0.109375q0.09375 0.78125 0.421875 1.296875q0.34375 0.5 1.0625 0.8125q0.71875 0.3125 1.609375 0.3125q0.796875 0 1.40625 -0.234375q0.609375 -0.234375 0.90625 -0.640625q0.296875 -0.421875 0.296875 -0.90625q0 -0.5 -0.296875 -0.859375q-0.28125 -0.375 -0.9375 -0.625q-0.421875 -0.171875 -1.875 -0.515625q-1.4375 -0.34375 -2.015625 -0.65625q-0.75001526 -0.390625 -1.1250153 -0.96875q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.796875 0.4375 -1.484375q0.45314026 -0.6875 1.3125153 -1.046875q0.875 -0.359375 1.9375 -0.359375q1.171875 0 2.0625 0.375q0.890625 0.375 1.359375 1.109375q0.484375 0.734375 0.515625 1.65625l-1.328125 0.09375q-0.109375 -1.0 -0.734375 -1.5q-0.609375 -0.515625 -1.8125 -0.515625q-1.265625 0 -1.84375 0.46875q-0.578125 0.46875 -0.578125 1.109375q0 0.5625 0.421875 0.9375q0.390625 0.359375 2.078125 0.75q1.703125 0.375 2.328125 0.65625q0.921875 0.421875 1.359375 1.078125q0.4375 0.640625 0.4375 1.484375q0 0.84375 -0.484375 1.59375q-0.484375 0.734375 -1.390625 1.140625q-0.890625 0.40625 -2.015625 0.40625q-1.421875 0 -2.390625 -0.40625q-0.95314026 -0.421875 -1.5000153 -1.25q-0.546875 -0.828125 -0.578125 -1.890625zm15.2912445 0.921875l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375zm7.1667175 4.53125l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm7.0056458 0l-2.890625 -7.59375l1.359375 0l1.625 4.546875q0.265625 0.734375 0.5 1.53125q0.15625 -0.609375 0.46875 -1.453125l1.6875 -4.625l1.328125 0l-2.875 7.59375l-1.203125 0zm10.421875 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375zm7.166748 4.53125l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0z" fill-rule="nonzero"/><path fill="#eeeeee" d="m55.688976 213.79025l0 0c0 -12.559036 10.181118 -22.740158 22.740154 -22.740158c12.559044 0 22.740158 10.181122 22.740158 22.740158c0 12.5590515 -10.181114 22.740158 -22.740158 22.740158c-12.559036 0 -22.740154 -10.181107 -22.740154 -22.740158z" fill-rule="evenodd"/><path fill="#bebebe" d="m68.77509 206.98926c0 -1.3082275 1.0605316 -2.3687592 2.3687668 -2.3687592c1.3082352 0 2.3687668 1.0605316 2.3687668 2.3687592c0 1.3082428 -1.0605316 2.3687744 -2.3687668 2.3687744c-1.3082352 0 -2.3687668 -1.0605316 -2.3687668 -2.3687744m14.570549 0c0 -1.3082275 1.0605316 -2.3687592 2.3687668 -2.3687592c1.3082275 0 2.3687668 1.0605316 2.3687668 2.3687592c0 1.3082428 -1.0605392 2.3687744 -2.3687668 2.3687744c-1.3082352 0 -2.3687668 -1.0605316 -2.3687668 -2.3687744" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m66.10382 223.7074q12.32531 8.464783 24.621841 0" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m55.688976 213.79025l0 0c0 -12.559036 10.181118 -22.740158 22.740154 -22.740158c12.559044 0 22.740158 10.181122 22.740158 22.740158c0 12.5590515 -10.181114 22.740158 -22.740158 22.740158c-12.559036 0 -22.740154 -10.181107 -22.740154 -22.740158z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m68.77509 206.98926c0 -1.3082275 1.0605316 -2.3687592 2.3687668 -2.3687592c1.3082352 0 2.3687668 1.0605316 2.3687668 2.3687592c0 1.3082428 -1.0605316 2.3687744 -2.3687668 2.3687744c-1.3082352 0 -2.3687668 -1.0605316 -2.3687668 -2.3687744m14.570549 0c0 -1.3082275 1.0605316 -2.3687592 2.3687668 -2.3687592c1.3082275 0 2.3687668 1.0605316 2.3687668 2.3687592c0 1.3082428 -1.0605392 2.3687744 -2.3687668 2.3687744c-1.3082352 0 -2.3687668 -1.0605316 -2.3687668 -2.3687744" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m66.10382 223.7074q12.32531 8.464783 24.621841 0" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m55.688976 213.79025l0 0c0 -12.559036 10.181118 -22.740158 22.740154 -22.740158c12.559044 0 22.740158 10.181122 22.740158 22.740158c0 12.5590515 -10.181114 22.740158 -22.740158 22.740158c-12.559036 0 -22.740154 -10.181107 -22.740154 -22.740158z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m85.46175 198.4357l81.102356 0l0 30.708664l-81.102356 0z" fill-rule="evenodd"/><path fill="#000000" d="m115.21389 209.0131l0.59375 -0.046875q0.046875 0.359375 0.203125 0.59375q0.15625 0.21875 0.46875 0.359375q0.328125 0.140625 0.734375 0.140625q0.359375 0 0.640625 -0.109375q0.28125 -0.109375 0.40625 -0.296875q0.140625 -0.1875 0.140625 -0.40625q0 -0.21875 -0.140625 -0.390625q-0.125 -0.171875 -0.421875 -0.28125q-0.1875 -0.078125 -0.84375 -0.234375q-0.65625 -0.15625 -0.921875 -0.296875q-0.34375 -0.171875 -0.515625 -0.4375q-0.15625 -0.265625 -0.15625 -0.59375q0 -0.359375 0.203125 -0.671875q0.203125 -0.3125 0.59375 -0.46875q0.390625 -0.171875 0.875 -0.171875q0.53125 0 0.9375 0.171875q0.40625 0.171875 0.625 0.5q0.21875 0.328125 0.234375 0.75l-0.609375 0.046875q-0.046875 -0.453125 -0.328125 -0.6875q-0.28125 -0.234375 -0.828125 -0.234375q-0.578125 0 -0.84375 0.21875q-0.25 0.203125 -0.25 0.5q0 0.265625 0.1875 0.421875q0.171875 0.171875 0.9375 0.34375q0.78125 0.171875 1.0625 0.296875q0.421875 0.203125 0.609375 0.5q0.203125 0.28125 0.203125 0.671875q0 0.375 -0.21875 0.71875q-0.21875 0.328125 -0.625 0.515625q-0.40625 0.1875 -0.921875 0.1875q-0.640625 0 -1.078125 -0.1875q-0.4375 -0.1875 -0.6875 -0.5625q-0.25 -0.375 -0.265625 -0.859375zm4.5490417 2.859375l-0.0625 -0.546875q0.203125 0.046875 0.34375 0.046875q0.1875 0 0.296875 -0.0625q0.125 -0.0625 0.203125 -0.1875q0.046875 -0.078125 0.171875 -0.421875q0.015625 -0.0625 0.0625 -0.15625l-1.3125 -3.453125l0.625 0l0.71875 2.0q0.140625 0.375 0.25 0.796875q0.109375 -0.40625 0.25 -0.78125l0.734375 -2.015625l0.578125 0l-1.3125 3.515625q-0.203125 0.5625 -0.328125 0.78125q-0.15625 0.28125 -0.359375 0.421875q-0.203125 0.140625 -0.46875 0.140625q-0.171875 0 -0.390625 -0.078125zm3.125 -2.359375l0.578125 -0.09375q0.046875 0.34375 0.265625 0.53125q0.234375 0.1875 0.625 0.1875q0.40625 0 0.59375 -0.15625q0.203125 -0.171875 0.203125 -0.390625q0 -0.203125 -0.171875 -0.3125q-0.125 -0.078125 -0.59375 -0.203125q-0.640625 -0.15625 -0.890625 -0.265625q-0.25 -0.125 -0.390625 -0.328125q-0.125 -0.21875 -0.125 -0.46875q0 -0.234375 0.109375 -0.421875q0.109375 -0.203125 0.296875 -0.34375q0.125 -0.09375 0.359375 -0.15625q0.234375 -0.078125 0.515625 -0.078125q0.40625 0 0.703125 0.125q0.3125 0.109375 0.453125 0.3125q0.15625 0.203125 0.203125 0.53125l-0.5625 0.078125q-0.046875 -0.265625 -0.234375 -0.40625q-0.1875 -0.15625 -0.53125 -0.15625q-0.390625 0 -0.5625 0.140625q-0.171875 0.125 -0.171875 0.296875q0 0.125 0.0625 0.203125q0.078125 0.109375 0.21875 0.15625q0.09375 0.046875 0.53125 0.15625q0.609375 0.171875 0.859375 0.28125q0.25 0.09375 0.390625 0.296875q0.140625 0.203125 0.140625 0.5q0 0.296875 -0.171875 0.5625q-0.171875 0.25 -0.5 0.390625q-0.3125 0.140625 -0.71875 0.140625q-0.6875 0 -1.046875 -0.28125q-0.34375 -0.28125 -0.4375 -0.828125zm4.84375 0.515625l0.078125 0.515625q-0.25 0.046875 -0.4375 0.046875q-0.3125 0 -0.5 -0.09375q-0.171875 -0.109375 -0.25 -0.265625q-0.0625 -0.171875 -0.0625 -0.703125l0 -1.984375l-0.4375 0l0 -0.453125l0.4375 0l0 -0.859375l0.578125 -0.34375l0 1.203125l0.59375 0l0 0.453125l-0.59375 0l0 2.015625q0 0.25 0.03125 0.328125q0.03125 0.078125 0.09375 0.125q0.078125 0.03125 0.203125 0.03125q0.109375 0 0.265625 -0.015625zm2.9274368 -0.59375l0.609375 0.078125q-0.140625 0.53125 -0.53125 0.828125q-0.390625 0.28125 -0.984375 0.28125q-0.765625 0 -1.203125 -0.46875q-0.4375 -0.46875 -0.4375 -1.3125q0 -0.859375 0.4375 -1.34375q0.453125 -0.484375 1.171875 -0.484375q0.6875 0 1.125 0.46875q0.4375 0.46875 0.4375 1.328125q0 0.046875 0 0.15625l-2.578125 0q0.03125 0.578125 0.3125 0.875q0.296875 0.296875 0.734375 0.296875q0.328125 0 0.546875 -0.15625q0.234375 -0.171875 0.359375 -0.546875zm-1.921875 -0.953125l1.9375 0q-0.046875 -0.4375 -0.21875 -0.640625q-0.28125 -0.34375 -0.734375 -0.34375q-0.40625 0 -0.6875 0.265625q-0.265625 0.265625 -0.296875 0.71875zm3.264389 2.0625l0 -3.453125l0.53125 0l0 0.484375q0.15625 -0.25 0.421875 -0.40625q0.28125 -0.15625 0.625 -0.15625q0.375 0 0.625 0.15625q0.25 0.15625 0.34375 0.453125q0.40625 -0.609375 1.0625 -0.609375q0.515625 0 0.78125 0.296875q0.28125 0.28125 0.28125 0.859375l0 2.375l-0.578125 0l0 -2.171875q0 -0.359375 -0.0625 -0.5q-0.046875 -0.15625 -0.203125 -0.25q-0.140625 -0.09375 -0.34375 -0.09375q-0.359375 0 -0.609375 0.25q-0.234375 0.234375 -0.234375 0.765625l0 2.0l-0.59375 0l0 -2.25q0 -0.375 -0.140625 -0.5625q-0.140625 -0.203125 -0.46875 -0.203125q-0.25 0 -0.453125 0.125q-0.203125 0.125 -0.296875 0.375q-0.09375 0.25 -0.09375 0.71875l0 1.796875l-0.59375 0z" fill-rule="nonzero"/><path fill="#000000" d="m106.39257 218.54436l1.828125 -4.765625l0.6875 0l1.953125 4.765625l-0.71875 0l-0.5625 -1.4375l-1.984375 0l-0.53125 1.4375l-0.671875 0zm1.375 -1.953125l1.625 0l-0.5 -1.328125q-0.234375 -0.59375 -0.34375 -0.984375q-0.09375 0.453125 -0.25 0.90625l-0.53125 1.40625zm5.7521667 1.953125l0 -0.4375q-0.328125 0.515625 -0.953125 0.515625q-0.421875 0 -0.765625 -0.21875q-0.34375 -0.234375 -0.53125 -0.640625q-0.1875 -0.40625 -0.1875 -0.9375q0 -0.515625 0.171875 -0.9375q0.171875 -0.421875 0.515625 -0.640625q0.34375 -0.234375 0.765625 -0.234375q0.3125 0 0.546875 0.140625q0.25 0.125 0.40625 0.328125l0 -1.703125l0.578125 0l0 4.765625l-0.546875 0zm-1.84375 -1.71875q0 0.65625 0.28125 0.984375q0.28125 0.328125 0.65625 0.328125q0.390625 0 0.65625 -0.3125q0.265625 -0.3125 0.265625 -0.953125q0 -0.703125 -0.28125 -1.03125q-0.265625 -0.34375 -0.671875 -0.34375q-0.375 0 -0.640625 0.328125q-0.265625 0.3125 -0.265625 1.0zm3.311264 1.71875l0 -3.453125l0.53125 0l0 0.484375q0.15625 -0.25 0.421875 -0.40625q0.28125 -0.15625 0.625 -0.15625q0.375 0 0.625 0.15625q0.25 0.15625 0.34375 0.453125q0.40625 -0.609375 1.0625 -0.609375q0.515625 0 0.78125 0.296875q0.28125 0.28125 0.28125 0.859375l0 2.375l-0.578125 0l0 -2.171875q0 -0.359375 -0.0625 -0.5q-0.046875 -0.15625 -0.203125 -0.25q-0.140625 -0.09375 -0.34375 -0.09375q-0.359375 0 -0.609375 0.25q-0.234375 0.234375 -0.234375 0.765625l0 2.0l-0.59375 0l0 -2.25q0 -0.375 -0.140625 -0.5625q-0.140625 -0.203125 -0.46875 -0.203125q-0.25 0 -0.453125 0.125q-0.203125 0.125 -0.296875 0.375q-0.09375 0.25 -0.09375 0.71875l0 1.796875l-0.59375 0zm5.5447083 -4.09375l0 -0.671875l0.59375 0l0 0.671875l-0.59375 0zm0 4.09375l0 -3.453125l0.59375 0l0 3.453125l-0.59375 0zm1.4788055 0l0 -3.453125l0.53125 0l0 0.5q0.375 -0.578125 1.09375 -0.578125q0.3125 0 0.578125 0.109375q0.265625 0.109375 0.390625 0.296875q0.125 0.1875 0.1875 0.4375q0.03125 0.15625 0.03125 0.5625l0 2.125l-0.59375 0l0 -2.09375q0 -0.359375 -0.078125 -0.53125q-0.0625 -0.1875 -0.234375 -0.28125q-0.171875 -0.109375 -0.40625 -0.109375q-0.375 0 -0.640625 0.234375q-0.265625 0.234375 -0.265625 0.890625l0 1.890625l-0.59375 0zm3.701889 -4.09375l0 -0.671875l0.59375 0l0 0.671875l-0.59375 0zm0 4.09375l0 -3.453125l0.59375 0l0 3.453125l-0.59375 0zm1.2444305 -1.03125l0.578125 -0.09375q0.046875 0.34375 0.265625 0.53125q0.23436737 0.1875 0.6249924 0.1875q0.40625 0 0.59375 -0.15625q0.203125 -0.171875 0.203125 -0.390625q0 -0.203125 -0.171875 -0.3125q-0.125 -0.078125 -0.59375 -0.203125q-0.6406174 -0.15625 -0.8906174 -0.265625q-0.25 -0.125 -0.390625 -0.328125q-0.125 -0.21875 -0.125 -0.46875q0 -0.234375 0.109375 -0.421875q0.109375 -0.203125 0.296875 -0.34375q0.125 -0.09375 0.359375 -0.15625q0.23436737 -0.078125 0.5156174 -0.078125q0.40625 0 0.703125 0.125q0.3125 0.109375 0.453125 0.3125q0.15625 0.203125 0.203125 0.53125l-0.5625 0.078125q-0.046875 -0.265625 -0.234375 -0.40625q-0.1875 -0.15625 -0.53125 -0.15625q-0.39061737 0 -0.5624924 0.140625q-0.171875 0.125 -0.171875 0.296875q0 0.125 0.0625 0.203125q0.078125 0.109375 0.21875 0.15625q0.09374237 0.046875 0.5312424 0.15625q0.609375 0.171875 0.859375 0.28125q0.25 0.09375 0.390625 0.296875q0.140625 0.203125 0.140625 0.5q0 0.296875 -0.171875 0.5625q-0.171875 0.25 -0.5 0.390625q-0.3125 0.140625 -0.71875 0.140625q-0.6874924 0 -1.0468674 -0.28125q-0.34375 -0.28125 -0.4375 -0.828125zm4.8437424 0.515625l0.078125 0.515625q-0.25 0.046875 -0.4375 0.046875q-0.3125 0 -0.5 -0.09375q-0.171875 -0.109375 -0.25 -0.265625q-0.0625 -0.171875 -0.0625 -0.703125l0 -1.984375l-0.4375 0l0 -0.453125l0.4375 0l0 -0.859375l0.578125 -0.34375l0 1.203125l0.59375 0l0 0.453125l-0.59375 0l0 2.015625q0 0.25 0.03125 0.328125q0.03125 0.078125 0.09375 0.125q0.078125 0.03125 0.203125 0.03125q0.109375 0 0.265625 -0.015625zm0.56806946 0.515625l0 -3.453125l0.515625 0l0 0.53125q0.203125 -0.375 0.375 -0.484375q0.171875 -0.125 0.375 -0.125q0.296875 0 0.609375 0.1875l-0.203125 0.546875q-0.21875 -0.125 -0.4375 -0.125q-0.1875 0 -0.34375 0.125q-0.140625 0.109375 -0.21875 0.3125q-0.09375 0.3125 -0.09375 0.671875l0 1.8125l-0.578125 0zm4.4665833 -0.421875q-0.328125 0.265625 -0.625 0.390625q-0.296875 0.109375 -0.640625 0.109375q-0.578125 0 -0.890625 -0.28125q-0.296875 -0.28125 -0.296875 -0.703125q0 -0.25 0.109375 -0.453125q0.125 -0.21875 0.3125 -0.34375q0.1875 -0.140625 0.421875 -0.203125q0.171875 -0.046875 0.515625 -0.078125q0.71875 -0.09375 1.046875 -0.203125q0 -0.125 0 -0.15625q0 -0.359375 -0.15625 -0.5q-0.234375 -0.203125 -0.671875 -0.203125q-0.40625 0 -0.609375 0.15625q-0.203125 0.140625 -0.296875 0.5l-0.5625 -0.078125q0.078125 -0.359375 0.25 -0.578125q0.1875 -0.234375 0.515625 -0.359375q0.34375 -0.125 0.78125 -0.125q0.453125 0 0.71875 0.109375q0.28125 0.09375 0.40625 0.265625q0.140625 0.15625 0.1875 0.390625q0.03125 0.15625 0.03125 0.546875l0 0.765625q0 0.828125 0.03125 1.046875q0.046875 0.203125 0.15625 0.40625l-0.609375 0q-0.09375 -0.1875 -0.125 -0.421875zm-0.046875 -1.3125q-0.3125 0.125 -0.953125 0.21875q-0.359375 0.0625 -0.515625 0.125q-0.140625 0.0625 -0.234375 0.1875q-0.078125 0.125 -0.078125 0.28125q0 0.234375 0.171875 0.390625q0.1875 0.15625 0.53125 0.15625q0.328125 0 0.59375 -0.140625q0.265625 -0.15625 0.390625 -0.421875q0.09375 -0.1875 0.09375 -0.578125l0 -0.21875zm2.780014 1.21875l0.078125 0.515625q-0.25 0.046875 -0.4375 0.046875q-0.3125 0 -0.5 -0.09375q-0.171875 -0.109375 -0.25 -0.265625q-0.0625 -0.171875 -0.0625 -0.703125l0 -1.984375l-0.4375 0l0 -0.453125l0.4375 0l0 -0.859375l0.578125 -0.34375l0 1.203125l0.59375 0l0 0.453125l-0.59375 0l0 2.015625q0 0.25 0.03125 0.328125q0.03125 0.078125 0.09375 0.125q0.078125 0.03125 0.203125 0.03125q0.109375 0 0.265625 -0.015625zm0.34931946 -1.203125q0 -0.96875 0.53125 -1.421875q0.453125 -0.390625 1.09375 -0.390625q0.703125 0 1.15625 0.46875q0.453125 0.46875 0.453125 1.28125q0 0.671875 -0.203125 1.0625q-0.1875 0.375 -0.578125 0.59375q-0.375 0.203125 -0.828125 0.203125q-0.734375 0 -1.1875 -0.453125q-0.4375 -0.46875 -0.4375 -1.34375zm0.609375 0q0 0.65625 0.28125 0.984375q0.296875 0.328125 0.734375 0.328125q0.4375 0 0.71875 -0.328125q0.296875 -0.328125 0.296875 -1.015625q0 -0.640625 -0.296875 -0.96875q-0.296875 -0.328125 -0.71875 -0.328125q-0.4375 0 -0.734375 0.328125q-0.28125 0.328125 -0.28125 1.0zm3.311264 1.71875l0 -3.453125l0.515625 0l0 0.53125q0.203125 -0.375 0.375 -0.484375q0.171875 -0.125 0.375 -0.125q0.296875 0 0.609375 0.1875l-0.203125 0.546875q-0.21875 -0.125 -0.4375 -0.125q-0.1875 0 -0.34375 0.125q-0.140625 0.109375 -0.21875 0.3125q-0.09375 0.3125 -0.09375 0.671875l0 1.8125l-0.578125 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m186.52493 326.51523l0 0c0 -21.856995 17.718597 -39.575592 39.575592 -39.575592l336.78583 0c10.496094 0 20.562317 4.1695557 27.984192 11.591431c7.421814 7.4218445 11.59137 17.488068 11.59137 27.984161l0 158.29764c0 21.856995 -17.718567 39.57556 -39.57556 39.57556l-336.78583 0c-21.856995 0 -39.575592 -17.718567 -39.575592 -39.57556z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" stroke-dasharray="4.0,3.0" d="m186.52493 326.51523l0 0c0 -21.856995 17.718597 -39.575592 39.575592 -39.575592l336.78583 0c10.496094 0 20.562317 4.1695557 27.984192 11.591431c7.421814 7.4218445 11.59137 17.488068 11.59137 27.984161l0 158.29764c0 21.856995 -17.718567 39.57556 -39.57556 39.57556l-336.78583 0c-21.856995 0 -39.575592 -17.718567 -39.575592 -39.57556z" fill-rule="evenodd"/><path fill="#cfe2f3" d="m452.7373 333.36594l0 0c0 -16.300842 28.499023 -29.51529 63.654358 -29.51529c35.155334 0 63.654358 13.214447 63.654358 29.51529l0 118.06125c0 16.300842 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214478 -63.654358 -29.51532z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m580.046 333.36594l0 0c0 16.300873 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214447 -63.654358 -29.51532" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m452.7373 333.36594l0 0c0 -16.300842 28.499023 -29.51529 63.654358 -29.51529c35.155334 0 63.654358 13.214447 63.654358 29.51529l0 118.06125c0 16.300842 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214478 -63.654358 -29.51532z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m580.046 333.36594l0 0c0 16.300873 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214447 -63.654358 -29.51532" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m452.7373 333.36594l0 0c0 -16.300842 28.499023 -29.51529 63.654358 -29.51529c35.155334 0 63.654358 13.214447 63.654358 29.51529l0 118.06125c0 16.300842 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214478 -63.654358 -29.51532z" fill-rule="evenodd"/><path fill="#cfe2f3" d="m212.98264 334.4678l0 0c0 -16.300842 28.499023 -29.51529 63.654358 -29.51529c35.155334 0 63.654358 13.214447 63.654358 29.51529l0 118.06125c0 16.300873 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214447 -63.654358 -29.51532z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m340.29135 334.4678l0 0c0 16.300873 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214447 -63.654358 -29.51532" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m212.98264 334.4678l0 0c0 -16.300842 28.499023 -29.51529 63.654358 -29.51529c35.155334 0 63.654358 13.214447 63.654358 29.51529l0 118.06125c0 16.300873 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214447 -63.654358 -29.51532z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m340.29135 334.4678l0 0c0 16.300873 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214447 -63.654358 -29.51532" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m212.98264 334.4678l0 0c0 -16.300842 28.499023 -29.51529 63.654358 -29.51529c35.155334 0 63.654358 13.214447 63.654358 29.51529l0 118.06125c0 16.300873 -28.499023 29.51532 -63.654358 29.51532c-35.155334 0 -63.654358 -13.214447 -63.654358 -29.51532z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m186.52473 452.66666l415.937 0l0 69.480316l-415.937 0z" fill-rule="evenodd"/><path fill="#595959" d="m326.31332 510.387l0 -7.625l2.625 0q0.890625 0 1.359375 0.109375q0.65625 0.140625 1.109375 0.546875q0.609375 0.5 0.90625 1.296875q0.296875 0.796875 0.296875 1.8125q0 0.875 -0.203125 1.546875q-0.203125 0.671875 -0.515625 1.109375q-0.3125 0.4375 -0.703125 0.6875q-0.375 0.25 -0.90625 0.390625q-0.53125 0.125 -1.21875 0.125l-2.75 0zm1.0 -0.90625l1.625 0q0.765625 0 1.1875 -0.140625q0.4375 -0.140625 0.6875 -0.390625q0.359375 -0.359375 0.5625 -0.953125q0.203125 -0.609375 0.203125 -1.484375q0 -1.1875 -0.40625 -1.828125q-0.390625 -0.65625 -0.953125 -0.875q-0.40625 -0.15625 -1.296875 -0.15625l-1.609375 0l0 5.828125zm10.351837 -0.875l0.96875 0.125q-0.234375 0.84375 -0.859375 1.3125q-0.609375 0.46875 -1.578125 0.46875q-1.203125 0 -1.921875 -0.75q-0.703125 -0.75 -0.703125 -2.09375q0 -1.390625 0.71875 -2.15625q0.71875 -0.78125 1.859375 -0.78125q1.109375 0 1.8125 0.765625q0.703125 0.75 0.703125 2.125q0 0.078125 0 0.234375l-4.125 0q0.046875 0.921875 0.515625 1.40625q0.46875 0.484375 1.15625 0.484375q0.515625 0 0.875 -0.265625q0.359375 -0.28125 0.578125 -0.875zm-3.078125 -1.515625l3.09375 0q-0.0625 -0.6875 -0.359375 -1.046875q-0.453125 -0.53125 -1.15625 -0.53125q-0.640625 0 -1.09375 0.4375q-0.4375 0.421875 -0.484375 1.140625zm6.7546387 3.296875l-2.09375 -5.53125l0.984375 0l1.1875 3.3125q0.1875 0.53125 0.359375 1.109375q0.109375 -0.4375 0.34375 -1.046875l1.21875 -3.375l0.96875 0l-2.09375 5.53125l-0.875 0zm3.796875 -6.546875l0 -1.078125l0.9375 0l0 1.078125l-0.9375 0zm0 6.546875l0 -5.53125l0.9375 0l0 5.53125l-0.9375 0zm5.976837 -2.03125l0.921875 0.125q-0.15625 0.953125 -0.78125 1.5q-0.625 0.53125 -1.53125 0.53125q-1.125 0 -1.8125 -0.734375q-0.6875 -0.75 -0.6875 -2.125q0 -0.90625 0.296875 -1.578125q0.296875 -0.671875 0.890625 -1.0q0.609375 -0.34375 1.328125 -0.34375q0.890625 0 1.46875 0.46875q0.578125 0.453125 0.734375 1.28125l-0.90625 0.140625q-0.140625 -0.546875 -0.46875 -0.828125q-0.328125 -0.28125 -0.796875 -0.28125q-0.703125 0 -1.15625 0.515625q-0.4375 0.5 -0.4375 1.59375q0 1.109375 0.421875 1.625q0.4375 0.5 1.125 0.5q0.546875 0 0.90625 -0.34375q0.375 -0.34375 0.484375 -1.046875zm5.5 0.25l0.96875 0.125q-0.234375 0.84375 -0.859375 1.3125q-0.609375 0.46875 -1.578125 0.46875q-1.203125 0 -1.921875 -0.75q-0.703125 -0.75 -0.703125 -2.09375q0 -1.390625 0.71875 -2.15625q0.71875 -0.78125 1.859375 -0.78125q1.109375 0 1.8125 0.765625q0.703125 0.75 0.703125 2.125q0 0.078125 0 0.234375l-4.125 0q0.046875 0.921875 0.515625 1.40625q0.46875 0.484375 1.15625 0.484375q0.515625 0 0.875 -0.265625q0.359375 -0.28125 0.578125 -0.875zm-3.078125 -1.515625l3.09375 0q-0.0625 -0.6875 -0.359375 -1.046875q-0.453125 -0.53125 -1.15625 -0.53125q-0.640625 0 -1.09375 0.4375q-0.4375 0.421875 -0.484375 1.140625zm8.277771 3.296875l0 -7.625l1.515625 0l1.796875 5.390625q0.25 0.765625 0.375 1.140625q0.125 -0.421875 0.40625 -1.234375l1.828125 -5.296875l1.34375 0l0 7.625l-0.96875 0l0 -6.390625l-2.21875 6.390625l-0.90625 0l-2.203125 -6.5l0 6.5l-0.96875 0zm12.3923645 -0.6875q-0.53125 0.453125 -1.015625 0.640625q-0.46875 0.171875 -1.015625 0.171875q-0.921875 0 -1.40625 -0.4375q-0.484375 -0.453125 -0.484375 -1.140625q0 -0.40625 0.171875 -0.734375q0.1875 -0.34375 0.484375 -0.546875q0.3125 -0.203125 0.6875 -0.3125q0.265625 -0.0625 0.828125 -0.140625q1.125 -0.125 1.671875 -0.3125q0 -0.203125 0 -0.25q0 -0.578125 -0.265625 -0.8125q-0.359375 -0.3125 -1.0625 -0.3125q-0.65625 0 -0.984375 0.234375q-0.3125 0.234375 -0.453125 0.8125l-0.921875 -0.125q0.125 -0.578125 0.40625 -0.9375q0.296875 -0.375 0.828125 -0.5625q0.546875 -0.203125 1.25 -0.203125q0.71875 0 1.15625 0.171875q0.4375 0.171875 0.640625 0.421875q0.21875 0.25 0.296875 0.640625q0.046875 0.234375 0.046875 0.859375l0 1.25q0 1.296875 0.0625 1.65625q0.0625 0.34375 0.234375 0.65625l-0.96875 0q-0.15625 -0.296875 -0.1875 -0.6875zm-0.078125 -2.078125q-0.515625 0.203125 -1.53125 0.34375q-0.578125 0.078125 -0.828125 0.1875q-0.234375 0.109375 -0.359375 0.3125q-0.125 0.1875 -0.125 0.4375q0 0.375 0.28125 0.625q0.28125 0.25 0.828125 0.25q0.53125 0 0.953125 -0.234375q0.421875 -0.234375 0.625 -0.65625q0.15625 -0.3125 0.15625 -0.9375l0 -0.328125zm2.3952637 2.765625l0 -5.53125l0.84375 0l0 0.796875q0.609375 -0.921875 1.75 -0.921875q0.5 0 0.921875 0.1875q0.421875 0.171875 0.625 0.46875q0.21875 0.296875 0.296875 0.6875q0.046875 0.265625 0.046875 0.921875l0 3.390625l-0.9375 0l0 -3.359375q0 -0.578125 -0.109375 -0.859375q-0.109375 -0.28125 -0.390625 -0.453125q-0.265625 -0.171875 -0.640625 -0.171875q-0.59375 0 -1.03125 0.390625q-0.4375 0.375 -0.4375 1.4375l0 3.015625l-0.9375 0zm9.535858 -0.6875q-0.53125 0.453125 -1.015625 0.640625q-0.46875 0.171875 -1.015625 0.171875q-0.921875 0 -1.40625 -0.4375q-0.484375 -0.453125 -0.484375 -1.140625q0 -0.40625 0.171875 -0.734375q0.1875 -0.34375 0.484375 -0.546875q0.3125 -0.203125 0.6875 -0.3125q0.265625 -0.0625 0.828125 -0.140625q1.125 -0.125 1.671875 -0.3125q0 -0.203125 0 -0.25q0 -0.578125 -0.265625 -0.8125q-0.359375 -0.3125 -1.0625 -0.3125q-0.65625 0 -0.984375 0.234375q-0.3125 0.234375 -0.453125 0.8125l-0.921875 -0.125q0.125 -0.578125 0.40625 -0.9375q0.296875 -0.375 0.828125 -0.5625q0.546875 -0.203125 1.25 -0.203125q0.71875 0 1.15625 0.171875q0.4375 0.171875 0.640625 0.421875q0.21875 0.25 0.296875 0.640625q0.046875 0.234375 0.046875 0.859375l0 1.25q0 1.296875 0.0625 1.65625q0.0625 0.34375 0.234375 0.65625l-0.96875 0q-0.15625 -0.296875 -0.1875 -0.6875zm-0.078125 -2.078125q-0.515625 0.203125 -1.53125 0.34375q-0.578125 0.078125 -0.828125 0.1875q-0.234375 0.109375 -0.359375 0.3125q-0.125 0.1875 -0.125 0.4375q0 0.375 0.28125 0.625q0.28125 0.25 0.828125 0.25q0.53125 0 0.953125 -0.234375q0.421875 -0.234375 0.625 -0.65625q0.15625 -0.3125 0.15625 -0.9375l0 -0.328125zm2.2233887 3.21875l0.90625 0.140625q0.0625 0.421875 0.328125 0.609375q0.34375 0.265625 0.9375 0.265625q0.65625 0 1.0 -0.265625q0.359375 -0.25 0.484375 -0.71875q0.078125 -0.296875 0.078125 -1.203125q-0.625 0.71875 -1.53125 0.71875q-1.140625 0 -1.765625 -0.8125q-0.625 -0.828125 -0.625 -1.984375q0 -0.78125 0.28125 -1.453125q0.296875 -0.671875 0.828125 -1.03125q0.546875 -0.375 1.28125 -0.375q0.984375 0 1.609375 0.796875l0 -0.671875l0.875 0l0 4.78125q0 1.296875 -0.265625 1.828125q-0.265625 0.5468445 -0.84375 0.8593445q-0.5625 0.3125 -1.390625 0.3125q-0.984375 0 -1.59375 -0.453125q-0.609375 -0.43746948 -0.59375 -1.3437195zm0.78125 -3.3125q0 1.078125 0.421875 1.578125q0.4375 0.5 1.078125 0.5q0.65625 0 1.09375 -0.484375q0.4375 -0.5 0.4375 -1.5625q0 -1.015625 -0.453125 -1.53125q-0.453125 -0.515625 -1.09375 -0.515625q-0.609375 0 -1.046875 0.515625q-0.4375 0.5 -0.4375 1.5zm9.098358 1.078125l0.96875 0.125q-0.234375 0.84375 -0.859375 1.3125q-0.609375 0.46875 -1.578125 0.46875q-1.203125 0 -1.921875 -0.75q-0.703125 -0.75 -0.703125 -2.09375q0 -1.390625 0.71875 -2.15625q0.71875 -0.78125 1.859375 -0.78125q1.109375 0 1.8125 0.765625q0.703125 0.75 0.703125 2.125q0 0.078125 0 0.234375l-4.125 0q0.046875 0.921875 0.515625 1.40625q0.46875 0.484375 1.15625 0.484375q0.515625 0 0.875 -0.265625q0.359375 -0.28125 0.578125 -0.875zm-3.078125 -1.515625l3.09375 0q-0.0625 -0.6875 -0.359375 -1.046875q-0.453125 -0.53125 -1.15625 -0.53125q-0.640625 0 -1.09375 0.4375q-0.4375 0.421875 -0.484375 1.140625zm5.2233887 3.296875l0 -5.53125l0.84375 0l0 0.78125q0.25 -0.40625 0.6875 -0.65625q0.4375 -0.25 0.984375 -0.25q0.609375 0 1.0 0.265625q0.390625 0.25 0.5625 0.703125q0.65625 -0.96875 1.703125 -0.96875q0.828125 0 1.265625 0.46875q0.4375 0.453125 0.4375 1.390625l0 3.796875l-0.921875 0l0 -3.484375q0 -0.5625 -0.09375 -0.796875q-0.09375 -0.25 -0.34375 -0.40625q-0.234375 -0.15625 -0.546875 -0.15625q-0.59375 0 -0.984375 0.390625q-0.375 0.390625 -0.375 1.25l0 3.203125l-0.9375 0l0 -3.59375q0 -0.625 -0.234375 -0.9375q-0.21875 -0.3125 -0.75 -0.3125q-0.390625 0 -0.734375 0.21875q-0.328125 0.203125 -0.484375 0.609375q-0.140625 0.390625 -0.140625 1.15625l0 2.859375l-0.9375 0zm12.6579895 -1.78125l0.96875 0.125q-0.234375 0.84375 -0.859375 1.3125q-0.609375 0.46875 -1.578125 0.46875q-1.203125 0 -1.921875 -0.75q-0.703125 -0.75 -0.703125 -2.09375q0 -1.390625 0.71875 -2.15625q0.71875 -0.78125 1.859375 -0.78125q1.109375 0 1.8125 0.765625q0.703125 0.75 0.703125 2.125q0 0.078125 0 0.234375l-4.125 0q0.046875 0.921875 0.515625 1.40625q0.46875 0.484375 1.15625 0.484375q0.515625 0 0.875 -0.265625q0.359375 -0.28125 0.578125 -0.875zm-3.078125 -1.515625l3.09375 0q-0.0625 -0.6875 -0.359375 -1.046875q-0.453125 -0.53125 -1.15625 -0.53125q-0.640625 0 -1.09375 0.4375q-0.4375 0.421875 -0.484375 1.140625zm5.223358 3.296875l0 -5.53125l0.84375 0l0 0.796875q0.609375 -0.921875 1.75 -0.921875q0.5 0 0.921875 0.1875q0.421875 0.171875 0.625 0.46875q0.21875 0.296875 0.296875 0.6875q0.046875 0.265625 0.046875 0.921875l0 3.390625l-0.9375 0l0 -3.359375q0 -0.578125 -0.109375 -0.859375q-0.109375 -0.28125 -0.390625 -0.453125q-0.265625 -0.171875 -0.640625 -0.171875q-0.59375 0 -1.03125 0.390625q-0.4375 0.375 -0.4375 1.4375l0 3.015625l-0.9375 0zm7.9733887 -0.84375l0.125 0.828125q-0.390625 0.09375 -0.703125 0.09375q-0.5 0 -0.78125 -0.15625q-0.28125 -0.171875 -0.40625 -0.4375q-0.109375 -0.265625 -0.109375 -1.109375l0 -3.171875l-0.6875 0l0 -0.734375l0.6875 0l0 -1.359375l0.9375 -0.5625l0 1.921875l0.9375 0l0 0.734375l-0.9375 0l0 3.234375q0 0.390625 0.046875 0.515625q0.046875 0.109375 0.15625 0.1875q0.109375 0.0625 0.328125 0.0625q0.15625 0 0.40625 -0.046875zm3.6556702 -1.609375l0.953125 -0.078125q0.0625 0.5625 0.3125 0.9375q0.25 0.359375 0.765625 0.59375q0.515625 0.21875 1.171875 0.21875q0.578125 0 1.015625 -0.171875q0.4375 -0.171875 0.65625 -0.46875q0.21875 -0.296875 0.21875 -0.65625q0 -0.359375 -0.21875 -0.625q-0.203125 -0.265625 -0.671875 -0.4375q-0.3125 -0.125 -1.359375 -0.375q-1.046875 -0.25 -1.46875 -0.484375q-0.546875 -0.28125 -0.828125 -0.703125q-0.265625 -0.421875 -0.265625 -0.953125q0 -0.578125 0.328125 -1.078125q0.328125 -0.5 0.953125 -0.765625q0.640625 -0.265625 1.40625 -0.265625q0.84375 0 1.484375 0.28125q0.65625 0.265625 1.0 0.796875q0.359375 0.53125 0.390625 1.203125l-0.96875 0.078125q-0.078125 -0.71875 -0.53125 -1.09375q-0.453125 -0.375 -1.328125 -0.375q-0.921875 0 -1.34375 0.34375q-0.40625 0.328125 -0.40625 0.8125q0 0.40625 0.296875 0.671875q0.28125 0.265625 1.515625 0.546875q1.234375 0.28125 1.6875 0.484375q0.671875 0.3125 0.984375 0.78125q0.3125 0.46875 0.3125 1.078125q0 0.609375 -0.34375 1.15625q-0.34375 0.53125 -1.0 0.828125q-0.65625 0.296875 -1.46875 0.296875q-1.046875 0 -1.75 -0.296875q-0.6875 -0.296875 -1.09375 -0.90625q-0.390625 -0.609375 -0.40625 -1.375zm9.3732605 1.609375l0.125 0.828125q-0.390625 0.09375 -0.703125 0.09375q-0.5 0 -0.78125 -0.15625q-0.28125 -0.171875 -0.40625 -0.4375q-0.109375 -0.265625 -0.109375 -1.109375l0 -3.171875l-0.6875 0l0 -0.734375l0.6875 0l0 -1.359375l0.9375 -0.5625l0 1.921875l0.9375 0l0 0.734375l-0.9375 0l0 3.234375q0 0.390625 0.046875 0.515625q0.046875 0.109375 0.15625 0.1875q0.109375 0.0625 0.328125 0.0625q0.15625 0 0.40625 -0.046875zm0.5700073 -1.921875q0 -1.53125 0.84375 -2.265625q0.71875 -0.625 1.734375 -0.625q1.140625 0 1.859375 0.75q0.734375 0.75 0.734375 2.0625q0 1.0625 -0.328125 1.6875q-0.3125 0.609375 -0.921875 0.953125q-0.609375 0.328125 -1.34375 0.328125q-1.15625 0 -1.875 -0.734375q-0.703125 -0.75 -0.703125 -2.15625zm0.953125 0q0 1.0625 0.46875 1.59375q0.46875 0.53125 1.15625 0.53125q0.703125 0 1.15625 -0.53125q0.46875 -0.53125 0.46875 -1.625q0 -1.015625 -0.46875 -1.546875q-0.453125 -0.53125 -1.15625 -0.53125q-0.6875 0 -1.15625 0.53125q-0.46875 0.515625 -0.46875 1.578125zm5.3015137 2.765625l0 -5.53125l0.84375 0l0 0.84375q0.328125 -0.59375 0.59375 -0.78125q0.28125 -0.1875 0.609375 -0.1875q0.46875 0 0.953125 0.3125l-0.3125 0.859375q-0.34375 -0.203125 -0.6875 -0.203125q-0.3125 0 -0.5625 0.1875q-0.234375 0.1875 -0.34375 0.515625q-0.15625 0.5 -0.15625 1.09375l0 2.890625l-0.9375 0zm7.1736145 -0.6875q-0.53125 0.453125 -1.015625 0.640625q-0.46875 0.171875 -1.015625 0.171875q-0.921875 0 -1.40625 -0.4375q-0.484375 -0.453125 -0.484375 -1.140625q0 -0.40625 0.171875 -0.734375q0.1875 -0.34375 0.484375 -0.546875q0.3125 -0.203125 0.6875 -0.3125q0.265625 -0.0625 0.828125 -0.140625q1.125 -0.125 1.671875 -0.3125q0 -0.203125 0 -0.25q0 -0.578125 -0.265625 -0.8125q-0.359375 -0.3125 -1.0625 -0.3125q-0.65625 0 -0.984375 0.234375q-0.3125 0.234375 -0.453125 0.8125l-0.921875 -0.125q0.125 -0.578125 0.40625 -0.9375q0.296875 -0.375 0.828125 -0.5625q0.546875 -0.203125 1.25 -0.203125q0.71875 0 1.15625 0.171875q0.4375 0.171875 0.640625 0.421875q0.21875 0.25 0.296875 0.640625q0.046875 0.234375 0.046875 0.859375l0 1.25q0 1.296875 0.0625 1.65625q0.0625 0.34375 0.234375 0.65625l-0.96875 0q-0.15625 -0.296875 -0.1875 -0.6875zm-0.078125 -2.078125q-0.515625 0.203125 -1.53125 0.34375q-0.578125 0.078125 -0.828125 0.1875q-0.234375 0.109375 -0.359375 0.3125q-0.125 0.1875 -0.125 0.4375q0 0.375 0.28125 0.625q0.28125 0.25 0.828125 0.25q0.53125 0 0.953125 -0.234375q0.421875 -0.234375 0.625 -0.65625q0.15625 -0.3125 0.15625 -0.9375l0 -0.328125zm2.2233887 3.21875l0.90625 0.140625q0.0625 0.421875 0.328125 0.609375q0.34375 0.265625 0.9375 0.265625q0.65625 0 1.0 -0.265625q0.359375 -0.25 0.484375 -0.71875q0.078125 -0.296875 0.078125 -1.203125q-0.625 0.71875 -1.53125 0.71875q-1.140625 0 -1.765625 -0.8125q-0.625 -0.828125 -0.625 -1.984375q0 -0.78125 0.28125 -1.453125q0.296875 -0.671875 0.828125 -1.03125q0.546875 -0.375 1.28125 -0.375q0.984375 0 1.609375 0.796875l0 -0.671875l0.875 0l0 4.78125q0 1.296875 -0.265625 1.828125q-0.265625 0.5468445 -0.84375 0.8593445q-0.5625 0.3125 -1.390625 0.3125q-0.984375 0 -1.59375 -0.453125q-0.609375 -0.43746948 -0.59375 -1.3437195zm0.78125 -3.3125q0 1.078125 0.421875 1.578125q0.4375 0.5 1.078125 0.5q0.65625 0 1.09375 -0.484375q0.4375 -0.5 0.4375 -1.5625q0 -1.015625 -0.453125 -1.53125q-0.453125 -0.515625 -1.09375 -0.515625q-0.609375 0 -1.046875 0.515625q-0.4375 0.5 -0.4375 1.5zm9.098358 1.078125l0.96875 0.125q-0.234375 0.84375 -0.859375 1.3125q-0.609375 0.46875 -1.578125 0.46875q-1.203125 0 -1.921875 -0.75q-0.703125 -0.75 -0.703125 -2.09375q0 -1.390625 0.71875 -2.15625q0.71875 -0.78125 1.859375 -0.78125q1.109375 0 1.8125 0.765625q0.703125 0.75 0.703125 2.125q0 0.078125 0 0.234375l-4.125 0q0.046875 0.921875 0.515625 1.40625q0.46875 0.484375 1.15625 0.484375q0.515625 0 0.875 -0.265625q0.359375 -0.28125 0.578125 -0.875zm-3.078125 -1.515625l3.09375 0q-0.0625 -0.6875 -0.359375 -1.046875q-0.453125 -0.53125 -1.15625 -0.53125q-0.640625 0 -1.09375 0.4375q-0.4375 0.421875 -0.484375 1.140625z" fill-rule="nonzero"/><path fill="#d9d2e9" d="m465.81735 402.09888l79.78281 0l0 41.493317c-39.88925 0 -39.88925 15.964539 -79.78281 7.9822693zm6.57312 0l0 -5.379364l79.237885 0l0 41.75363c-3.011963 0 -6.0281982 0.2892151 -6.0281982 0.2892151l0 -36.663483zm6.178406 -5.379364l0 -5.2492065l79.92441 0l0 41.623474c-3.432495 0 -6.864929 0.21691895 -6.864929 0.21691895l0 -36.591187z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m465.81735 402.09888l79.78281 0l0 41.493317c-39.88925 0 -39.88925 15.964539 -79.78281 7.9822693zm6.57312 0l0 -5.379364l79.237885 0l0 41.75363c-3.011963 0 -6.0281982 0.2892151 -6.0281982 0.2892151m-67.03128 -42.042847l0 -5.2492065l79.92441 0l0 41.623474c-3.432495 0 -6.864929 0.21691895 -6.864929 0.21691895" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m465.81735 451.57446c39.893555 7.9822693 39.893555 -7.9822693 79.78281 -7.9822693l0 -4.829834c0 0 3.0162354 -0.2892151 6.0281982 -0.2892151l0 -5.162445c0 0 3.432434 -0.21691895 6.864929 -0.21691895l0 -41.623474l-79.92441 0l0 5.2492065l-6.178406 0l0 5.379364l-6.57312 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m465.81735 402.09888l79.78281 0l0 41.493317c-39.88925 0 -39.88925 15.964539 -79.78281 7.9822693zm6.57312 0l0 -5.379364l79.237885 0l0 41.75363c-3.011963 0 -6.0281982 0.2892151 -6.0281982 0.2892151m-67.03128 -42.042847l0 -5.2492065l79.92441 0l0 41.623474c-3.432495 0 -6.864929 0.21691895 -6.864929 0.21691895" fill-rule="evenodd"/><path fill="#000000" d="m499.9607 417.50104l0.765625 0.203125q-0.25 0.921875 -0.875 1.421875q-0.609375 0.484375 -1.5 0.484375q-0.921875 0 -1.515625 -0.375q-0.578125 -0.375 -0.875 -1.09375q-0.296875 -0.71875 -0.296875 -1.53125q0 -0.890625 0.328125 -1.5625q0.34375 -0.671875 0.96875 -1.015625q0.640625 -0.34375 1.40625 -0.34375q0.859375 0 1.4375 0.4375q0.59375 0.4375 0.8125 1.234375l-0.734375 0.171875q-0.203125 -0.625 -0.59375 -0.90625q-0.375 -0.28125 -0.9375 -0.28125q-0.671875 0 -1.109375 0.3125q-0.4375 0.3125 -0.625 0.84375q-0.171875 0.53125 -0.171875 1.109375q0 0.71875 0.203125 1.265625q0.21875 0.546875 0.65625 0.828125q0.453125 0.265625 0.984375 0.265625q0.640625 0 1.078125 -0.359375q0.4375 -0.375 0.59375 -1.109375zm1.5898438 2.015625l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.5273438 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm6.7148438 2.078125l0 -0.609375q-0.484375 0.703125 -1.3125 0.703125q-0.375 0 -0.703125 -0.140625q-0.3125 -0.140625 -0.46875 -0.34375q-0.140625 -0.21875 -0.203125 -0.53125q-0.046875 -0.203125 -0.046875 -0.65625l0 -2.578125l0.703125 0l0 2.3125q0 0.546875 0.046875 0.734375q0.0625 0.28125 0.265625 0.4375q0.21875 0.15625 0.546875 0.15625q0.3125 0 0.578125 -0.15625q0.28125 -0.171875 0.390625 -0.4375q0.125 -0.28125 0.125 -0.8125l0 -2.234375l0.703125 0l0 4.15625l-0.625 0zm4.4179688 0l0 -0.53125q-0.390625 0.625 -1.15625 0.625q-0.5 0 -0.921875 -0.265625q-0.40625 -0.28125 -0.640625 -0.765625q-0.21875 -0.5 -0.21875 -1.140625q0 -0.609375 0.203125 -1.109375q0.203125 -0.515625 0.609375 -0.78125q0.421875 -0.28125 0.9375 -0.28125q0.375 0 0.65625 0.171875q0.296875 0.15625 0.484375 0.40625l0 -2.0625l0.703125 0l0 5.734375l-0.65625 0zm-2.21875 -2.078125q0 0.796875 0.328125 1.203125q0.34375 0.390625 0.796875 0.390625q0.46875 0 0.78125 -0.375q0.328125 -0.375 0.328125 -1.15625q0 -0.84375 -0.328125 -1.234375q-0.328125 -0.40625 -0.8125 -0.40625q-0.46875 0 -0.78125 0.390625q-0.3125 0.375 -0.3125 1.1875z" fill-rule="nonzero"/><path fill="#000000" d="m482.95483 429.51666l0 -5.734375l1.140625 0l1.359375 4.0625q0.1875 0.5625 0.265625 0.84375q0.109375 -0.3125 0.3125 -0.921875l1.375 -3.984375l1.015625 0l0 5.734375l-0.734375 0l0 -4.796875l-1.65625 4.796875l-0.6875 0l-1.65625 -4.875l0 4.875l-0.734375 0zm9.3046875 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.8085938 2.078125l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm7.1523438 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.6835938 2.421875l0.671875 0.109375q0.046875 0.3125 0.25 0.453125q0.25 0.203125 0.703125 0.203125q0.5 0 0.765625 -0.203125q0.265625 -0.1875 0.359375 -0.546875q0.046875 -0.21875 0.046875 -0.90625q-0.46875 0.546875 -1.15625 0.546875q-0.84375 0 -1.3125 -0.609375q-0.46875 -0.625 -0.46875 -1.484375q0 -0.59375 0.203125 -1.09375q0.21875 -0.515625 0.625 -0.78125q0.40625 -0.28125 0.96875 -0.28125q0.734375 0 1.203125 0.59375l0 -0.5l0.65625 0l0 3.59375q0 0.96875 -0.203125 1.375q-0.203125 0.40625 -0.625 0.640625q-0.421875 0.234375 -1.046875 0.234375q-0.75 0 -1.203125 -0.34375q-0.453125 -0.328125 -0.4375 -1.0zm0.578125 -2.5q0 0.828125 0.3125 1.203125q0.328125 0.375 0.828125 0.375q0.484375 0 0.8125 -0.375q0.328125 -0.375 0.328125 -1.171875q0 -0.765625 -0.34375 -1.140625q-0.34375 -0.390625 -0.8125 -0.390625q-0.46875 0 -0.796875 0.375q-0.328125 0.375 -0.328125 1.125zm6.8398438 0.8125l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m492.55054 439.51666l0 -5.734375l2.15625 0q0.5625 0 0.875 0.0625q0.421875 0.0625 0.703125 0.265625q0.28125 0.203125 0.453125 0.5625q0.171875 0.34375 0.171875 0.765625q0 0.734375 -0.46875 1.25q-0.453125 0.5 -1.671875 0.5l-1.46875 0l0 2.328125l-0.75 0zm0.75 -3.0l1.484375 0q0.734375 0 1.03125 -0.265625q0.3125 -0.28125 0.3125 -0.78125q0 -0.359375 -0.1875 -0.609375q-0.171875 -0.265625 -0.46875 -0.34375q-0.1875 -0.046875 -0.703125 -0.046875l-1.46875 0l0 2.046875zm4.2265625 0.921875q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm1.296875 -3.40625l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.6210938 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.6367188 1.234375l0.6875 -0.109375q0.0625 0.40625 0.328125 0.640625q0.265625 0.21875 0.75 0.21875q0.484375 0 0.71875 -0.1875q0.234375 -0.203125 0.234375 -0.46875q0 -0.25 -0.203125 -0.375q-0.140625 -0.09375 -0.71875 -0.25q-0.78125 -0.1875 -1.078125 -0.328125q-0.296875 -0.140625 -0.453125 -0.390625q-0.15625 -0.265625 -0.15625 -0.5625q0 -0.28125 0.125 -0.515625q0.140625 -0.234375 0.359375 -0.390625q0.15625 -0.125 0.4375 -0.203125q0.28125 -0.09375 0.609375 -0.09375q0.484375 0 0.859375 0.140625q0.375 0.140625 0.546875 0.390625q0.171875 0.234375 0.234375 0.640625l-0.6875 0.09375q-0.046875 -0.328125 -0.265625 -0.5q-0.21875 -0.1875 -0.640625 -0.1875q-0.484375 0 -0.6875 0.171875q-0.203125 0.15625 -0.203125 0.375q0 0.125 0.078125 0.234375q0.09375 0.125 0.28125 0.1875q0.09375 0.046875 0.609375 0.1875q0.75 0.203125 1.046875 0.328125q0.296875 0.125 0.453125 0.375q0.171875 0.234375 0.171875 0.59375q0 0.34375 -0.203125 0.65625q-0.203125 0.3125 -0.59375 0.484375q-0.375 0.171875 -0.875 0.171875q-0.796875 0 -1.234375 -0.328125q-0.421875 -0.34375 -0.53125 -1.0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m452.73862 313.64877l127.3071 0l0 33.88977l-127.3071 0z" fill-rule="evenodd"/><path fill="#000000" d="m474.75067 336.7288l0 -10.484375l3.96875 0q1.046875 0 1.59375 0.09375q0.765625 0.125 1.28125 0.484375q0.53125 0.359375 0.84375 1.015625q0.328125 0.65625 0.328125 1.4375q0 1.328125 -0.859375 2.265625q-0.84375 0.921875 -3.078125 0.921875l-2.6875 0l0 4.265625l-1.390625 0zm1.390625 -5.5l2.71875 0q1.34375 0 1.90625 -0.5q0.5625 -0.5 0.5625 -1.40625q0 -0.671875 -0.328125 -1.140625q-0.328125 -0.46875 -0.875 -0.609375q-0.359375 -0.09375 -1.296875 -0.09375l-2.6875 0l0 3.75zm7.7443542 1.703125q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.276123 3.796875l0 -10.484375l1.28125 0l0 10.484375l-1.28125 0zm3.287384 -9.015625l0 -1.46875l1.296875 0l0 1.46875l-1.296875 0zm0 9.015625l0 -7.59375l1.296875 0l0 7.59375l-1.296875 0zm8.20929 -2.78125l1.265625 0.15625q-0.203125 1.3125 -1.0625 2.0625q-0.84375 0.734375 -2.09375 0.734375q-1.5625 0 -2.515625 -1.015625q-0.9375 -1.03125 -0.9375 -2.921875q0 -1.234375 0.40625 -2.15625q0.40625 -0.921875 1.234375 -1.375q0.84375 -0.46875 1.8125 -0.46875q1.25 0 2.03125 0.625q0.78125 0.625 1.015625 1.765625l-1.265625 0.203125q-0.171875 -0.765625 -0.625 -1.15625q-0.453125 -0.390625 -1.09375 -0.390625q-0.984375 0 -1.59375 0.703125q-0.609375 0.703125 -0.609375 2.203125q0 1.53125 0.578125 2.234375q0.59375 0.6875 1.546875 0.6875q0.75 0 1.265625 -0.453125q0.515625 -0.46875 0.640625 -1.4375zm2.3125 5.703125l-0.140625 -1.203125q0.421875 0.109375 0.734375 0.109375q0.4375 0 0.6875 -0.140625q0.265625 -0.140625 0.421875 -0.40625q0.125 -0.1875 0.390625 -0.953125q0.046875 -0.109375 0.125 -0.3125l-2.890625 -7.609375l1.390625 0l1.578125 4.390625q0.3125 0.84375 0.546875 1.765625q0.234375 -0.890625 0.53125 -1.734375l1.625 -4.421875l1.296875 0l-2.890625 7.71875q-0.46875 1.25 -0.734375 1.734375q-0.34375 0.625 -0.78125 0.921875q-0.4375 0.296875 -1.0625 0.296875q-0.375 0 -0.828125 -0.15625zm19.10321 -6.59375l1.390625 0.34375q-0.4375 1.703125 -1.578125 2.609375q-1.125 0.890625 -2.765625 0.890625q-1.6875 0 -2.75 -0.6875q-1.0625 -0.6875 -1.625 -2.0q-0.546875 -1.3125 -0.546875 -2.8125q0 -1.640625 0.625 -2.859375q0.625 -1.21875 1.78125 -1.84375q1.15625 -0.640625 2.546875 -0.640625q1.5625 0 2.640625 0.8125q1.078125 0.796875 1.5 2.25l-1.375 0.3125q-0.359375 -1.140625 -1.0625 -1.65625q-0.6875 -0.53125 -1.734375 -0.53125q-1.21875 0 -2.03125 0.578125q-0.8125 0.578125 -1.140625 1.5625q-0.328125 0.96875 -0.328125 2.015625q0 1.328125 0.390625 2.328125q0.390625 1.0 1.21875 1.5q0.828125 0.484375 1.78125 0.484375q1.171875 0 1.96875 -0.671875q0.8125 -0.671875 1.09375 -1.984375zm7.8967896 2.734375q-0.71875 0.609375 -1.375 0.859375q-0.65625 0.25 -1.421875 0.25q-1.25 0 -1.921875 -0.609375q-0.671875 -0.609375 -0.671875 -1.5625q0 -0.5625 0.25 -1.015625q0.25 -0.46875 0.65625 -0.75q0.421875 -0.28125 0.9375 -0.421875q0.375 -0.09375 1.140625 -0.1875q1.5625 -0.1875 2.296875 -0.453125q0.015625 -0.265625 0.015625 -0.328125q0 -0.796875 -0.375 -1.109375q-0.484375 -0.4375 -1.453125 -0.4375q-0.921875 0 -1.359375 0.328125q-0.421875 0.3125 -0.625 1.109375l-1.265625 -0.171875q0.171875 -0.796875 0.5625 -1.296875q0.390625 -0.5 1.140625 -0.765625q0.75 -0.265625 1.71875 -0.265625q0.984375 0 1.59375 0.234375q0.609375 0.21875 0.890625 0.5625q0.28125 0.34375 0.40625 0.875q0.0625 0.328125 0.0625 1.1875l0 1.71875q0 1.796875 0.078125 2.28125q0.078125 0.46875 0.328125 0.90625l-1.34375 0q-0.203125 -0.40625 -0.265625 -0.9375zm-0.109375 -2.875q-0.703125 0.28125 -2.09375 0.484375q-0.796875 0.109375 -1.125 0.265625q-0.328125 0.140625 -0.515625 0.421875q-0.171875 0.265625 -0.171875 0.59375q0 0.515625 0.390625 0.859375q0.390625 0.34375 1.140625 0.34375q0.734375 0 1.3125 -0.3125q0.59375 -0.328125 0.859375 -0.890625q0.203125 -0.4375 0.203125 -1.296875l0 -0.46875zm8.260498 1.03125l1.265625 0.15625q-0.203125 1.3125 -1.0625 2.0625q-0.84375 0.734375 -2.09375 0.734375q-1.5625 0 -2.515625 -1.015625q-0.9375 -1.03125 -0.9375 -2.921875q0 -1.234375 0.40625 -2.15625q0.40625 -0.921875 1.234375 -1.375q0.84375 -0.46875 1.8125 -0.46875q1.25 0 2.03125 0.625q0.78125 0.625 1.015625 1.765625l-1.265625 0.203125q-0.171875 -0.765625 -0.625 -1.15625q-0.453125 -0.390625 -1.09375 -0.390625q-0.984375 0 -1.59375 0.703125q-0.609375 0.703125 -0.609375 2.203125q0 1.53125 0.578125 2.234375q0.59375 0.6875 1.546875 0.6875q0.75 0 1.265625 -0.453125q0.515625 -0.46875 0.640625 -1.4375zm2.375 2.78125l0 -10.484375l1.28125 0l0 3.75q0.90625 -1.03125 2.28125 -1.03125q0.84375 0 1.46875 0.328125q0.625 0.328125 0.890625 0.921875q0.265625 0.578125 0.265625 1.703125l0 4.8125l-1.28125 0l0 -4.8125q0 -0.96875 -0.421875 -1.40625q-0.421875 -0.4375 -1.1875 -0.4375q-0.578125 0 -1.078125 0.296875q-0.5 0.296875 -0.71875 0.8125q-0.21875 0.5 -0.21875 1.390625l0 4.15625l-1.28125 0zm13.354187 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m212.98163 314.75067l127.3071 0l0 33.88974l-127.3071 0z" fill-rule="evenodd"/><path fill="#000000" d="m233.17552 337.83066l0 -9.25l-3.453125 0l0 -1.234375l8.3125 0l0 1.234375l-3.46875 0l0 9.25l-1.390625 0zm4.0144653 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.307358 3.796875l0 -10.484375l1.296875 0l0 5.96875l3.046875 -3.078125l1.671875 0l-2.90625 2.8125l3.1875 4.78125l-1.578125 0l-2.515625 -3.890625l-0.90625 0.875l0 3.015625l-1.296875 0zm12.53125 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375zm7.1823425 4.53125l0 -7.59375l1.15625 0l0 1.078125q0.84375 -1.25 2.421875 -1.25q0.6875 0 1.265625 0.25q0.578125 0.234375 0.859375 0.640625q0.28125 0.40625 0.40625 0.953125q0.0625 0.359375 0.0625 1.25l0 4.671875l-1.28125 0l0 -4.625q0 -0.78125 -0.15625 -1.171875q-0.15625 -0.390625 -0.546875 -0.625q-0.375 -0.234375 -0.890625 -0.234375q-0.8125 0 -1.421875 0.53125q-0.59375 0.515625 -0.59375 1.96875l0 4.15625l-1.28125 0zm11.9105835 -3.375l1.3125 -0.109375q0.09375 0.78125 0.421875 1.296875q0.34375 0.5 1.0625 0.8125q0.71875 0.3125 1.609375 0.3125q0.796875 0 1.40625 -0.234375q0.609375 -0.234375 0.90625 -0.640625q0.296875 -0.421875 0.296875 -0.90625q0 -0.5 -0.296875 -0.859375q-0.28125 -0.375 -0.9375 -0.625q-0.421875 -0.171875 -1.875 -0.515625q-1.4375 -0.34375 -2.015625 -0.65625q-0.75 -0.390625 -1.125 -0.96875q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.796875 0.4375 -1.484375q0.453125 -0.6875 1.3125 -1.046875q0.875 -0.359375 1.9375 -0.359375q1.171875 0 2.0625 0.375q0.890625 0.375 1.359375 1.109375q0.484375 0.734375 0.515625 1.65625l-1.328125 0.09375q-0.109375 -1.0 -0.734375 -1.5q-0.609375 -0.515625 -1.8125 -0.515625q-1.265625 0 -1.84375 0.46875q-0.578125 0.46875 -0.578125 1.109375q0 0.5625 0.421875 0.9375q0.390625 0.359375 2.078125 0.75q1.703125 0.375 2.328125 0.65625q0.921875 0.421875 1.359375 1.078125q0.4375 0.640625 0.4375 1.484375q0 0.84375 -0.484375 1.59375q-0.484375 0.734375 -1.390625 1.140625q-0.890625 0.40625 -2.015625 0.40625q-1.421875 0 -2.390625 -0.40625q-0.953125 -0.421875 -1.5 -1.25q-0.546875 -0.828125 -0.578125 -1.890625zm12.900604 2.21875l0.1875 1.140625q-0.546875 0.109375 -0.984375 0.109375q-0.6875 0 -1.078125 -0.21875q-0.390625 -0.21875 -0.546875 -0.578125q-0.15625 -0.359375 -0.15625 -1.515625l0 -4.375l-0.953125 0l0 -1.0l0.953125 0l0 -1.890625l1.28125 -0.765625l0 2.65625l1.296875 0l0 1.0l-1.296875 0l0 4.4375q0 0.546875 0.0625 0.71875q0.078125 0.15625 0.21875 0.25q0.15625 0.078125 0.453125 0.078125q0.203125 0 0.5625 -0.046875zm0.77511597 -2.640625q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.2917175 3.796875l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm9.849396 -0.9375q-0.71875 0.609375 -1.375 0.859375q-0.65625 0.25 -1.421875 0.25q-1.25 0 -1.921875 -0.609375q-0.671875 -0.609375 -0.671875 -1.5625q0 -0.5625 0.25 -1.015625q0.25 -0.46875 0.65625 -0.75q0.421875 -0.28125 0.9375 -0.421875q0.375 -0.09375 1.140625 -0.1875q1.5625 -0.1875 2.296875 -0.453125q0.015625 -0.265625 0.015625 -0.328125q0 -0.796875 -0.375 -1.109375q-0.484375 -0.4375 -1.453125 -0.4375q-0.921875 0 -1.359375 0.328125q-0.421875 0.3125 -0.625 1.109375l-1.265625 -0.171875q0.171875 -0.796875 0.5625 -1.296875q0.390625 -0.5 1.140625 -0.765625q0.75 -0.265625 1.71875 -0.265625q0.984375 0 1.59375 0.234375q0.609375 0.21875 0.890625 0.5625q0.28125 0.34375 0.40625 0.875q0.0625 0.328125 0.0625 1.1875l0 1.71875q0 1.796875 0.078125 2.28125q0.078125 0.46875 0.328125 0.90625l-1.34375 0q-0.203125 -0.40625 -0.265625 -0.9375zm-0.109375 -2.875q-0.703125 0.28125 -2.09375 0.484375q-0.796875 0.109375 -1.125 0.265625q-0.328125 0.140625 -0.515625 0.421875q-0.171875 0.265625 -0.171875 0.59375q0 0.515625 0.390625 0.859375q0.390625 0.34375 1.140625 0.34375q0.734375 0 1.3125 -0.3125q0.59375 -0.328125 0.859375 -0.890625q0.203125 -0.4375 0.203125 -1.296875l0 -0.46875zm3.072998 4.4375l1.25 0.1875q0.078125 0.578125 0.4375 0.84375q0.46875 0.359375 1.3125 0.359375q0.890625 0 1.375 -0.359375q0.484375 -0.359375 0.65625 -1.0q0.109375 -0.390625 0.09375 -1.65625q-0.84375 1.0 -2.109375 1.0q-1.5625 0 -2.421875 -1.125q-0.859375 -1.140625 -0.859375 -2.71875q0 -1.09375 0.390625 -2.0q0.40625 -0.921875 1.140625 -1.421875q0.75 -0.5 1.765625 -0.5q1.34375 0 2.21875 1.078125l0 -0.90625l1.1875 0l0 6.5625q0 1.78125 -0.359375 2.515625q-0.359375 0.734375 -1.15625 1.15625q-0.78125 0.4375 -1.921875 0.4375q-1.359375 0 -2.203125 -0.609375q-0.828125 -0.609375 -0.796875 -1.84375zm1.0625 -4.5625q0 1.5 0.59375 2.1875q0.59375 0.6875 1.484375 0.6875q0.890625 0 1.484375 -0.6875q0.609375 -0.6875 0.609375 -2.140625q0 -1.390625 -0.625 -2.09375q-0.609375 -0.71875 -1.484375 -0.71875q-0.859375 0 -1.46875 0.703125q-0.59375 0.6875 -0.59375 2.0625zm12.526093 1.484375l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375z" fill-rule="nonzero"/><path fill="#fff2cc" d="m228.6194 424.55652l68.64378 0l0 33.53012c-34.3219 0 -34.3219 12.775574 -68.64378 5.5167236z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m228.6194 424.55652l68.64378 0l0 33.53012c-34.3219 0 -34.3219 12.775574 -68.64378 5.5167236z" fill-rule="evenodd"/><path fill="#000000" d="m251.33974 434.00156l0 -5.734375l1.96875 0q0.671875 0 1.015625 0.09375q0.5 0.109375 0.84375 0.40625q0.453125 0.375 0.671875 0.984375q0.23435974 0.59375 0.23435974 1.359375q0 0.640625 -0.15623474 1.15625q-0.15625 0.5 -0.390625 0.828125q-0.234375 0.328125 -0.53125 0.515625q-0.28125 0.1875 -0.6875 0.296875q-0.390625 0.09375 -0.90625 0.09375l-2.0625 0zm0.75 -0.671875l1.21875 0q0.578125 0 0.890625 -0.109375q0.328125 -0.109375 0.515625 -0.296875q0.265625 -0.265625 0.421875 -0.71875q0.15625 -0.46875 0.15625 -1.109375q0 -0.90625 -0.296875 -1.375q-0.296875 -0.484375 -0.71875 -0.65625q-0.3125 -0.109375 -0.984375 -0.109375l-1.203125 0l0 4.375zm7.7773285 -0.671875l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm5.0742188 2.46875l-1.578125 -4.15625l0.734375 0l0.890625 2.484375q0.140625 0.40625 0.265625 0.84375q0.09375 -0.328125 0.265625 -0.796875l0.921875 -2.53125l0.71875 0l-1.5625 4.15625l-0.65625 0zm2.84375 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm4.140625 0.171875l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875z" fill-rule="nonzero"/><path fill="#000000" d="m240.1874 444.00156l0 -5.734375l1.140625 0l1.359375 4.0625q0.1875 0.5625 0.265625 0.84375q0.109375 -0.3125 0.3125 -0.921875l1.375 -3.984375l1.015625 0l0 5.734375l-0.734375 0l0 -4.796875l-1.65625 4.796875l-0.6875 0l-1.65625 -4.875l0 4.875l-0.734375 0zm9.3046875 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.8085938 2.078125l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm7.1523285 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.0468597 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.23435974 -0.15625 0.51560974 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.68748474 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21873474 -0.28125 0.62498474 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.6835938 2.421875l0.671875 0.109375q0.046875 0.3125 0.25 0.453125q0.25 0.203125 0.703125 0.203125q0.5 0 0.765625 -0.203125q0.265625 -0.1875 0.359375 -0.546875q0.046875 -0.21875 0.046875 -0.90625q-0.46875 0.546875 -1.15625 0.546875q-0.84375 0 -1.3125 -0.609375q-0.46875 -0.625 -0.46875 -1.484375q0 -0.59375 0.203125 -1.09375q0.21875 -0.515625 0.625 -0.78125q0.40625 -0.28125 0.96875 -0.28125q0.734375 0 1.203125 0.59375l0 -0.5l0.65625 0l0 3.59375q0 0.96875 -0.203125 1.375q-0.203125 0.40625 -0.625 0.640625q-0.421875 0.234375 -1.046875 0.234375q-0.75 0 -1.203125 -0.34375q-0.453125 -0.328125 -0.4375 -1.0zm0.578125 -2.5q0 0.828125 0.3125 1.203125q0.328125 0.375 0.828125 0.375q0.484375 0 0.8125 -0.375q0.328125 -0.375 0.328125 -1.171875q0 -0.765625 -0.34375 -1.140625q-0.34375 -0.390625 -0.8125 -0.390625q-0.46875 0 -0.796875 0.375q-0.328125 0.375 -0.328125 1.125zm6.8398438 0.8125l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m254.3456 454.00156l0 -5.046875l-1.890625 0l0 -0.6875l4.5468597 0l0 0.6875l-1.9062347 0l0 5.046875l-0.75 0zm2.1874847 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9960938 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#fff2cc" d="m264.20734 372.59326l68.64377 0l0 33.53012c-34.3219 0 -34.3219 12.775574 -68.64377 5.5167236z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m264.20734 372.59326l68.64377 0l0 33.53012c-34.3219 0 -34.3219 12.775574 -68.64377 5.5167236z" fill-rule="evenodd"/><path fill="#000000" d="m280.0507 387.0383l0 -5.734375l4.140625 0l0 0.6875l-3.390625 0l0 1.75l3.171875 0l0 0.671875l-3.171875 0l0 1.953125l3.515625 0l0 0.671875l-4.265625 0zm5.2265625 0l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm4.4335938 0l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm2.4140625 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804993 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7773438 0l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 0l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m289.9335 397.0383l0 -5.046875l-1.890625 0l0 -0.6875l4.546875 0l0 0.6875l-1.90625 0l0 5.046875l-0.75 0zm2.1875 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9961243 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#eeeeee" d="m18.843596 38.32938l0 0c-1.1719189 -6.765497 2.675726 -13.462929 9.910236 -17.250328c7.2345104 -3.7873974 16.587114 -4.000538 24.089151 -0.5489731l0 0c2.6574516 -3.9337406 7.5213623 -6.6497173 13.120495 -7.326399c5.5991287 -0.6766825 11.275848 0.7654085 15.313042 3.890068l0 0c2.2638092 -3.5665827 6.708832 -5.9628696 11.757744 -6.3385344c5.0489197 -0.37566566 9.987183 1.3224564 13.062431 4.491784l0 0c4.089897 -3.7805672 10.597031 -5.372343 16.705719 -4.0865574c6.1086884 1.2857857 10.721771 5.218195 11.843124 10.095652l0 0c5.0108185 1.0736961 9.184723 3.8031769 11.443314 7.4832306c2.2585907 3.6800537 2.3802948 7.9496765 0.33369446 11.70573l0 0c4.934189 5.044796 6.0884247 11.766922 3.031952 17.657803c-3.0564728 5.8908806 -9.864441 10.065479 -17.8833 10.965908c-0.056518555 5.528801 -3.9163742 10.601967 -10.091812 13.264069c-6.1754456 2.6621017 -13.702148 2.4974518 -19.679 -0.4304886l0 0c-2.5458145 6.6216965 -9.711449 11.493881 -18.401085 12.511581c-8.689629 1.0177078 -17.345467 -2.0015106 -22.227867 -7.753235l0 0c-5.984806 2.8350449 -13.166077 3.6517258 -19.923859 2.265831c-6.757782 -1.3859024 -12.522837 -4.857643 -15.994682 -9.63208l0 0c-6.1157207 0.56220245 -12.028776 -1.9269104 -14.80454 -6.2320023c-2.775764 -4.3050995 -1.8233414 -9.509716 2.3845835 -13.03083l0 0c-5.455381 -2.5223541 -8.239044 -7.5275497 -6.8994207 -12.405567c1.3396239 -4.8780174 6.498973 -8.523483 12.787648 -9.035431z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m12.834479 60.031128l0 0c2.5744104 1.1903076 5.548459 1.730259 8.52283 1.5473595m3.8957863 17.7159c1.279089 -0.1175766 2.5328388 -0.36657715 3.728918 -0.74057007m32.187836 8.106506c-0.8996315 -1.0598068 -1.6528435 -2.192299 -2.246811 -3.378189m42.877323 -1.3803482l0 0c0.46413422 -1.2072372 0.76486206 -2.4497375 0.89714813 -3.706787m28.872543 -9.1263275c0.060165405 -5.886265 -4.195709 -11.275791 -10.939621 -13.853615m25.790817 -14.769478c-1.0921631 2.004383 -2.7594604 3.782444 -4.87117 5.1947746m-6.9048157 -24.384262l0 0c0.18608093 0.8094158 0.27220154 1.6309967 0.25717163 2.4533558m-28.805527 -8.462204l0 0c-1.0202255 0.94306374 -1.8607559 1.9969254 -2.4954224 3.1287708m-22.32499 -1.2824326l0 0c-0.54369354 0.8565769 -0.94968414 1.7629833 -1.2086258 2.6983376m-27.225327 0.7380638l0 0c1.5874252 0.7303486 3.0560112 1.6093998 4.373493 2.6178474m-38.372444 15.181549l0 0c0.16152191 0.9324608 0.4167328 1.8534241 0.7632446 2.7542725" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m18.843596 38.32938l0 0c-1.1719189 -6.765497 2.675726 -13.462929 9.910236 -17.250328c7.2345104 -3.7873974 16.587114 -4.000538 24.089151 -0.5489731l0 0c2.6574516 -3.9337406 7.5213623 -6.6497173 13.120495 -7.326399c5.5991287 -0.6766825 11.275848 0.7654085 15.313042 3.890068l0 0c2.2638092 -3.5665827 6.708832 -5.9628696 11.757744 -6.3385344c5.0489197 -0.37566566 9.987183 1.3224564 13.062431 4.491784l0 0c4.089897 -3.7805672 10.597031 -5.372343 16.705719 -4.0865574c6.1086884 1.2857857 10.721771 5.218195 11.843124 10.095652l0 0c5.0108185 1.0736961 9.184723 3.8031769 11.443314 7.4832306c2.2585907 3.6800537 2.3802948 7.9496765 0.33369446 11.70573l0 0c4.934189 5.044796 6.0884247 11.766922 3.031952 17.657803c-3.0564728 5.8908806 -9.864441 10.065479 -17.8833 10.965908c-0.056518555 5.528801 -3.9163742 10.601967 -10.091812 13.264069c-6.1754456 2.6621017 -13.702148 2.4974518 -19.679 -0.4304886l0 0c-2.5458145 6.6216965 -9.711449 11.493881 -18.401085 12.511581c-8.689629 1.0177078 -17.345467 -2.0015106 -22.227867 -7.753235l0 0c-5.984806 2.8350449 -13.166077 3.6517258 -19.923859 2.265831c-6.757782 -1.3859024 -12.522837 -4.857643 -15.994682 -9.63208l0 0c-6.1157207 0.56220245 -12.028776 -1.9269104 -14.80454 -6.2320023c-2.775764 -4.3050995 -1.8233414 -9.509716 2.3845835 -13.03083l0 0c-5.455381 -2.5223541 -8.239044 -7.5275497 -6.8994207 -12.405567c1.3396239 -4.8780174 6.498973 -8.523483 12.787648 -9.035431z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m12.834479 60.031128l0 0c2.5744104 1.1903076 5.548459 1.730259 8.52283 1.5473595m3.8957863 17.7159c1.279089 -0.1175766 2.5328388 -0.36657715 3.728918 -0.74057007m32.187836 8.106506c-0.8996315 -1.0598068 -1.6528435 -2.192299 -2.246811 -3.378189m42.877323 -1.3803482l0 0c0.46413422 -1.2072372 0.76486206 -2.4497375 0.89714813 -3.706787m28.872543 -9.1263275c0.060165405 -5.886265 -4.195709 -11.275791 -10.939621 -13.853615m25.790817 -14.769478c-1.0921631 2.004383 -2.7594604 3.782444 -4.87117 5.1947746m-6.9048157 -24.384262l0 0c0.18608093 0.8094158 0.27220154 1.6309967 0.25717163 2.4533558m-28.805527 -8.462204l0 0c-1.0202255 0.94306374 -1.8607559 1.9969254 -2.4954224 3.1287708m-22.32499 -1.2824326l0 0c-0.54369354 0.8565769 -0.94968414 1.7629833 -1.2086258 2.6983376m-27.225327 0.7380638l0 0c1.5874252 0.7303486 3.0560112 1.6093998 4.373493 2.6178474m-38.372444 15.181549l0 0c0.16152191 0.9324608 0.4167328 1.8534241 0.7632446 2.7542725" fill-rule="evenodd"/><path fill="#000000" d="m55.644993 33.393417l0 -1.234375l4.4375 -0.015625l0 3.90625q-1.03125 0.8125 -2.125 1.21875q-1.078125 0.40625 -2.21875 0.40625q-1.546875 0 -2.8125 -0.65625q-1.265625 -0.65625 -1.90625 -1.90625q-0.640625 -1.265625 -0.640625 -2.8125q0 -1.5312481 0.640625 -2.843748q0.640625 -1.328125 1.84375 -1.96875q1.203125 -0.65625 2.765625 -0.65625q1.140625 0 2.0625 0.375q0.921875 0.359375 1.4375 1.03125q0.53125 0.65625 0.796875 1.703125l-1.25 0.34375q-0.234375 -0.796875 -0.59375 -1.25q-0.34375 -0.46875 -1.0 -0.734375q-0.65625 -0.28125 -1.4375 -0.28125q-0.953125 0 -1.65625 0.296875q-0.6875 0.28125 -1.125 0.765625q-0.421875 0.46875 -0.65625 1.03125q-0.390625 0.96875 -0.390625 2.109373q0 1.40625 0.46875 2.359375q0.484375 0.9375 1.40625 1.390625q0.9375 0.453125 1.96875 0.453125q0.90625 0 1.765625 -0.34375q0.859375 -0.34375 1.296875 -0.734375l0 -1.953125l-3.078125 0zm5.8376007 0.3125q0 -2.109373 1.171875 -3.124998q0.984375 -0.84375 2.3906212 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828123q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.5937462 0 -2.5781212 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.6406212 0.71875 1.6093712 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.124998q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.6093712 0.71875q-0.625 0.7187481 -0.625 2.187498zm6.822979 0q0 -2.109373 1.171875 -3.124998q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828123q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.124998q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.7187481 -0.625 2.187498zm7.072983 4.421875l1.25 0.1875q0.078125 0.578125 0.4375 0.8437538q0.46875 0.359375 1.3125 0.359375q0.890625 0 1.375 -0.359375q0.484375 -0.3593788 0.65625 -1.0000038q0.109375 -0.390625 0.09375 -1.65625q-0.84375 1.0 -2.109375 1.0q-1.5625 0 -2.421875 -1.125q-0.859375 -1.140625 -0.859375 -2.71875q0 -1.09375 0.390625 -1.9999981q0.40625 -0.921875 1.140625 -1.421875q0.75 -0.5 1.765625 -0.5q1.34375 0 2.21875 1.078125l0 -0.90625l1.1875 0l0 6.562498q0 1.78125 -0.359375 2.515625q-0.359375 0.7343788 -1.15625 1.1562538q-0.78125 0.4375 -1.921875 0.4375q-1.359375 0 -2.203125 -0.609375q-0.828125 -0.609375 -0.796875 -1.8437538zm1.0625 -4.5625q0 1.5 0.59375 2.1875q0.59375 0.6875 1.484375 0.6875q0.890625 0 1.484375 -0.6875q0.609375 -0.6875 0.609375 -2.140625q0 -1.390625 -0.625 -2.093748q-0.609375 -0.71875 -1.484375 -0.71875q-0.859375 0 -1.46875 0.703125q-0.59375 0.6874981 -0.59375 2.062498zm7.291733 3.9375l0 -10.484373l1.28125 0l0 10.484373l-1.28125 0zm8.490532 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.9687576 -1.03125 -0.9687576 -2.890625q0 -1.9218731 0.9843826 -2.968748q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921873q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4374981q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.5937481z" fill-rule="nonzero"/><path fill="#000000" d="m52.441463 55.502796l4.015625 -10.484375l1.5 0l4.296875 10.484375l-1.578125 0l-1.234375 -3.171875l-4.375 0l-1.15625 3.171875l-1.46875 0zm3.015625 -4.3125l3.5625 0l-1.09375 -2.90625q-0.5 -1.3125 -0.75 -2.171875q-0.203125 1.015625 -0.5625 2.0l-1.15625 3.078125zm12.666225 4.3125l0 -0.953125q-0.71875 1.125 -2.125 1.125q-0.90625 0 -1.671875 -0.5q-0.7499962 -0.5 -1.1718712 -1.390625q-0.421875 -0.90625 -0.421875 -2.078125q0 -1.140625 0.375 -2.0625q0.390625 -0.921875 1.1406212 -1.40625q0.765625 -0.5 1.703125 -0.5q0.6875 0 1.21875 0.296875q0.53125 0.28125 0.875 0.734375l0 -3.75l1.28125 0l0 10.484375l-1.203125 0zm-4.0625 -3.796875q0 1.46875 0.609375 2.1875q0.625 0.71875 1.453125 0.71875q0.84375 0 1.4375 -0.6875q0.59375 -0.6875 0.59375 -2.109375q0 -1.5625 -0.609375 -2.28125q-0.59375 -0.734375 -1.484375 -0.734375q-0.84375 0 -1.421875 0.703125q-0.578125 0.703125 -0.578125 2.203125zm7.291733 3.796875l0 -7.59375l1.15625 0l0 1.0625q0.34375 -0.5625 0.9375 -0.890625q0.609375 -0.34375 1.359375 -0.34375q0.84375 0 1.375 0.34375q0.546875 0.34375 0.765625 0.984375q0.90625 -1.328125 2.359375 -1.328125q1.125 0 1.734375 0.625q0.609375 0.625 0.609375 1.921875l0 5.21875l-1.28125 0l0 -4.78125q0 -0.78125 -0.125 -1.109375q-0.125 -0.34375 -0.453125 -0.546875q-0.328125 -0.21875 -0.78125 -0.21875q-0.796875 0 -1.328125 0.53125q-0.53125 0.53125 -0.53125 1.703125l0 4.421875l-1.28125 0l0 -4.9375q0 -0.859375 -0.3125 -1.28125q-0.3125 -0.4375 -1.03125 -0.4375q-0.546875 0 -1.015625 0.296875q-0.453125 0.28125 -0.671875 0.828125q-0.203125 0.546875 -0.203125 1.59375l0 3.9375l-1.28125 0zm12.208771 -9.015625l0 -1.46875l1.296875 0l0 1.46875l-1.296875 0zm0 9.015625l0 -7.59375l1.296875 0l0 7.59375l-1.296875 0zm3.2561493 0l0 -7.59375l1.15625 0l0 1.078125q0.84375 -1.25 2.421875 -1.25q0.6875 0 1.265625 0.25q0.578125 0.234375 0.859375 0.640625q0.28125 0.40625 0.40625 0.953125q0.0625 0.359375 0.0625 1.25l0 4.671875l-1.28125 0l0 -4.625q0 -0.78125 -0.15625 -1.171875q-0.15625 -0.390625 -0.546875 -0.625q-0.375 -0.234375 -0.890625 -0.234375q-0.8125 0 -1.421875 0.53125q-0.59375 0.515625 -0.59375 1.96875l0 4.15625l-1.28125 0z" fill-rule="nonzero"/><path fill="#000000" d="m54.951344 69.83092l1.390625 0.34375q-0.4375 1.703125 -1.578125 2.609375q-1.125 0.890625 -2.765625 0.890625q-1.6875 0 -2.75 -0.6875q-1.0625 -0.6875 -1.625 -2.0q-0.546875 -1.3125 -0.546875 -2.8125q0 -1.640625 0.625 -2.859375q0.625 -1.21875 1.78125 -1.8437462q1.15625 -0.640625 2.546875 -0.640625q1.5625 0 2.640625 0.8125q1.078125 0.7968712 1.5 2.2499962l-1.375 0.3125q-0.359375 -1.140625 -1.0625 -1.65625q-0.6875 -0.53125 -1.734375 -0.53125q-1.21875 0 -2.03125 0.578125q-0.8125 0.578125 -1.140625 1.5625q-0.328125 0.96875 -0.328125 2.015625q0 1.328125 0.390625 2.328125q0.390625 1.0 1.21875 1.5q0.828125 0.484375 1.78125 0.484375q1.171875 0 1.96875 -0.671875q0.8125 -0.671875 1.09375 -1.984375zm2.4592743 -0.125q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q0.9999962 1.015625 0.9999962 2.828125q0 1.46875 -0.4375 2.3125q-0.4374962 0.828125 -1.2812462 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.307354 3.796875l0 -7.59375l1.15625 0l0 1.078125q0.84375 -1.25 2.421875 -1.25q0.6875 0 1.265625 0.25q0.578125 0.234375 0.859375 0.640625q0.28125 0.40625 0.40625 0.953125q0.0625 0.359375 0.0625 1.25l0 4.671875l-1.28125 0l0 -4.625q0 -0.78125 -0.15625 -1.171875q-0.15625 -0.390625 -0.546875 -0.625q-0.375 -0.234375 -0.890625 -0.234375q-0.8125 0 -1.421875 0.53125q-0.59375 0.515625 -0.59375 1.96875l0 4.15625l-1.28125 0zm7.635483 -2.265625l1.265625 -0.203125q0.109375 0.765625 0.59375 1.171875q0.5 0.40625 1.375 0.40625q0.890625 0 1.3125 -0.359375q0.4375 -0.359375 0.4375 -0.84375q0 -0.4375 -0.375 -0.6875q-0.265625 -0.171875 -1.3125 -0.4375q-1.421875 -0.359375 -1.96875 -0.609375q-0.546875 -0.265625 -0.828125 -0.734375q-0.28125 -0.46875 -0.28125 -1.015625q0 -0.515625 0.21875 -0.9375q0.234375 -0.4375 0.640625 -0.734375q0.296875 -0.21875 0.8125 -0.359375q0.53125 -0.15625 1.125 -0.15625q0.890625 0 1.5625 0.265625q0.671875 0.25 1.0 0.6875q0.328125 0.4375 0.4375 1.171875l-1.25 0.171875q-0.09375 -0.578125 -0.5 -0.90625q-0.40625 -0.34375 -1.15625 -0.34375q-0.890625 0 -1.28125 0.296875q-0.375 0.296875 -0.375 0.6875q0 0.25 0.15625 0.453125q0.15625 0.203125 0.5 0.34375q0.1875 0.078125 1.140625 0.328125q1.359375 0.359375 1.890625 0.59375q0.546875 0.234375 0.859375 0.6875q0.3125 0.4375 0.3125 1.09375q0 0.640625 -0.375 1.21875q-0.375 0.5625 -1.09375 0.875q-0.703125 0.3125 -1.59375 0.3125q-1.484375 0 -2.265625 -0.609375q-0.765625 -0.625 -0.984375 -1.828125zm7.359375 -1.53125q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.276108 3.796875l0 -10.484371l1.2812576 0l0 10.484371l-1.2812576 0zm8.490532 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m78.39643 94.21265l0 48.61696l0.06298828 0l0 48.23343" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m78.39643 94.21265l0 48.61696l0.06298828 0l0 44.80635" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m78.45942 187.63594l-1.1245804 -1.1245728l1.1245804 3.0897675l1.124588 -3.0897675z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m325.44882 196.47507l0 -142.3937" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m325.44882 196.47507l0 -138.96661" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m325.44882 57.50845l1.1245728 1.1245842l-1.1245728 -3.0897675l-1.1245728 3.0897675z" fill-rule="evenodd"/><path fill="#fff2cc" d="m291.1273 109.86622l68.64377 0l0 33.530113c-34.3219 0 -34.3219 12.775589 -68.64377 5.516739z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m291.1273 109.86622l68.64377 0l0 33.530113c-34.3219 0 -34.3219 12.775589 -68.64377 5.516739z" fill-rule="evenodd"/><path fill="#000000" d="m306.97064 124.31128l0 -5.734375l4.140625 0l0 0.6875l-3.390625 0l0 1.75l3.171875 0l0 0.671875l-3.171875 0l0 1.953125l3.515625 0l0 0.671875l-4.265625 0zm5.2265625 0l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm4.4335938 0l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm2.4140625 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7773438 0l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 0l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m316.85345 134.31128l0 -5.046875l-1.890625 0l0 -0.6875l4.546875 0l0 0.6875l-1.90625 0l0 5.046875l-0.75 0zm2.1875 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9960938 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m229.93439 197.62204l0 -136.47244" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m229.93439 194.19496l0 -133.04535" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m229.93439 194.19496l-1.124588 -1.124588l1.124588 3.0897675l1.1245728 -3.0897675z" fill-rule="evenodd"/><path fill="#d9d2e9" d="m187.6024 133.88799l72.88655 0l0 36.198868c-36.441315 0 -36.441315 13.9275055 -72.88655 6.963745zm6.004959 0l0 -4.6929626l72.38873 0l0 36.42595c-2.7516174 0 -5.507141 0.25231934 -5.507141 0.25231934l0 -31.985306zm5.644348 -4.6929626l0 -4.579422l73.0159 0l0 36.31241c-3.1357422 0 -6.271515 0.1892395 -6.271515 0.1892395l0 -31.922226z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m187.6024 133.88799l72.88655 0l0 36.198868c-36.441315 0 -36.441315 13.9275055 -72.88655 6.963745zm6.004959 0l0 -4.6929626l72.38873 0l0 36.42595c-2.7516174 0 -5.507141 0.25231934 -5.507141 0.25231934m-61.237244 -36.67827l0 -4.579422l73.0159 0l0 36.31241c-3.1357422 0 -6.271515 0.1892395 -6.271515 0.1892395" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m187.6024 177.0506c36.445236 6.9637604 36.445236 -6.963745 72.88655 -6.963745l0 -4.213562c0 0 2.7555237 -0.25231934 5.507141 -0.25231934l0 -4.503723c0 0 3.1357727 -0.1892395 6.271515 -0.1892395l0 -36.31241l-73.0159 0l0 4.579422l-5.644348 0l0 4.6929626l-6.004959 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m187.6024 133.88799l72.88655 0l0 36.198868c-36.441315 0 -36.441315 13.9275055 -72.88655 6.963745zm6.004959 0l0 -4.6929626l72.38873 0l0 36.42595c-2.7516174 0 -5.507141 0.25231934 -5.507141 0.25231934m-61.237244 -36.67827l0 -4.579422l73.0159 0l0 36.31241c-3.1357422 0 -6.271515 0.1892395 -6.271515 0.1892395" fill-rule="evenodd"/><path fill="#000000" d="m218.29764 146.13367l0.765625 0.203125q-0.25 0.921875 -0.875 1.421875q-0.609375 0.484375 -1.5 0.484375q-0.921875 0 -1.515625 -0.375q-0.578125 -0.375 -0.875 -1.09375q-0.296875 -0.71875 -0.296875 -1.53125q0 -0.890625 0.328125 -1.5625q0.34375 -0.671875 0.96875 -1.015625q0.640625 -0.34375 1.40625 -0.34375q0.859375 0 1.4375 0.4375q0.59375 0.4375 0.8125 1.234375l-0.734375 0.171875q-0.203125 -0.625 -0.59375 -0.90625q-0.375 -0.28125 -0.9375 -0.28125q-0.671875 0 -1.109375 0.3125q-0.4375 0.3125 -0.625 0.84375q-0.171875 0.53125 -0.171875 1.109375q0 0.71875 0.203125 1.265625q0.21875 0.546875 0.65625 0.828125q0.453125 0.265625 0.984375 0.265625q0.640625 0 1.078125 -0.359375q0.4375 -0.375 0.59375 -1.109375zm1.5898438 2.015625l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.5273438 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm6.7148438 2.078125l0 -0.609375q-0.484375 0.703125 -1.3125 0.703125q-0.375 0 -0.703125 -0.140625q-0.3125 -0.140625 -0.46875 -0.34375q-0.140625 -0.21875 -0.203125 -0.53125q-0.046875 -0.203125 -0.046875 -0.65625l0 -2.578125l0.703125 0l0 2.3125q0 0.546875 0.046875 0.734375q0.0625 0.28125 0.265625 0.4375q0.21875 0.15625 0.546875 0.15625q0.3125 0 0.578125 -0.15625q0.28125 -0.171875 0.390625 -0.4375q0.125 -0.28125 0.125 -0.8125l0 -2.234375l0.703125 0l0 4.15625l-0.625 0zm4.4179688 0l0 -0.53125q-0.390625 0.625 -1.15625 0.625q-0.5 0 -0.921875 -0.265625q-0.40625 -0.28125 -0.640625 -0.765625q-0.21875 -0.5 -0.21875 -1.140625q0 -0.609375 0.203125 -1.109375q0.203125 -0.515625 0.609375 -0.78125q0.421875 -0.28125 0.9375 -0.28125q0.375 0 0.65625 0.171875q0.296875 0.15625 0.484375 0.40625l0 -2.0625l0.703125 0l0 5.734375l-0.65625 0zm-2.21875 -2.078125q0 0.796875 0.328125 1.203125q0.34375 0.390625 0.796875 0.390625q0.46875 0 0.78125 -0.375q0.328125 -0.375 0.328125 -1.15625q0 -0.84375 -0.328125 -1.234375q-0.328125 -0.40625 -0.8125 -0.40625q-0.46875 0 -0.78125 0.390625q-0.3125 0.375 -0.3125 1.1875z" fill-rule="nonzero"/><path fill="#000000" d="m201.29178 158.14929l0 -5.734375l1.140625 0l1.359375 4.0625q0.1875 0.5625 0.265625 0.84375q0.109375 -0.3125 0.3125 -0.921875l1.375 -3.984375l1.015625 0l0 5.734375l-0.734375 0l0 -4.796875l-1.65625 4.796875l-0.6875 0l-1.65625 -4.875l0 4.875l-0.734375 0zm9.3046875 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.8085938 2.078125l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm7.1523438 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.6835938 2.421875l0.671875 0.109375q0.046875 0.3125 0.25 0.453125q0.25 0.203125 0.703125 0.203125q0.5 0 0.765625 -0.203125q0.265625 -0.1875 0.359375 -0.546875q0.046875 -0.21875 0.046875 -0.90625q-0.46875 0.546875 -1.15625 0.546875q-0.84375 0 -1.3125 -0.609375q-0.46875 -0.625 -0.46875 -1.484375q0 -0.59375 0.203125 -1.09375q0.21875 -0.515625 0.625 -0.78125q0.40625 -0.28125 0.96875 -0.28125q0.734375 0 1.203125 0.59375l0 -0.5l0.65625 0l0 3.59375q0 0.96875 -0.203125 1.375q-0.203125 0.40625 -0.625 0.640625q-0.421875 0.234375 -1.046875 0.234375q-0.75 0 -1.203125 -0.34375q-0.453125 -0.328125 -0.4375 -1.0zm0.578125 -2.5q0 0.828125 0.3125 1.203125q0.328125 0.375 0.828125 0.375q0.484375 0 0.8125 -0.375q0.328125 -0.375 0.328125 -1.171875q0 -0.765625 -0.34375 -1.140625q-0.34375 -0.390625 -0.8125 -0.390625q-0.46875 0 -0.796875 0.375q-0.328125 0.375 -0.328125 1.125zm6.8398438 0.8125l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m210.88748 168.14929l0 -5.734375l2.15625 0q0.5625 0 0.875 0.0625q0.421875 0.0625 0.703125 0.265625q0.28125 0.203125 0.453125 0.5625q0.171875 0.34375 0.171875 0.765625q0 0.734375 -0.46875 1.25q-0.453125 0.5 -1.671875 0.5l-1.46875 0l0 2.328125l-0.75 0zm0.75 -3.0l1.484375 0q0.734375 0 1.03125 -0.265625q0.3125 -0.28125 0.3125 -0.78125q0 -0.359375 -0.1875 -0.609375q-0.171875 -0.265625 -0.46875 -0.34375q-0.1875 -0.046875 -0.703125 -0.046875l-1.46875 0l0 2.046875zm4.2265625 0.921875q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm1.296875 -3.40625l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.6210938 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.6367188 1.234375l0.6875 -0.109375q0.0625 0.40625 0.328125 0.640625q0.265625 0.21875 0.75 0.21875q0.484375 0 0.71875 -0.1875q0.234375 -0.203125 0.234375 -0.46875q0 -0.25 -0.203125 -0.375q-0.140625 -0.09375 -0.71875 -0.25q-0.78125 -0.1875 -1.078125 -0.328125q-0.296875 -0.140625 -0.453125 -0.390625q-0.15625 -0.265625 -0.15625 -0.5625q0 -0.28125 0.125 -0.515625q0.140625 -0.234375 0.359375 -0.390625q0.15625 -0.125 0.4375 -0.203125q0.28125 -0.09375 0.609375 -0.09375q0.484375 0 0.859375 0.140625q0.375 0.140625 0.546875 0.390625q0.171875 0.234375 0.234375 0.640625l-0.6875 0.09375q-0.046875 -0.328125 -0.265625 -0.5q-0.21875 -0.1875 -0.640625 -0.1875q-0.484375 0 -0.6875 0.171875q-0.203125 0.15625 -0.203125 0.375q0 0.125 0.078125 0.234375q0.09375 0.125 0.28125 0.1875q0.09375 0.046875 0.609375 0.1875q0.75 0.203125 1.046875 0.328125q0.296875 0.125 0.453125 0.375q0.171875 0.234375 0.171875 0.59375q0 0.34375 -0.203125 0.65625q-0.203125 0.3125 -0.59375 0.484375q-0.375 0.171875 -0.875 0.171875q-0.796875 0 -1.234375 -0.328125q-0.421875 -0.34375 -0.53125 -1.0z" fill-rule="nonzero"/><path fill="#fff2cc" d="m195.61153 78.1733l68.64378 0l0 33.53012c-34.321884 0 -34.321884 12.775589 -68.64378 5.5167313z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m195.61153 78.1733l68.64378 0l0 33.53012c-34.321884 0 -34.321884 12.775589 -68.64378 5.5167313z" fill-rule="evenodd"/><path fill="#000000" d="m218.33186 87.61836l0 -5.734375l1.96875 0q0.671875 0 1.015625 0.09375q0.5 0.109375 0.84375 0.40625q0.453125 0.375 0.671875 0.984375q0.234375 0.59375 0.234375 1.359375q0 0.640625 -0.15625 1.15625q-0.15625 0.5 -0.390625 0.828125q-0.234375 0.328125 -0.53125 0.515625q-0.28125 0.1875 -0.6875 0.296875q-0.390625 0.09375 -0.90625 0.09375l-2.0625 0zm0.75 -0.671875l1.21875 0q0.578125 0 0.890625 -0.109375q0.328125 -0.109375 0.515625 -0.296875q0.265625 -0.265625 0.421875 -0.71875q0.15625 -0.46875 0.15625 -1.109375q0 -0.90625 -0.296875 -1.375q-0.296875 -0.484375 -0.71875 -0.65625q-0.3125 -0.109375 -0.984375 -0.109375l-1.203125 0l0 4.375zm7.7773438 -0.671875l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm5.0742188 2.46875l-1.578125 -4.15625l0.734375 0l0.890625 2.484375q0.140625 0.40625 0.265625 0.84375q0.09375 -0.328125 0.265625 -0.796875l0.921875 -2.53125l0.71875 0l-1.5625 4.15625l-0.65625 0zm2.84375 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm4.140625 0.171875l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875z" fill-rule="nonzero"/><path fill="#000000" d="m207.17952 97.61836l0 -5.734375l1.140625 0l1.359375 4.0625q0.1875 0.5625 0.265625 0.84375q0.109375 -0.3125 0.3125 -0.921875l1.375 -3.984375l1.015625 0l0 5.734375l-0.734375 0l0 -4.796875l-1.65625 4.796875l-0.6875 0l-1.65625 -4.875l0 4.875l-0.734375 0zm9.3046875 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.8085938 2.078125l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm7.1523438 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.6835938 2.421875l0.671875 0.109375q0.046875 0.3125 0.25 0.453125q0.25 0.203125 0.703125 0.203125q0.5 0 0.765625 -0.203125q0.265625 -0.1875 0.359375 -0.546875q0.046875 -0.21875 0.046875 -0.90625q-0.46875 0.546875 -1.15625 0.546875q-0.84375 0 -1.3125 -0.609375q-0.46875 -0.625 -0.46875 -1.484375q0 -0.59375 0.203125 -1.09375q0.21875 -0.515625 0.625 -0.78125q0.40625 -0.28125 0.96875 -0.28125q0.734375 0 1.203125 0.59375l0 -0.5l0.65625 0l0 3.59375q0 0.96875 -0.203125 1.375q-0.203125 0.40625 -0.625 0.640625q-0.421875 0.234375 -1.046875 0.234375q-0.75 0 -1.203125 -0.34375q-0.453125 -0.328125 -0.4375 -1.0zm0.578125 -2.5q0 0.828125 0.3125 1.203125q0.328125 0.375 0.828125 0.375q0.484375 0 0.8125 -0.375q0.328125 -0.375 0.328125 -1.171875q0 -0.765625 -0.34375 -1.140625q-0.34375 -0.390625 -0.8125 -0.390625q-0.46875 0 -0.796875 0.375q-0.328125 0.375 -0.328125 1.125zm6.8398438 0.8125l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m221.33772 107.61836l0 -5.046875l-1.890625 0l0 -0.6875l4.546875 0l0 0.6875l-1.90625 0l0 5.046875l-0.75 0zm2.1875 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9960938 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m317.41818 312.05908l0 -36.251984l0.0630188 0l0 -36.251953" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m317.41818 312.05908l0 -36.251984l0.06298828 0l0 -32.824875" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m317.48117 242.98222l1.1246033 1.124588l-1.1246033 -3.0897675l-1.1245728 3.0897675z" fill-rule="evenodd"/><path fill="#fff2cc" d="m283.1273 259.85834l68.64377 0l0 33.53012c-34.3219 0 -34.3219 12.775604 -68.64377 5.5167236z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m283.1273 259.85834l68.64377 0l0 33.53012c-34.3219 0 -34.3219 12.775604 -68.64377 5.5167236z" fill-rule="evenodd"/><path fill="#000000" d="m298.97064 274.3034l0 -5.734375l4.140625 0l0 0.6875l-3.390625 0l0 1.75l3.171875 0l0 0.671875l-3.171875 0l0 1.953125l3.515625 0l0 0.671875l-4.265625 0zm5.2265625 0l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm4.4335938 0l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm2.4140625 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7773438 0l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 0l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m308.85345 284.3034l0 -5.046875l-1.890625 0l0 -0.6875l4.546875 0l0 0.6875l-1.90625 0l0 5.046875l-0.75 0zm2.1875 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9960938 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m237.83464 239.54568l0 36.125977l0.06300354 0l0 36.125977" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m237.83464 239.54568l0 36.125977l0.06300354 0l0 32.698914" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m237.89764 308.37057l-1.124588 -1.1246033l1.124588 3.0897827l1.1245728 -3.0897827z" fill-rule="evenodd"/><path fill="#fff2cc" d="m203.61153 259.85834l68.64378 0l0 33.53012c-34.321884 0 -34.321884 12.775604 -68.64378 5.5167236z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m203.61153 259.85834l68.64378 0l0 33.53012c-34.321884 0 -34.321884 12.775604 -68.64378 5.5167236z" fill-rule="evenodd"/><path fill="#000000" d="m226.33186 269.3034l0 -5.734375l1.96875 0q0.671875 0 1.015625 0.09375q0.5 0.109375 0.84375 0.40625q0.453125 0.375 0.671875 0.984375q0.234375 0.59375 0.234375 1.359375q0 0.640625 -0.15625 1.15625q-0.15625 0.5 -0.390625 0.828125q-0.234375 0.328125 -0.53125 0.515625q-0.28125 0.1875 -0.6875 0.296875q-0.390625 0.09375 -0.90625 0.09375l-2.0625 0zm0.75 -0.671875l1.21875 0q0.578125 0 0.890625 -0.109375q0.328125 -0.109375 0.515625 -0.296875q0.265625 -0.265625 0.421875 -0.71875q0.15625 -0.46875 0.15625 -1.109375q0 -0.90625 -0.296875 -1.375q-0.296875 -0.484375 -0.71875 -0.65625q-0.3125 -0.109375 -0.984375 -0.109375l-1.203125 0l0 4.375zm7.7773438 -0.671875l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm5.0742188 2.46875l-1.578125 -4.15625l0.734375 0l0.890625 2.484375q0.140625 0.40625 0.265625 0.84375q0.09375 -0.328125 0.265625 -0.796875l0.921875 -2.53125l0.71875 0l-1.5625 4.15625l-0.65625 0zm2.84375 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm4.140625 0.171875l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875z" fill-rule="nonzero"/><path fill="#000000" d="m215.17952 279.3034l0 -5.734375l1.140625 0l1.359375 4.0625q0.1875 0.5625 0.265625 0.84375q0.109375 -0.3125 0.3125 -0.921875l1.375 -3.984375l1.015625 0l0 5.734375l-0.734375 0l0 -4.796875l-1.65625 4.796875l-0.6875 0l-1.65625 -4.875l0 4.875l-0.734375 0zm9.3046875 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.8085938 2.078125l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm7.1523438 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.6835938 2.421875l0.671875 0.109375q0.046875 0.3125 0.25 0.453125q0.25 0.203125 0.703125 0.203125q0.5 0 0.765625 -0.203125q0.265625 -0.1875 0.359375 -0.546875q0.046875 -0.21875 0.046875 -0.90625q-0.46875 0.546875 -1.15625 0.546875q-0.84375 0 -1.3125 -0.609375q-0.46875 -0.625 -0.46875 -1.484375q0 -0.59375 0.203125 -1.09375q0.21875 -0.515625 0.625 -0.78125q0.40625 -0.28125 0.96875 -0.28125q0.734375 0 1.203125 0.59375l0 -0.5l0.65625 0l0 3.59375q0 0.96875 -0.203125 1.375q-0.203125 0.40625 -0.625 0.640625q-0.421875 0.234375 -1.046875 0.234375q-0.75 0 -1.203125 -0.34375q-0.453125 -0.328125 -0.4375 -1.0zm0.578125 -2.5q0 0.828125 0.3125 1.203125q0.328125 0.375 0.828125 0.375q0.484375 0 0.8125 -0.375q0.328125 -0.375 0.328125 -1.171875q0 -0.765625 -0.34375 -1.140625q-0.34375 -0.390625 -0.8125 -0.390625q-0.46875 0 -0.796875 0.375q-0.328125 0.375 -0.328125 1.125zm6.8398438 0.8125l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46873474 -0.6875 1.3281097 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.32810974 0.28125 -0.32810974 1.078125l0 2.265625l-0.703125 0zm5.9804535 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m229.33772 289.3034l0 -5.046875l-1.890625 0l0 -0.6875l4.546875 0l0 0.6875l-1.90625 0l0 5.046875l-0.75 0zm2.1875 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9960938 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m78.42913 236.53041l0 156.9764l134.55118 0" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m78.42913 236.53041l0 156.9764l131.12411 0" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m209.55322 393.5068l-1.1245728 1.1245728l3.0897675 -1.1245728l-3.0897675 -1.1245728z" fill-rule="evenodd"/><path fill="#fff2cc" d="m44.108906 318.0843l68.64378 0l0 33.53012c-34.32189 0 -34.32189 12.775604 -68.64378 5.5167236z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m44.108906 318.0843l68.64378 0l0 33.53012c-34.32189 0 -34.32189 12.775604 -68.64378 5.5167236z" fill-rule="evenodd"/><path fill="#000000" d="m59.95228 332.52936l0 -5.734375l4.140625 0l0 0.6875l-3.390625 0l0 1.75l3.171875 0l0 0.671875l-3.171875 0l0 1.953125l3.515625 0l0 0.671875l-4.265625 0zm5.2265625 0l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm4.4335938 0l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm2.4140625 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7773438 0l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 0l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m69.83509 342.52936l0 -5.046875l-1.890625 0l0 -0.6875l4.546875 0l0 0.6875l-1.90625 0l0 5.046875l-0.75 0zm2.1875 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9960938 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#eeeeee" d="m458.64172 109.49409l120.66144 0l0 41.79528l-120.66144 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m458.64172 109.49409l120.66144 0l0 41.79528l-120.66144 0z" fill-rule="evenodd"/><path fill="#000000" d="m501.5183 122.79985l1.390625 0.34375q-0.4375 1.703125 -1.578125 2.609375q-1.125 0.890625 -2.765625 0.890625q-1.6875 0 -2.75 -0.6875q-1.0625 -0.6875 -1.625 -2.0q-0.546875 -1.3125 -0.546875 -2.8125q0 -1.640625 0.625 -2.859375q0.625 -1.21875 1.78125 -1.84375q1.15625 -0.640625 2.546875 -0.640625q1.5625 0 2.640625 0.8125q1.078125 0.796875 1.5 2.25l-1.375 0.3125q-0.359375 -1.140625 -1.0625 -1.65625q-0.6875 -0.53125 -1.734375 -0.53125q-1.21875 0 -2.03125 0.578125q-0.8125 0.578125 -1.140625 1.5625q-0.328125 0.96875 -0.328125 2.015625q0 1.328125 0.390625 2.328125q0.390625 1.0 1.21875 1.5q0.828125 0.484375 1.78125 0.484375q1.171875 0 1.96875 -0.671875q0.8125 -0.671875 1.09375 -1.984375zm2.943634 3.671875l0 -10.484375l1.28125 0l0 3.75q0.90625 -1.03125 2.28125 -1.03125q0.84375 0 1.46875 0.328125q0.625 0.328125 0.890625 0.921875q0.265625 0.578125 0.265625 1.703125l0 4.8125l-1.28125 0l0 -4.8125q0 -0.96875 -0.421875 -1.40625q-0.421875 -0.4375 -1.1875 -0.4375q-0.578125 0 -1.078125 0.296875q-0.5 0.296875 -0.71875 0.8125q-0.21875 0.5 -0.21875 1.390625l0 4.15625l-1.28125 0zm8.135468 0l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm4.4119263 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.307373 3.796875l0 -7.59375l1.15625 0l0 1.0625q0.34375 -0.5625 0.9375 -0.890625q0.609375 -0.34375 1.359375 -0.34375q0.84375 0 1.375 0.34375q0.546875 0.34375 0.765625 0.984375q0.90625 -1.328125 2.359375 -1.328125q1.125 0 1.734375 0.625q0.609375 0.625 0.609375 1.921875l0 5.21875l-1.28125 0l0 -4.78125q0 -0.78125 -0.125 -1.109375q-0.125 -0.34375 -0.453125 -0.546875q-0.328125 -0.21875 -0.78125 -0.21875q-0.796875 0 -1.328125 0.53125q-0.53125 0.53125 -0.53125 1.703125l0 4.421875l-1.28125 0l0 -4.9375q0 -0.859375 -0.3125 -1.28125q-0.3125 -0.4375 -1.03125 -0.4375q-0.546875 0 -1.015625 0.296875q-0.453125 0.28125 -0.671875 0.828125q-0.203125 0.546875 -0.203125 1.59375l0 3.9375l-1.28125 0zm17.411865 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375z" fill-rule="nonzero"/><path fill="#000000" d="m500.9174 133.98735l1.390625 0l0 6.046875q0 1.59375 -0.359375 2.53125q-0.359375 0.921875 -1.296875 1.5q-0.9375 0.578125 -2.453125 0.578125q-1.46875 0 -2.40625 -0.5q-0.9375 -0.515625 -1.34375 -1.46875q-0.390625 -0.96875 -0.390625 -2.640625l0 -6.046875l1.390625 0l0 6.046875q0 1.375 0.25 2.015625q0.25 0.640625 0.859375 1.0q0.625 0.34375 1.53125 0.34375q1.53125 0 2.171875 -0.6875q0.65625 -0.703125 0.65625 -2.671875l0 -6.046875zm3.5374146 13.390625l0 -10.5l1.171875 0l0 0.984375q0.421875 -0.578125 0.9375 -0.859375q0.515625 -0.296875 1.265625 -0.296875q0.96875 0 1.71875 0.5q0.75 0.5 1.125 1.421875q0.375 0.90625 0.375 1.984375q0 1.171875 -0.421875 2.109375q-0.40625 0.921875 -1.21875 1.421875q-0.796875 0.5 -1.671875 0.5q-0.640625 0 -1.15625 -0.265625q-0.515625 -0.28125 -0.84375 -0.6875l0 3.6875l-1.28125 0zm1.15625 -6.65625q0 1.453125 0.59375 2.15625q0.609375 0.703125 1.453125 0.703125q0.859375 0 1.46875 -0.71875q0.609375 -0.734375 0.609375 -2.25q0 -1.453125 -0.609375 -2.171875q-0.59375 -0.734375 -1.421875 -0.734375q-0.8125 0 -1.453125 0.78125q-0.640625 0.765625 -0.640625 2.234375zm11.916718 3.75l0 -0.953125q-0.71875 1.125 -2.125 1.125q-0.90625 0 -1.671875 -0.5q-0.75 -0.5 -1.171875 -1.390625q-0.421875 -0.90625 -0.421875 -2.078125q0 -1.140625 0.375 -2.0625q0.390625 -0.921875 1.140625 -1.40625q0.765625 -0.5 1.703125 -0.5q0.6875 0 1.21875 0.296875q0.53125 0.28125 0.875 0.734375l0 -3.75l1.28125 0l0 10.484375l-1.203125 0zm-4.0625 -3.796875q0 1.46875 0.609375 2.1875q0.625 0.71875 1.453125 0.71875q0.84375 0 1.4375 -0.6875q0.59375 -0.6875 0.59375 -2.109375q0 -1.5625 -0.609375 -2.28125q-0.59375 -0.734375 -1.484375 -0.734375q-0.84375 0 -1.421875 0.703125q-0.578125 0.703125 -0.578125 2.203125zm12.244873 2.859375q-0.71875 0.609375 -1.375 0.859375q-0.65625 0.25 -1.421875 0.25q-1.25 0 -1.921875 -0.609375q-0.671875 -0.609375 -0.671875 -1.5625q0 -0.5625 0.25 -1.015625q0.25 -0.46875 0.65625 -0.75q0.421875 -0.28125 0.9375 -0.421875q0.375 -0.09375 1.140625 -0.1875q1.5625 -0.1875 2.296875 -0.453125q0.015625 -0.265625 0.015625 -0.328125q0 -0.796875 -0.375 -1.109375q-0.484375 -0.4375 -1.453125 -0.4375q-0.921875 0 -1.359375 0.328125q-0.421875 0.3125 -0.625 1.109375l-1.265625 -0.171875q0.171875 -0.796875 0.5625 -1.296875q0.390625 -0.5 1.140625 -0.765625q0.75 -0.265625 1.71875 -0.265625q0.984375 0 1.59375 0.234375q0.609375 0.21875 0.890625 0.5625q0.28125 0.34375 0.40625 0.875q0.0625 0.328125 0.0625 1.1875l0 1.71875q0 1.796875 0.078125 2.28125q0.078125 0.46875 0.328125 0.90625l-1.34375 0q-0.203125 -0.40625 -0.265625 -0.9375zm-0.109375 -2.875q-0.703125 0.28125 -2.09375 0.484375q-0.796875 0.109375 -1.125 0.265625q-0.328125 0.140625 -0.515625 0.421875q-0.171875 0.265625 -0.171875 0.59375q0 0.515625 0.390625 0.859375q0.390625 0.34375 1.140625 0.34375q0.734375 0 1.3125 -0.3125q0.59375 -0.328125 0.859375 -0.890625q0.203125 -0.4375 0.203125 -1.296875l0 -0.46875zm6.119873 2.65625l0.1875 1.140625q-0.546875 0.109375 -0.984375 0.109375q-0.6875 0 -1.078125 -0.21875q-0.390625 -0.21875 -0.546875 -0.578125q-0.15625 -0.359375 -0.15625 -1.515625l0 -4.375l-0.953125 0l0 -1.0l0.953125 0l0 -1.890625l1.28125 -0.765625l0 2.65625l1.296875 0l0 1.0l-1.296875 0l0 4.4375q0 0.546875 0.0625 0.71875q0.078125 0.15625 0.21875 0.25q0.15625 0.078125 0.453125 0.078125q0.203125 0 0.5625 -0.046875zm6.4625854 -1.296875l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375zm7.166748 4.53125l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0z" fill-rule="nonzero"/><path fill="#eeeeee" d="m620.4934 255.92322l120.66144 0l0 41.795288l-120.66144 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m620.4934 255.92322l120.66144 0l0 41.795288l-120.66144 0z" fill-rule="evenodd"/><path fill="#000000" d="m663.37 269.22897l1.390625 0.34375q-0.4375 1.703125 -1.578125 2.609375q-1.125 0.890625 -2.765625 0.890625q-1.6875 0 -2.75 -0.6875q-1.0625 -0.6875 -1.625 -2.0q-0.546875 -1.3125 -0.546875 -2.8125q0 -1.640625 0.625 -2.859375q0.625 -1.21875 1.78125 -1.84375q1.15625 -0.640625 2.546875 -0.640625q1.5625 0 2.640625 0.8125q1.078125 0.796875 1.5 2.25l-1.375 0.3125q-0.359375 -1.140625 -1.0625 -1.65625q-0.6875 -0.53125 -1.734375 -0.53125q-1.21875 0 -2.03125 0.578125q-0.8125 0.578125 -1.140625 1.5625q-0.328125 0.96875 -0.328125 2.015625q0 1.328125 0.390625 2.328125q0.390625 1.0 1.21875 1.5q0.828125 0.484375 1.78125 0.484375q1.171875 0 1.96875 -0.671875q0.8125 -0.671875 1.09375 -1.984375zm2.9436646 3.671875l0 -10.484375l1.28125 0l0 3.75q0.90625 -1.03125 2.28125 -1.03125q0.84375 0 1.46875 0.328125q0.625 0.328125 0.890625 0.921875q0.265625 0.578125 0.265625 1.703125l0 4.8125l-1.28125 0l0 -4.8125q0 -0.96875 -0.421875 -1.40625q-0.421875 -0.4375 -1.1875 -0.4375q-0.578125 0 -1.078125 0.296875q-0.5 0.296875 -0.71875 0.8125q-0.21875 0.5 -0.21875 1.390625l0 4.15625l-1.28125 0zm8.135498 0l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm4.411865 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.307373 3.796875l0 -7.59375l1.15625 0l0 1.0625q0.34375 -0.5625 0.9375 -0.890625q0.609375 -0.34375 1.359375 -0.34375q0.84375 0 1.375 0.34375q0.546875 0.34375 0.765625 0.984375q0.90625 -1.328125 2.359375 -1.328125q1.125 0 1.734375 0.625q0.609375 0.625 0.609375 1.921875l0 5.21875l-1.28125 0l0 -4.78125q0 -0.78125 -0.125 -1.109375q-0.125 -0.34375 -0.453125 -0.546875q-0.328125 -0.21875 -0.78125 -0.21875q-0.796875 0 -1.328125 0.53125q-0.53125 0.53125 -0.53125 1.703125l0 4.421875l-1.28125 0l0 -4.9375q0 -0.859375 -0.3125 -1.28125q-0.3125 -0.4375 -1.03125 -0.4375q-0.546875 0 -1.015625 0.296875q-0.453125 0.28125 -0.671875 0.828125q-0.203125 0.546875 -0.203125 1.59375l0 3.9375l-1.28125 0zm17.411865 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375z" fill-rule="nonzero"/><path fill="#000000" d="m655.0265 290.90085l0 -10.484375l3.9375 0q1.203125 0 1.921875 0.3125q0.734375 0.3125 1.140625 0.984375q0.40625 0.65625 0.40625 1.375q0 0.671875 -0.375 1.265625q-0.359375 0.59375 -1.09375 0.96875q0.953125 0.28125 1.46875 0.953125q0.515625 0.671875 0.515625 1.578125q0 0.75 -0.3125 1.390625q-0.3125 0.625 -0.78125 0.96875q-0.453125 0.34375 -1.140625 0.515625q-0.6875 0.171875 -1.6875 0.171875l-4.0 0zm1.390625 -6.078125l2.265625 0q0.921875 0 1.3125 -0.125q0.53125 -0.15625 0.796875 -0.515625q0.28125 -0.375 0.28125 -0.921875q0 -0.53125 -0.25 -0.921875q-0.25 -0.390625 -0.71875 -0.53125q-0.46875 -0.15625 -1.59375 -0.15625l-2.09375 0l0 3.171875zm0 4.84375l2.609375 0q0.671875 0 0.9375 -0.046875q0.484375 -0.09375 0.796875 -0.296875q0.328125 -0.203125 0.53125 -0.578125q0.21875 -0.390625 0.21875 -0.890625q0 -0.578125 -0.3125 -1.015625q-0.296875 -0.4375 -0.828125 -0.609375q-0.53125 -0.171875 -1.53125 -0.171875l-2.421875 0l0 3.609375zm8.26001 1.234375l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm4.411865 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm8.713623 3.796875l-2.328125 -7.59375l1.328125 0l1.203125 4.375l0.453125 1.640625q0.03125 -0.125 0.390625 -1.578125l1.21875 -4.4375l1.328125 0l1.125 4.40625l0.390625 1.453125l0.4375 -1.46875l1.296875 -4.390625l1.25 0l-2.375 7.59375l-1.34375 0l-1.203125 -4.546875l-0.296875 -1.296875l-1.53125 5.84375l-1.34375 0zm8.662415 -2.265625l1.265625 -0.203125q0.109375 0.765625 0.59375 1.171875q0.5 0.40625 1.375 0.40625q0.890625 0 1.3125 -0.359375q0.4375 -0.359375 0.4375 -0.84375q0 -0.4375 -0.375 -0.6875q-0.265625 -0.171875 -1.3125 -0.4375q-1.421875 -0.359375 -1.96875 -0.609375q-0.546875 -0.265625 -0.828125 -0.734375q-0.28125 -0.46875 -0.28125 -1.015625q0 -0.515625 0.21875 -0.9375q0.234375 -0.4375 0.640625 -0.734375q0.296875 -0.21875 0.8125 -0.359375q0.53125 -0.15625 1.125 -0.15625q0.890625 0 1.5625 0.265625q0.671875 0.25 1.0 0.6875q0.328125 0.4375 0.4375 1.171875l-1.25 0.171875q-0.09375 -0.578125 -0.5 -0.90625q-0.40625 -0.34375 -1.15625 -0.34375q-0.890625 0 -1.28125 0.296875q-0.375 0.296875 -0.375 0.6875q0 0.25 0.15625 0.453125q0.15625 0.203125 0.5 0.34375q0.1875 0.078125 1.140625 0.328125q1.359375 0.359375 1.890625 0.59375q0.546875 0.234375 0.859375 0.6875q0.3125 0.4375 0.3125 1.09375q0 0.640625 -0.375 1.21875q-0.375 0.5625 -1.09375 0.875q-0.703125 0.3125 -1.59375 0.3125q-1.484375 0 -2.265625 -0.609375q-0.765625 -0.625 -0.984375 -1.828125zm13.046875 -0.1875l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375zm7.166748 4.53125l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m544.79266 151.60104l0 77.71654l0.40942383 0l0 77.71654" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m544.79266 155.02814l0 74.289444l0.40942383 0l0 77.71654" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m544.79266 155.02814l1.1245728 1.124588l-1.1245728 -3.0897675l-1.1245728 3.0897675z" fill-rule="evenodd"/><path fill="#d9d2e9" d="m504.83572 201.67892l79.78281 0l0 41.493332c-39.889282 0 -39.889282 15.964523 -79.78281 7.982254zm6.57312 0l0 -5.379364l79.237885 0l0 41.75363c-3.011963 0 -6.0281982 0.28919983 -6.0281982 0.28919983l0 -36.663467zm6.1783752 -5.379364l0 -5.2492065l79.92444 0l0 41.623474c-3.432495 0 -6.864929 0.21691895 -6.864929 0.21691895l0 -36.591187z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m504.83572 201.67892l79.78281 0l0 41.493332c-39.889282 0 -39.889282 15.964523 -79.78281 7.982254zm6.57312 0l0 -5.379364l79.237885 0l0 41.75363c-3.011963 0 -6.0281982 0.28919983 -6.0281982 0.28919983m-67.03131 -42.04283l0 -5.2492065l79.92444 0l0 41.623474c-3.432495 0 -6.864929 0.21691895 -6.864929 0.21691895" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m504.83572 251.15451c39.893524 7.9822693 39.893524 -7.982254 79.78281 -7.982254l0 -4.8298645c0 0 3.0162354 -0.28919983 6.0281982 -0.28919983l0 -5.162445c0 0 3.432434 -0.21691895 6.864929 -0.21691895l0 -41.623474l-79.92444 0l0 5.2492065l-6.1783752 0l0 5.379364l-6.57312 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m504.83572 201.67892l79.78281 0l0 41.493332c-39.889282 0 -39.889282 15.964523 -79.78281 7.982254zm6.57312 0l0 -5.379364l79.237885 0l0 41.75363c-3.011963 0 -6.0281982 0.28919983 -6.0281982 0.28919983m-67.03131 -42.04283l0 -5.2492065l79.92444 0l0 41.623474c-3.432495 0 -6.864929 0.21691895 -6.864929 0.21691895" fill-rule="evenodd"/><path fill="#000000" d="m519.9771 223.36234l0.765625 0l0 3.3125q0 0.859375 -0.203125 1.375q-0.1875 0.5 -0.703125 0.828125q-0.515625 0.3125 -1.34375 0.3125q-0.796875 0 -1.3125 -0.265625q-0.515625 -0.28125 -0.734375 -0.8125q-0.21875 -0.53125 -0.21875 -1.4375l0 -3.3125l0.765625 0l0 3.3125q0 0.75 0.140625 1.109375q0.140625 0.34375 0.46875 0.53125q0.34375 0.1875 0.828125 0.1875q0.84375 0 1.1875 -0.375q0.359375 -0.375 0.359375 -1.453125l0 -3.3125zm1.9335938 7.328125l0 -5.75l0.640625 0l0 0.546875q0.21875 -0.3125 0.5 -0.46875q0.296875 -0.171875 0.703125 -0.171875q0.53125 0 0.9375 0.28125q0.40625 0.265625 0.609375 0.765625q0.203125 0.5 0.203125 1.09375q0 0.640625 -0.234375 1.15625q-0.21875 0.5 -0.65625 0.78125q-0.4375 0.265625 -0.90625 0.265625q-0.359375 0 -0.640625 -0.140625q-0.28125 -0.15625 -0.453125 -0.390625l0 2.03125l-0.703125 0zm0.640625 -3.640625q0 0.796875 0.3125 1.1875q0.328125 0.375 0.796875 0.375q0.46875 0 0.796875 -0.390625q0.328125 -0.40625 0.328125 -1.234375q0 -0.796875 -0.328125 -1.1875q-0.3125 -0.390625 -0.765625 -0.390625q-0.453125 0 -0.796875 0.421875q-0.34375 0.40625 -0.34375 1.21875zm6.4960938 2.046875l0 -0.53125q-0.390625 0.625 -1.15625 0.625q-0.5 0 -0.921875 -0.265625q-0.40625 -0.28125 -0.640625 -0.765625q-0.21875 -0.5 -0.21875 -1.140625q0 -0.609375 0.203125 -1.109375q0.203125 -0.515625 0.609375 -0.78125q0.421875 -0.28125 0.9375 -0.28125q0.375 0 0.65625 0.171875q0.296875 0.15625 0.484375 0.40625l0 -2.0625l0.703125 0l0 5.734375l-0.65625 0zm-2.21875 -2.078125q0 0.796875 0.328125 1.203125q0.34375 0.390625 0.796875 0.390625q0.46875 0 0.78125 -0.375q0.328125 -0.375 0.328125 -1.15625q0 -0.84375 -0.328125 -1.234375q-0.328125 -0.40625 -0.8125 -0.40625q-0.46875 0 -0.78125 0.390625q-0.3125 0.375 -0.3125 1.1875zm6.6835938 1.5625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm3.3398438 1.453125l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625zm3.5351562 -0.71875l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9023438 2.46875l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm4.9960938 0l0 -5.734375l2.15625 0q0.5625 0 0.875 0.0625q0.421875 0.0625 0.703125 0.265625q0.28125 0.203125 0.453125 0.5625q0.171875 0.34375 0.171875 0.765625q0 0.734375 -0.46875 1.25q-0.453125 0.5 -1.671875 0.5l-1.46875 0l0 2.328125l-0.75 0zm0.75 -3.0l1.484375 0q0.734375 0 1.03125 -0.265625q0.3125 -0.28125 0.3125 -0.78125q0 -0.359375 -0.1875 -0.609375q-0.171875 -0.265625 -0.46875 -0.34375q-0.1875 -0.046875 -0.703125 -0.046875l-1.46875 0l0 2.046875zm4.2265625 0.921875q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm1.296875 -3.40625l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.6210938 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.6367188 1.234375l0.6875 -0.109375q0.0625 0.40625 0.328125 0.640625q0.265625 0.21875 0.75 0.21875q0.484375 0 0.71875 -0.1875q0.234375 -0.203125 0.234375 -0.46875q0 -0.25 -0.203125 -0.375q-0.140625 -0.09375 -0.71875 -0.25q-0.78125 -0.1875 -1.078125 -0.328125q-0.296875 -0.140625 -0.453125 -0.390625q-0.15625 -0.265625 -0.15625 -0.5625q0 -0.28125 0.125 -0.515625q0.140625 -0.234375 0.359375 -0.390625q0.15625 -0.125 0.4375 -0.203125q0.28125 -0.09375 0.609375 -0.09375q0.484375 0 0.859375 0.140625q0.375 0.140625 0.546875 0.390625q0.171875 0.234375 0.234375 0.640625l-0.6875 0.09375q-0.046875 -0.328125 -0.265625 -0.5q-0.21875 -0.1875 -0.640625 -0.1875q-0.484375 0 -0.6875 0.171875q-0.203125 0.15625 -0.203125 0.375q0 0.125 0.078125 0.234375q0.09375 0.125 0.28125 0.1875q0.09375 0.046875 0.609375 0.1875q0.75 0.203125 1.046875 0.328125q0.296875 0.125 0.453125 0.375q0.171875 0.234375 0.171875 0.59375q0 0.34375 -0.203125 0.65625q-0.203125 0.3125 -0.59375 0.484375q-0.375 0.171875 -0.875 0.171875q-0.796875 0 -1.234375 -0.328125q-0.421875 -0.34375 -0.53125 -1.0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m485.21783 151.58989l-0.806427 0l0 52.220474l-147.16208 0" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m485.21783 151.58989l-0.806427 0l0 52.220474l-143.73499 0" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m340.67642 203.81036l1.1246033 -1.1245728l-3.0897827 1.1245728l3.0897827 1.124588z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m351.77167 179.11548l133.44879 0l0 22.456696l-133.44879 0z" fill-rule="evenodd"/><path fill="#595959" d="m384.69724 195.79549l0 -5.734375l3.859375 0l0 0.6875l-3.09375 0l0 1.765625l2.6875 0l0 0.671875l-2.6875 0l0 2.609375l-0.765625 0zm7.6054688 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm5.4492188 1.84375l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625zm3.3945312 -0.890625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm1.296875 1.515625l0 -5.734375l0.703125 0l0 2.0625q0.484375 -0.578125 1.234375 -0.578125q0.46875 0 0.796875 0.1875q0.34375 0.1875 0.484375 0.515625q0.15625 0.3125 0.15625 0.921875l0 2.625l-0.703125 0l0 -2.625q0 -0.53125 -0.234375 -0.765625q-0.21875 -0.25 -0.640625 -0.25q-0.3125 0 -0.59375 0.171875q-0.265625 0.15625 -0.390625 0.4375q-0.109375 0.265625 -0.109375 0.765625l0 2.265625l-0.703125 0zm6.765625 0l0 -5.734375l2.15625 0q0.5625 0 0.875 0.0625q0.421875 0.0625 0.703125 0.265625q0.28125 0.203125 0.453125 0.5625q0.171875 0.34375 0.171875 0.765625q0 0.734375 -0.46875 1.25q-0.453125 0.5 -1.671875 0.5l-1.46875 0l0 2.328125l-0.75 0zm0.75 -3.0l1.484375 0q0.734375 0 1.03125 -0.265625q0.3125 -0.28125 0.3125 -0.78125q0 -0.359375 -0.1875 -0.609375q-0.171875 -0.265625 -0.46875 -0.34375q-0.1875 -0.046875 -0.703125 -0.046875l-1.46875 0l0 2.046875zm4.2265625 0.921875q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm1.296875 -3.40625l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.6210938 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.6367188 1.234375l0.6875 -0.109375q0.0625 0.40625 0.328125 0.640625q0.265625 0.21875 0.75 0.21875q0.484375 0 0.71875 -0.1875q0.234375 -0.203125 0.234375 -0.46875q0 -0.25 -0.203125 -0.375q-0.140625 -0.09375 -0.71875 -0.25q-0.78125 -0.1875 -1.078125 -0.328125q-0.296875 -0.140625 -0.453125 -0.390625q-0.15625 -0.265625 -0.15625 -0.5625q0 -0.28125 0.125 -0.515625q0.140625 -0.234375 0.359375 -0.390625q0.15625 -0.125 0.4375 -0.203125q0.28125 -0.09375 0.609375 -0.09375q0.484375 0 0.859375 0.140625q0.375 0.140625 0.546875 0.390625q0.171875 0.234375 0.234375 0.640625l-0.6875 0.09375q-0.046875 -0.328125 -0.265625 -0.5q-0.21875 -0.1875 -0.640625 -0.1875q-0.484375 0 -0.6875 0.171875q-0.203125 0.15625 -0.203125 0.375q0 0.125 0.078125 0.234375q0.09375 0.125 0.28125 0.1875q0.09375 0.046875 0.609375 0.1875q0.75 0.203125 1.046875 0.328125q0.296875 0.125 0.453125 0.375q0.171875 0.234375 0.171875 0.59375q0 0.34375 -0.203125 0.65625q-0.203125 0.3125 -0.59375 0.484375q-0.375 0.171875 -0.875 0.171875q-0.796875 0 -1.234375 -0.328125q-0.421875 -0.34375 -0.53125 -1.0zm6.5976562 1.234375l0 -5.734375l2.546875 0q0.765625 0 1.15625 0.15625q0.40625 0.15625 0.640625 0.546875q0.234375 0.390625 0.234375 0.859375q0 0.609375 -0.390625 1.03125q-0.390625 0.421875 -1.21875 0.53125q0.296875 0.140625 0.453125 0.28125q0.34375 0.3125 0.640625 0.765625l0.984375 1.5625l-0.953125 0l-0.75 -1.1875q-0.328125 -0.515625 -0.546875 -0.78125q-0.21875 -0.28125 -0.390625 -0.390625q-0.171875 -0.109375 -0.34375 -0.15625q-0.125 -0.03125 -0.421875 -0.03125l-0.875 0l0 2.546875l-0.765625 0zm0.765625 -3.203125l1.625 0q0.515625 0 0.8125 -0.109375q0.296875 -0.109375 0.4375 -0.34375q0.15625 -0.234375 0.15625 -0.515625q0 -0.40625 -0.296875 -0.65625q-0.28125 -0.265625 -0.921875 -0.265625l-1.8125 0l0 1.890625zm5.0117188 3.203125l0 -5.734375l2.15625 0q0.5625 0 0.875 0.0625q0.421875 0.0625 0.703125 0.265625q0.28125 0.203125 0.453125 0.5625q0.171875 0.34375 0.171875 0.765625q0 0.734375 -0.46875 1.25q-0.453125 0.5 -1.671875 0.5l-1.46875 0l0 2.328125l-0.75 0zm0.75 -3.0l1.484375 0q0.734375 0 1.03125 -0.265625q0.3125 -0.28125 0.3125 -0.78125q0 -0.359375 -0.1875 -0.609375q-0.171875 -0.265625 -0.46875 -0.34375q-0.1875 -0.046875 -0.703125 -0.046875l-1.46875 0l0 2.046875zm8.6640625 0.984375l0.765625 0.203125q-0.25 0.921875 -0.875 1.421875q-0.609375 0.484375 -1.5 0.484375q-0.921875 0 -1.515625 -0.375q-0.578125 -0.375 -0.875 -1.09375q-0.296875 -0.71875 -0.296875 -1.53125q0 -0.890625 0.328125 -1.5625q0.34375 -0.671875 0.96875 -1.015625q0.640625 -0.34375 1.40625 -0.34375q0.859375 0 1.4375 0.4375q0.59375 0.4375 0.8125 1.234375l-0.734375 0.171875q-0.203125 -0.625 -0.59375 -0.90625q-0.375 -0.28125 -0.9375 -0.28125q-0.671875 0 -1.109375 0.3125q-0.4375 0.3125 -0.625 0.84375q-0.171875 0.53125 -0.171875 1.109375q0 0.71875 0.203125 1.265625q0.21875 0.546875 0.65625 0.828125q0.453125 0.265625 0.984375 0.265625q0.640625 0 1.078125 -0.359375q0.4375 -0.375 0.59375 -1.109375z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m580.046 392.39658l100.78735 0l0 -94.677185" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m580.046 392.39658l100.787415 0l0 -91.25009" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m680.83344 301.14648l1.1245728 1.1246033l-1.1245728 -3.0897827l-1.1245728 3.0897827z" fill-rule="evenodd"/><path fill="#d9d2e9" d="m634.48663 327.22485l79.78284 0l0 41.493317c-39.889282 0 -39.889282 15.964539 -79.78284 7.9822693zm6.57312 0l0 -5.379364l79.237915 0l0 41.75363c-3.011963 0 -6.0281982 0.2892151 -6.0281982 0.2892151l0 -36.663483zm6.178406 -5.379364l0 -5.2492065l79.92438 0l0 41.623474c-3.432434 0 -6.864868 0.21691895 -6.864868 0.21691895l0 -36.591187z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m634.48663 327.22485l79.78284 0l0 41.493317c-39.889282 0 -39.889282 15.964539 -79.78284 7.9822693zm6.57312 0l0 -5.379364l79.237915 0l0 41.75363c-3.011963 0 -6.0281982 0.2892151 -6.0281982 0.2892151m-67.03131 -42.042847l0 -5.2492065l79.92438 0l0 41.623474c-3.432434 0 -6.864868 0.21691895 -6.864868 0.21691895" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m634.48663 376.70044c39.893555 7.9822693 39.893555 -7.9822693 79.78284 -7.9822693l0 -4.829834c0 0 3.0162354 -0.2892151 6.0281982 -0.2892151l0 -5.162445c0 0 3.432434 -0.21691895 6.864868 -0.21691895l0 -41.623474l-79.92438 0l0 5.2492065l-6.178406 0l0 5.379364l-6.57312 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m634.48663 327.22485l79.78284 0l0 41.493317c-39.889282 0 -39.889282 15.964539 -79.78284 7.9822693zm6.57312 0l0 -5.379364l79.237915 0l0 41.75363c-3.011963 0 -6.0281982 0.2892151 -6.0281982 0.2892151m-67.03131 -42.042847l0 -5.2492065l79.92438 0l0 41.623474c-3.432434 0 -6.864868 0.21691895 -6.864868 0.21691895" fill-rule="evenodd"/><path fill="#000000" d="m645.40735 354.64264l0 -5.734375l2.140625 0q0.65625 0 1.046875 0.1875q0.40625 0.171875 0.625 0.53125q0.234375 0.359375 0.234375 0.75q0 0.375 -0.203125 0.703125q-0.203125 0.3125 -0.609375 0.515625q0.53125 0.15625 0.796875 0.53125q0.28125 0.359375 0.28125 0.859375q0 0.390625 -0.171875 0.75q-0.15625 0.34375 -0.40625 0.53125q-0.25 0.1875 -0.640625 0.28125q-0.375 0.09375 -0.921875 0.09375l-2.171875 0zm0.75 -3.328125l1.234375 0q0.515625 0 0.734375 -0.0625q0.28125 -0.078125 0.421875 -0.28125q0.15625 -0.203125 0.15625 -0.5q0 -0.28125 -0.140625 -0.5q-0.140625 -0.21875 -0.390625 -0.296875q-0.25 -0.078125 -0.875 -0.078125l-1.140625 0l0 1.71875zm0 2.65625l1.421875 0q0.375 0 0.515625 -0.03125q0.265625 -0.046875 0.4375 -0.15625q0.1875 -0.109375 0.296875 -0.3125q0.109375 -0.21875 0.109375 -0.484375q0 -0.328125 -0.171875 -0.5625q-0.15625 -0.234375 -0.453125 -0.328125q-0.28125 -0.09375 -0.828125 -0.09375l-1.328125 0l0 1.96875zm4.5078125 0.671875l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm2.4140625 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm4.7617188 2.078125l-1.265625 -4.15625l0.71875 0l0.65625 2.40625l0.25 0.890625q0.015625 -0.078125 0.21875 -0.859375l0.65625 -2.4375l0.71875 0l0.625 2.40625l0.203125 0.796875l0.25 -0.796875l0.703125 -2.40625l0.6875 0l-1.296875 4.15625l-0.734375 0l-0.65625 -2.484375l-0.15625 -0.703125l-0.84375 3.1875l-0.734375 0zm4.7304688 -1.234375l0.6875 -0.109375q0.0625 0.40625 0.328125 0.640625q0.265625 0.21875 0.75 0.21875q0.484375 0 0.71875 -0.1875q0.234375 -0.203125 0.234375 -0.46875q0 -0.25 -0.203125 -0.375q-0.140625 -0.09375 -0.71875 -0.25q-0.78125 -0.1875 -1.078125 -0.328125q-0.296875 -0.140625 -0.453125 -0.390625q-0.15625 -0.265625 -0.15625 -0.5625q0 -0.28125 0.125 -0.515625q0.140625 -0.234375 0.359375 -0.390625q0.15625 -0.125 0.4375 -0.203125q0.28125 -0.09375 0.609375 -0.09375q0.484375 0 0.859375 0.140625q0.375 0.140625 0.546875 0.390625q0.171875 0.234375 0.234375 0.640625l-0.6875 0.09375q-0.046875 -0.328125 -0.265625 -0.5q-0.21875 -0.1875 -0.640625 -0.1875q-0.484375 0 -0.6875 0.171875q-0.203125 0.15625 -0.203125 0.375q0 0.125 0.078125 0.234375q0.09375 0.125 0.28125 0.1875q0.09375 0.046875 0.609375 0.1875q0.75 0.203125 1.046875 0.328125q0.296875 0.125 0.453125 0.375q0.171875 0.234375 0.171875 0.59375q0 0.34375 -0.203125 0.65625q-0.203125 0.3125 -0.59375 0.484375q-0.375 0.171875 -0.875 0.171875q-0.796875 0 -1.234375 -0.328125q-0.421875 -0.34375 -0.53125 -1.0zm7.125 -0.109375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9023438 2.46875l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm4.9960938 0l0 -5.734375l2.15625 0q0.5625 0 0.875 0.0625q0.421875 0.0625 0.703125 0.265625q0.28125 0.203125 0.453125 0.5625q0.171875 0.34375 0.171875 0.765625q0 0.734375 -0.46875 1.25q-0.453125 0.5 -1.671875 0.5l-1.46875 0l0 2.328125l-0.75 0zm0.75 -3.0l1.484375 0q0.734375 0 1.03125 -0.265625q0.3125 -0.28125 0.3125 -0.78125q0 -0.359375 -0.1875 -0.609375q-0.171875 -0.265625 -0.46875 -0.34375q-0.1875 -0.046875 -0.703125 -0.046875l-1.46875 0l0 2.046875zm4.2265625 0.921875q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm1.296875 -3.40625l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.6210938 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.6367188 1.234375l0.6875 -0.109375q0.0625 0.40625 0.328125 0.640625q0.265625 0.21875 0.75 0.21875q0.484375 0 0.71875 -0.1875q0.234375 -0.203125 0.234375 -0.46875q0 -0.25 -0.203125 -0.375q-0.140625 -0.09375 -0.71875 -0.25q-0.78125 -0.1875 -1.078125 -0.328125q-0.296875 -0.140625 -0.453125 -0.390625q-0.15625 -0.265625 -0.15625 -0.5625q0 -0.28125 0.125 -0.515625q0.140625 -0.234375 0.359375 -0.390625q0.15625 -0.125 0.4375 -0.203125q0.28125 -0.09375 0.609375 -0.09375q0.484375 0 0.859375 0.140625q0.375 0.140625 0.546875 0.390625q0.171875 0.234375 0.234375 0.640625l-0.6875 0.09375q-0.046875 -0.328125 -0.265625 -0.5q-0.21875 -0.1875 -0.640625 -0.1875q-0.484375 0 -0.6875 0.171875q-0.203125 0.15625 -0.203125 0.375q0 0.125 0.078125 0.234375q0.09375 0.125 0.28125 0.1875q0.09375 0.046875 0.609375 0.1875q0.75 0.203125 1.046875 0.328125q0.296875 0.125 0.453125 0.375q0.171875 0.234375 0.171875 0.59375q0 0.34375 -0.203125 0.65625q-0.203125 0.3125 -0.59375 0.484375q-0.375 0.171875 -0.875 0.171875q-0.796875 0 -1.234375 -0.328125q-0.421875 -0.34375 -0.53125 -1.0z" fill-rule="nonzero"/><path fill="#fff2cc" d="m44.077408 109.48587l68.64378 0l0 33.53012c-34.32189 0 -34.32189 12.775589 -68.64378 5.5167236z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m44.077408 109.48587l68.64378 0l0 33.53012c-34.32189 0 -34.32189 12.775589 -68.64378 5.5167236z" fill-rule="evenodd"/><path fill="#000000" d="m59.920784 123.93093l0 -5.734375l4.140625 0l0 0.6875l-3.390625 0l0 1.75l3.171875 0l0 0.671875l-3.171875 0l0 1.953125l3.515625 0l0 0.671875l-4.265625 0zm5.2265625 0l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm4.4335938 0l0 -4.15625l0.640625 0l0 0.640625q0.234375 -0.453125 0.4375 -0.59375q0.21875 -0.140625 0.453125 -0.140625q0.359375 0 0.734375 0.234375l-0.25 0.65625q-0.25 -0.15625 -0.515625 -0.15625q-0.234375 0 -0.421875 0.140625q-0.171875 0.140625 -0.25 0.375q-0.125 0.375 -0.125 0.828125l0 2.171875l-0.703125 0zm2.4140625 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7773438 0l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 0l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m69.8036 133.93092l0 -5.046875l-1.890625 0l0 -0.6875l4.546875 0l0 0.6875l-1.90625 0l0 5.046875l-0.75 0zm2.1875 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9960938 2.078125l0 -5.734375l0.703125 0l0 3.265625l1.671875 -1.6875l0.90625 0l-1.59375 1.546875l1.75 2.609375l-0.859375 0l-1.375 -2.125l-0.5 0.484375l0 1.640625l-0.703125 0zm6.84375 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m336.96588 217.9206l57.88513 0l0 174.48819l57.89438 0" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m336.96588 217.92061l57.88513 0l0 174.48817l54.467316 0" fill-rule="evenodd"/><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m449.31833 392.40878l-1.1246033 1.1246033l3.0897827 -1.1246033l-3.0897827 -1.1245728z" fill-rule="evenodd"/><path fill="#d9d2e9" d="m350.17694 314.47943l79.782776 0l0 41.493347c-39.88925 0 -39.88925 15.964539 -79.782776 7.9822693zm6.57312 0l0 -5.3793335l79.237885 0l0 41.7536c-3.011963 0 -6.0282288 0.2892151 -6.0282288 0.2892151l0 -36.663483zm6.1783752 -5.3793335l0 -5.2492065l79.92441 0l0 41.623474c-3.432434 0 -6.8648987 0.21688843 -6.8648987 0.21688843l0 -36.591156z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m350.17694 314.47943l79.782776 0l0 41.493347c-39.88925 0 -39.88925 15.964539 -79.782776 7.9822693zm6.57312 0l0 -5.3793335l79.237885 0l0 41.7536c-3.011963 0 -6.0282288 0.2892151 -6.0282288 0.2892151m-67.03128 -42.042816l0 -5.2492065l79.92441 0l0 41.623474c-3.432434 0 -6.8648987 0.21688843 -6.8648987 0.21688843" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m350.17694 363.95505c39.893524 7.9822693 39.893524 -7.9822693 79.782776 -7.9822693l0 -4.8298645c0 0 3.0162659 -0.2892151 6.0282288 -0.2892151l0 -5.162445c0 0 3.4324646 -0.21688843 6.8648987 -0.21688843l0 -41.623474l-79.92441 0l0 5.2492065l-6.1783752 0l0 5.3793335l-6.57312 0z" fill-rule="evenodd"/><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m350.17694 314.47943l79.782776 0l0 41.493347c-39.88925 0 -39.88925 15.964539 -79.782776 7.9822693zm6.57312 0l0 -5.3793335l79.237885 0l0 41.7536c-3.011963 0 -6.0282288 0.2892151 -6.0282288 0.2892151m-67.03128 -42.042816l0 -5.2492065l79.92441 0l0 41.623474c-3.432434 0 -6.8648987 0.21688843 -6.8648987 0.21688843" fill-rule="evenodd"/><path fill="#000000" d="m384.32028 329.88162l0.765625 0.203125q-0.25 0.921875 -0.875 1.421875q-0.609375 0.484375 -1.5 0.484375q-0.921875 0 -1.515625 -0.375q-0.578125 -0.375 -0.875 -1.09375q-0.296875 -0.71875 -0.296875 -1.53125q0 -0.890625 0.328125 -1.5625q0.34375 -0.671875 0.96875 -1.015625q0.640625 -0.34375 1.40625 -0.34375q0.859375 0 1.4375 0.4375q0.59375 0.4375 0.8125 1.234375l-0.734375 0.171875q-0.203125 -0.625 -0.59375 -0.90625q-0.375 -0.28125 -0.9375 -0.28125q-0.671875 0 -1.109375 0.3125q-0.4375 0.3125 -0.625 0.84375q-0.171875 0.53125 -0.171875 1.109375q0 0.71875 0.203125 1.265625q0.21875 0.546875 0.65625 0.828125q0.453125 0.265625 0.984375 0.265625q0.640625 0 1.078125 -0.359375q0.4375 -0.375 0.59375 -1.109375zm1.5898438 2.015625l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.5273438 -2.078125q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm6.7148438 2.078125l0 -0.609375q-0.484375 0.703125 -1.3125 0.703125q-0.375 0 -0.703125 -0.140625q-0.3125 -0.140625 -0.46875 -0.34375q-0.140625 -0.21875 -0.203125 -0.53125q-0.046875 -0.203125 -0.046875 -0.65625l0 -2.578125l0.703125 0l0 2.3125q0 0.546875 0.046875 0.734375q0.0625 0.28125 0.265625 0.4375q0.21875 0.15625 0.546875 0.15625q0.3125 0 0.578125 -0.15625q0.28125 -0.171875 0.390625 -0.4375q0.125 -0.28125 0.125 -0.8125l0 -2.234375l0.703125 0l0 4.15625l-0.625 0zm4.4179688 0l0 -0.53125q-0.390625 0.625 -1.15625 0.625q-0.5 0 -0.921875 -0.265625q-0.40625 -0.28125 -0.640625 -0.765625q-0.21875 -0.5 -0.21875 -1.140625q0 -0.609375 0.203125 -1.109375q0.203125 -0.515625 0.609375 -0.78125q0.421875 -0.28125 0.9375 -0.28125q0.375 0 0.65625 0.171875q0.296875 0.15625 0.484375 0.40625l0 -2.0625l0.703125 0l0 5.734375l-0.65625 0zm-2.21875 -2.078125q0 0.796875 0.328125 1.203125q0.34375 0.390625 0.796875 0.390625q0.46875 0 0.78125 -0.375q0.328125 -0.375 0.328125 -1.15625q0 -0.84375 -0.328125 -1.234375q-0.328125 -0.40625 -0.8125 -0.40625q-0.46875 0 -0.78125 0.390625q-0.3125 0.375 -0.3125 1.1875z" fill-rule="nonzero"/><path fill="#000000" d="m367.31442 341.89725l0 -5.734375l1.140625 0l1.359375 4.0625q0.1875 0.5625 0.265625 0.84375q0.109375 -0.3125 0.3125 -0.921875l1.375 -3.984375l1.015625 0l0 5.734375l-0.734375 0l0 -4.796875l-1.65625 4.796875l-0.6875 0l-1.65625 -4.875l0 4.875l-0.734375 0zm9.3046875 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.8085938 2.078125l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm7.1523438 -0.515625q-0.390625 0.328125 -0.75 0.46875q-0.359375 0.140625 -0.78125 0.140625q-0.671875 0 -1.046875 -0.328125q-0.359375 -0.34375 -0.359375 -0.859375q0 -0.3125 0.125 -0.5625q0.140625 -0.25 0.359375 -0.390625q0.234375 -0.15625 0.515625 -0.234375q0.203125 -0.0625 0.625 -0.109375q0.859375 -0.109375 1.25 -0.25q0.015625 -0.140625 0.015625 -0.171875q0 -0.4375 -0.203125 -0.609375q-0.265625 -0.234375 -0.796875 -0.234375q-0.5 0 -0.734375 0.171875q-0.234375 0.171875 -0.359375 0.609375l-0.6875 -0.09375q0.09375 -0.4375 0.3125 -0.703125q0.21875 -0.28125 0.625 -0.421875q0.40625 -0.15625 0.9375 -0.15625q0.53125 0 0.859375 0.125q0.34375 0.125 0.5 0.328125q0.15625 0.1875 0.21875 0.46875q0.03125 0.1875 0.03125 0.65625l0 0.9375q0 0.96875 0.046875 1.234375q0.046875 0.265625 0.171875 0.5l-0.734375 0q-0.109375 -0.21875 -0.140625 -0.515625zm-0.0625 -1.5625q-0.375 0.15625 -1.140625 0.265625q-0.4375 0.0625 -0.625 0.140625q-0.171875 0.078125 -0.265625 0.234375q-0.09375 0.140625 -0.09375 0.328125q0 0.28125 0.203125 0.46875q0.21875 0.1875 0.625 0.1875q0.40625 0 0.71875 -0.171875q0.328125 -0.1875 0.46875 -0.5q0.109375 -0.234375 0.109375 -0.703125l0 -0.25zm1.6835938 2.421875l0.671875 0.109375q0.046875 0.3125 0.25 0.453125q0.25 0.203125 0.703125 0.203125q0.5 0 0.765625 -0.203125q0.265625 -0.1875 0.359375 -0.546875q0.046875 -0.21875 0.046875 -0.90625q-0.46875 0.546875 -1.15625 0.546875q-0.84375 0 -1.3125 -0.609375q-0.46875 -0.625 -0.46875 -1.484375q0 -0.59375 0.203125 -1.09375q0.21875 -0.515625 0.625 -0.78125q0.40625 -0.28125 0.96875 -0.28125q0.734375 0 1.203125 0.59375l0 -0.5l0.65625 0l0 3.59375q0 0.96875 -0.203125 1.375q-0.203125 0.40625 -0.625 0.640625q-0.421875 0.234375 -1.046875 0.234375q-0.75 0 -1.203125 -0.34375q-0.453125 -0.328125 -0.4375 -1.0zm0.578125 -2.5q0 0.828125 0.3125 1.203125q0.328125 0.375 0.828125 0.375q0.484375 0 0.8125 -0.375q0.328125 -0.375 0.328125 -1.171875q0 -0.765625 -0.34375 -1.140625q-0.34375 -0.390625 -0.8125 -0.390625q-0.46875 0 -0.796875 0.375q-0.328125 0.375 -0.328125 1.125zm6.8398438 0.8125l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.203125 -0.3125 0.515625 -0.5q0.328125 -0.1875 0.75 -0.1875q0.453125 0 0.75 0.203125q0.296875 0.1875 0.421875 0.53125q0.484375 -0.734375 1.28125 -0.734375q0.609375 0 0.9375 0.34375q0.34375 0.34375 0.34375 1.0625l0 2.84375l-0.703125 0l0 -2.609375q0 -0.421875 -0.078125 -0.609375q-0.0625 -0.1875 -0.25 -0.296875q-0.171875 -0.125 -0.40625 -0.125q-0.4375 0 -0.734375 0.296875q-0.28125 0.296875 -0.28125 0.9375l0 2.40625l-0.703125 0l0 -2.703125q0 -0.46875 -0.171875 -0.703125q-0.171875 -0.234375 -0.5625 -0.234375q-0.296875 0 -0.5625 0.15625q-0.25 0.15625 -0.359375 0.46875q-0.109375 0.296875 -0.109375 0.859375l0 2.15625l-0.703125 0zm9.5078125 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.9179688 2.46875l0 -4.15625l0.625 0l0 0.59375q0.46875 -0.6875 1.328125 -0.6875q0.375 0 0.6875 0.140625q0.3125 0.140625 0.46875 0.359375q0.15625 0.21875 0.21875 0.515625q0.046875 0.1875 0.046875 0.6875l0 2.546875l-0.703125 0l0 -2.53125q0 -0.421875 -0.09375 -0.625q-0.078125 -0.21875 -0.296875 -0.34375q-0.203125 -0.140625 -0.484375 -0.140625q-0.4375 0 -0.765625 0.296875q-0.328125 0.28125 -0.328125 1.078125l0 2.265625l-0.703125 0zm5.9804688 -0.625l0.109375 0.609375q-0.296875 0.078125 -0.53125 0.078125q-0.390625 0 -0.609375 -0.125q-0.203125 -0.125 -0.296875 -0.3125q-0.078125 -0.203125 -0.078125 -0.84375l0 -2.390625l-0.515625 0l0 -0.546875l0.515625 0l0 -1.015625l0.703125 -0.421875l0 1.4375l0.703125 0l0 0.546875l-0.703125 0l0 2.4375q0 0.296875 0.03125 0.390625q0.046875 0.078125 0.125 0.125q0.078125 0.046875 0.234375 0.046875q0.125 0 0.3125 -0.015625z" fill-rule="nonzero"/><path fill="#000000" d="m376.91013 351.89725l0 -5.734375l2.15625 0q0.5625 0 0.875 0.0625q0.421875 0.0625 0.703125 0.265625q0.28125 0.203125 0.453125 0.5625q0.171875 0.34375 0.171875 0.765625q0 0.734375 -0.46875 1.25q-0.453125 0.5 -1.671875 0.5l-1.46875 0l0 2.328125l-0.75 0zm0.75 -3.0l1.484375 0q0.734375 0 1.03125 -0.265625q0.3125 -0.28125 0.3125 -0.78125q0 -0.359375 -0.1875 -0.609375q-0.171875 -0.265625 -0.46875 -0.34375q-0.1875 -0.046875 -0.703125 -0.046875l-1.46875 0l0 2.046875zm4.2265625 0.921875q0 -1.15625 0.640625 -1.703125q0.53125 -0.46875 1.3125 -0.46875q0.84375 0 1.390625 0.5625q0.546875 0.5625 0.546875 1.546875q0 0.8125 -0.25 1.265625q-0.234375 0.453125 -0.703125 0.71875q-0.453125 0.25 -0.984375 0.25q-0.875 0 -1.421875 -0.5625q-0.53125 -0.5625 -0.53125 -1.609375zm0.71875 0q0 0.796875 0.34375 1.203125q0.359375 0.390625 0.890625 0.390625q0.515625 0 0.859375 -0.390625q0.359375 -0.40625 0.359375 -1.21875q0 -0.78125 -0.359375 -1.171875q-0.34375 -0.390625 -0.859375 -0.390625q-0.53125 0 -0.890625 0.390625q-0.34375 0.390625 -0.34375 1.1875zm3.9804688 2.078125l0 -5.734375l0.703125 0l0 5.734375l-0.703125 0zm1.7929688 -4.921875l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.4804688 -1.515625l0.6875 0.078125q-0.109375 0.71875 -0.578125 1.125q-0.46875 0.40625 -1.140625 0.40625q-0.859375 0 -1.375 -0.546875q-0.515625 -0.5625 -0.515625 -1.609375q0 -0.671875 0.21875 -1.171875q0.234375 -0.5 0.6875 -0.75q0.453125 -0.265625 0.984375 -0.265625q0.671875 0 1.09375 0.34375q0.4375 0.34375 0.5625 0.96875l-0.6875 0.109375q-0.09375 -0.421875 -0.34375 -0.625q-0.25 -0.21875 -0.59375 -0.21875q-0.53125 0 -0.875 0.390625q-0.328125 0.375 -0.328125 1.203125q0 0.828125 0.3125 1.21875q0.328125 0.375 0.84375 0.375q0.421875 0 0.6875 -0.25q0.28125 -0.265625 0.359375 -0.78125zm1.296875 -3.40625l0 -0.8125l0.703125 0l0 0.8125l-0.703125 0zm0 4.921875l0 -4.15625l0.703125 0l0 4.15625l-0.703125 0zm4.6210938 -1.34375l0.71875 0.09375q-0.171875 0.640625 -0.640625 1.0q-0.453125 0.34375 -1.1875 0.34375q-0.90625 0 -1.4375 -0.5625q-0.53125 -0.5625 -0.53125 -1.578125q0 -1.046875 0.53125 -1.625q0.546875 -0.578125 1.40625 -0.578125q0.828125 0 1.359375 0.578125q0.53125 0.5625 0.53125 1.59375q0 0.0625 -0.015625 0.1875l-3.09375 0q0.046875 0.671875 0.390625 1.046875q0.34375 0.359375 0.875 0.359375q0.375 0 0.640625 -0.203125q0.28125 -0.203125 0.453125 -0.65625zm-2.3125 -1.125l2.3125 0q-0.046875 -0.53125 -0.265625 -0.796875q-0.328125 -0.40625 -0.875 -0.40625q-0.484375 0 -0.8125 0.328125q-0.328125 0.328125 -0.359375 0.875zm3.6367188 1.234375l0.6875 -0.109375q0.0625 0.40625 0.328125 0.640625q0.265625 0.21875 0.75 0.21875q0.484375 0 0.71875 -0.1875q0.234375 -0.203125 0.234375 -0.46875q0 -0.25 -0.203125 -0.375q-0.140625 -0.09375 -0.71875 -0.25q-0.78125 -0.1875 -1.078125 -0.328125q-0.296875 -0.140625 -0.453125 -0.390625q-0.15625 -0.265625 -0.15625 -0.5625q0 -0.28125 0.125 -0.515625q0.140625 -0.234375 0.359375 -0.390625q0.15625 -0.125 0.4375 -0.203125q0.28125 -0.09375 0.609375 -0.09375q0.484375 0 0.859375 0.140625q0.375 0.140625 0.546875 0.390625q0.171875 0.234375 0.234375 0.640625l-0.6875 0.09375q-0.046875 -0.328125 -0.265625 -0.5q-0.21875 -0.1875 -0.640625 -0.1875q-0.484375 0 -0.6875 0.171875q-0.203125 0.15625 -0.203125 0.375q0 0.125 0.078125 0.234375q0.09375 0.125 0.28125 0.1875q0.09375 0.046875 0.609375 0.1875q0.75 0.203125 1.046875 0.328125q0.296875 0.125 0.453125 0.375q0.171875 0.234375 0.171875 0.59375q0 0.34375 -0.203125 0.65625q-0.203125 0.3125 -0.59375 0.484375q-0.375 0.171875 -0.875 0.171875q-0.796875 0 -1.234375 -0.328125q-0.421875 -0.34375 -0.53125 -1.0z" fill-rule="nonzero"/></g></svg>
\ No newline at end of file
diff --git a/chrome/installer/mac/third_party/xz/BUILD.gn b/chrome/installer/mac/third_party/xz/BUILD.gn
index f135162..e194826 100644
--- a/chrome/installer/mac/third_party/xz/BUILD.gn
+++ b/chrome/installer/mac/third_party/xz/BUILD.gn
@@ -15,13 +15,16 @@
 _coder_lzma2 = true
 _coder_delta = false
 _coder_bcj_arm = false
+_coder_bcj_arm64 = false
 _coder_bcj_armthumb = false
 _coder_bcj_ia64 = false
 _coder_bcj_powerpc = false
+_coder_bcj_riscv = false
 _coder_bcj_sparc = false
 _coder_bcj_x86 = true
-_coder_simple = _coder_bcj_arm || _coder_bcj_armthumb || _coder_bcj_ia64 ||
-                _coder_bcj_powerpc || _coder_bcj_sparc || _coder_bcj_x86
+_coder_simple = _coder_bcj_arm || _coder_bcj_arm64 || _coder_bcj_armthumb ||
+                _coder_bcj_ia64 || _coder_bcj_powerpc || _coder_bcj_riscv ||
+                _coder_bcj_sparc || _coder_bcj_x86
 _small = true
 
 config("common_config") {
@@ -61,6 +64,9 @@
   visibility = [ ":*" ]
   defines = []
 
+  if (_coder_simple) {
+    defines += [ "HAVE_DECODERS=1" ]
+  }
   if (_coder_lzma1) {
     defines += [ "HAVE_DECODER_LZMA1=1" ]
   }
@@ -73,6 +79,9 @@
   if (_coder_bcj_arm) {
     defines += [ "HAVE_DECODER_ARM=1" ]
   }
+  if (_coder_bcj_arm64) {
+    defines += [ "HAVE_DECODER_ARM64=1" ]
+  }
   if (_coder_bcj_armthumb) {
     defines += [ "HAVE_DECODER_ARMTHUMB=1" ]
   }
@@ -82,6 +91,9 @@
   if (_coder_bcj_powerpc) {
     defines += [ "HAVE_DECODER_POWERPC=1" ]
   }
+  if (_coder_bcj_riscv) {
+    defines += [ "HAVE_DECODER_RISCV=1" ]
+  }
   if (_coder_bcj_sparc) {
     defines += [ "HAVE_DECODER_SPARC=1" ]
   }
@@ -94,6 +106,9 @@
   visibility = [ ":*" ]
   defines = []
 
+  if (_coder_simple) {
+    defines += [ "HAVE_ENCODERS=1" ]
+  }
   if (_coder_lzma1) {
     defines += [ "HAVE_ENCODER_LZMA1=1" ]
   }
@@ -106,6 +121,9 @@
   if (_coder_bcj_arm) {
     defines += [ "HAVE_ENCODER_ARM=1" ]
   }
+  if (_coder_bcj_arm64) {
+    defines += [ "HAVE_ENCODER_ARM64=1" ]
+  }
   if (_coder_bcj_armthumb) {
     defines += [ "HAVE_ENCODER_ARMTHUMB=1" ]
   }
@@ -115,6 +133,9 @@
   if (_coder_bcj_powerpc) {
     defines += [ "HAVE_ENCODER_POWERPC=1" ]
   }
+  if (_coder_bcj_riscv) {
+    defines += [ "HAVE_ENCODER_RISCV=1" ]
+  }
   if (_coder_bcj_sparc) {
     defines += [ "HAVE_ENCODER_SPARC=1" ]
   }
@@ -132,15 +153,19 @@
   ]
 
   sources = [
+    "xz/src/common/tuklib_cpucores.c",
     "xz/src/common/tuklib_physmem.c",
     "xz/src/liblzma/check/check.c",
     "xz/src/liblzma/common/block_util.c",
     "xz/src/liblzma/common/common.c",
     "xz/src/liblzma/common/easy_preset.c",
     "xz/src/liblzma/common/filter_common.c",
+    "xz/src/liblzma/common/hardware_cputhreads.c",
     "xz/src/liblzma/common/hardware_physmem.c",
     "xz/src/liblzma/common/index.c",
+    "xz/src/liblzma/common/outqueue.c",
     "xz/src/liblzma/common/stream_flags_common.c",
+    "xz/src/liblzma/common/string_conversion.c",
     "xz/src/liblzma/common/vli_size.c",
     "xz/src/liblzma/lzma/lzma_encoder_presets.c",
     "xz/src/liblzma/rangecoder/price_table.c",
@@ -190,6 +215,9 @@
   if (_coder_bcj_arm) {
     sources += [ "xz/src/liblzma/simple/arm.c" ]
   }
+  if (_coder_bcj_arm64) {
+    sources += [ "xz/src/liblzma/simple/arm64.c" ]
+  }
   if (_coder_bcj_armthumb) {
     sources += [ "xz/src/liblzma/simple/armthumb.c" ]
   }
@@ -199,6 +227,9 @@
   if (_coder_bcj_powerpc) {
     sources += [ "xz/src/liblzma/simple/powerpc.c" ]
   }
+  if (_coder_bcj_riscv) {
+    sources += [ "xz/src/liblzma/simple/riscv.c" ]
+  }
   if (_coder_bcj_sparc) {
     sources += [ "xz/src/liblzma/simple/sparc.c" ]
   }
@@ -224,13 +255,16 @@
     "xz/src/liblzma/common/block_decoder.c",
     "xz/src/liblzma/common/block_header_decoder.c",
     "xz/src/liblzma/common/easy_decoder_memusage.c",
+    "xz/src/liblzma/common/file_info.c",
     "xz/src/liblzma/common/filter_buffer_decoder.c",
     "xz/src/liblzma/common/filter_decoder.c",
     "xz/src/liblzma/common/filter_flags_decoder.c",
     "xz/src/liblzma/common/index_decoder.c",
     "xz/src/liblzma/common/index_hash.c",
+    "xz/src/liblzma/common/lzip_decoder.c",
     "xz/src/liblzma/common/stream_buffer_decoder.c",
     "xz/src/liblzma/common/stream_decoder.c",
+    "xz/src/liblzma/common/stream_decoder_mt.c",
     "xz/src/liblzma/common/stream_flags_decoder.c",
     "xz/src/liblzma/common/vli_decoder.c",
     "xz/src/liblzma/lz/lz_decoder.c",
@@ -274,6 +308,7 @@
     "xz/src/liblzma/common/index_encoder.c",
     "xz/src/liblzma/common/stream_buffer_encoder.c",
     "xz/src/liblzma/common/stream_encoder.c",
+    "xz/src/liblzma/common/stream_encoder_mt.c",
     "xz/src/liblzma/common/stream_flags_encoder.c",
     "xz/src/liblzma/common/vli_encoder.c",
     "xz/src/liblzma/lz/lz_encoder.c",
@@ -362,7 +397,6 @@
   ]
 
   sources = [
-    "xz/src/common/tuklib_cpucores.c",
     "xz/src/common/tuklib_exit.c",
     "xz/src/common/tuklib_mbstr_fw.c",
     "xz/src/common/tuklib_mbstr_width.c",
@@ -375,6 +409,7 @@
     "xz/src/xz/list.c",
     "xz/src/xz/main.c",
     "xz/src/xz/message.c",
+    "xz/src/xz/mytime.c",
     "xz/src/xz/options.c",
     "xz/src/xz/signals.c",
     "xz/src/xz/suffix.c",
diff --git a/chrome/installer/mac/third_party/xz/LICENSE b/chrome/installer/mac/third_party/xz/LICENSE
index 508c69f..7d81323 100644
--- a/chrome/installer/mac/third_party/xz/LICENSE
+++ b/chrome/installer/mac/third_party/xz/LICENSE
@@ -1,69 +1,89 @@
-What:      XZ Utils license information
-Original:  File xz-5.0.5/COPYING from
-           redistributable_sources/original/557.xz/xz-5.0.5.tar.bz2
-Retrieved: 20-Sep-2013
---------------------------------------------------------------------------------
 
 XZ Utils Licensing
 ==================
 
     Different licenses apply to different files in this package. Here
-    is a rough summary of which licenses apply to which parts of this
-    package (but check the individual files to be sure!):
+    is a summary of which licenses apply to which parts of this package:
 
-      - liblzma is in the public domain.
+      - liblzma is under the BSD Zero Clause License (0BSD).
 
-      - xz, xzdec, and lzmadec command line tools are in the public
-        domain unless GNU getopt_long had to be compiled and linked
-        in from the lib directory. The getopt_long code is under
-        GNU LGPLv2.1+.
+      - The command line tools xz, xzdec, lzmadec, and lzmainfo are
+        under 0BSD except that, on systems that don't have a usable
+        getopt_long, GNU getopt_long is compiled and linked in from the
+        'lib' directory. The getopt_long code is under GNU LGPLv2.1+.
 
       - The scripts to grep, diff, and view compressed files have been
-        adapted from gzip. These scripts and their documentation are
-        under GNU GPLv2+.
+        adapted from GNU gzip. These scripts (xzgrep, xzdiff, xzless,
+        and xzmore) are under GNU GPLv2+. The man pages of the scripts
+        are under 0BSD; they aren't based on the man pages of GNU gzip.
 
-      - All the documentation in the doc directory and most of the
-        XZ Utils specific documentation files in other directories
-        are in the public domain.
+      - Most of the XZ Utils specific documentation that is in
+        plain text files (like README, INSTALL, PACKAGERS, NEWS,
+        and ChangeLog) are under 0BSD unless stated otherwise in
+        the file itself. The files xz-file-format.txt and
+        lzma-file-format.xt are in the public domain but may
+        be distributed under the terms of 0BSD too.
 
-      - Translated messages are in the public domain.
+      - Translated messages and man pages are under 0BSD except that
+        some old translations are in the public domain.
 
-      - The build system contains public domain files, and files that
-        are under GNU GPLv2+ or GNU GPLv3+. None of these files end up
-        in the binaries being built.
+      - Test files and test code in the 'tests' directory, and
+        debugging utilities in the 'debug' directory are under
+        the BSD Zero Clause License (0BSD).
 
-      - Test files and test code in the tests directory, and debugging
-        utilities in the debug directory are in the public domain.
+      - The GNU Autotools based build system contains files that are
+        under GNU GPLv2+, GNU GPLv3+, and a few permissive licenses.
+        These files don't affect the licensing of the binaries being
+        built.
 
-      - The extra directory may contain public domain files, and files
-        that are under various free software licenses.
+      - The 'extra' directory contains files that are under various
+        free software licenses. These aren't built or installed as
+        part of XZ Utils.
 
-    You can do whatever you want with the files that have been put into
-    the public domain. If you find public domain legally problematic,
-    take the previous sentence as a license grant. If you still find
-    the lack of copyright legally problematic, you have too many
-    lawyers.
+    The following command may be helpful in finding per-file license
+    information. It works on xz.git and on a clean file tree extracted
+    from a release tarball.
 
-    As usual, this software is provided "as is", without any warranty.
+        sh build-aux/license-check.sh -v
 
-    If you copy significant amounts of public domain code from XZ Utils
+    For the files under the BSD Zero Clause License (0BSD), if
+    a copyright notice is needed, the following is sufficient:
+
+        Copyright (C) The XZ Utils authors and contributors
+
+    If you copy significant amounts of 0BSD-licensed code from XZ Utils
     into your project, acknowledging this somewhere in your software is
     polite (especially if it is proprietary, non-free software), but
-    naturally it is not legally required. Here is an example of a good
-    notice to put into "about box" or into documentation:
+    it is not legally required by the license terms. Here is an example
+    of a good notice to put into "about box" or into documentation:
 
-        This software includes code from XZ Utils <http://tukaani.org/xz/>.
+        This software includes code from XZ Utils <https://tukaani.org/xz/>.
 
     The following license texts are included in the following files:
+      - COPYING.0BSD: BSD Zero Clause License
       - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1
       - COPYING.GPLv2: GNU General Public License version 2
       - COPYING.GPLv3: GNU General Public License version 3
 
-    Note that the toolchain (compiler, linker etc.) may add some code
-    pieces that are copyrighted. Thus, it is possible that e.g. liblzma
-    binary wouldn't actually be in the public domain in its entirety
-    even though it contains no copyrighted code from the XZ Utils source
-    package.
+    A note about old XZ Utils releases:
 
-    If you have questions, don't hesitate to ask the author(s) for more
-    information.
+        XZ Utils releases 5.4.6 and older and 5.5.1alpha have a
+        significant amount of code put into the public domain and
+        that obviously remains so. The switch from public domain to
+        0BSD for newer releases was made in Febrary 2024 because
+        public domain has (real or perceived) legal ambiguities in
+        some jurisdictions.
+
+        There is very little *practical* difference between public
+        domain and 0BSD. The main difference likely is that one
+        shouldn't claim that 0BSD-licensed code is in the public
+        domain; 0BSD-licensed code is copyrighted but available under
+        an extremely permissive license. Neither 0BSD nor public domain
+        require retaining or reproducing author, copyright holder, or
+        license notices when distributing the software. (Compare to,
+        for example, BSD 2-Clause "Simplified" License which does have
+        such requirements.)
+
+    If you have questions, don't hesitate to ask for more information.
+    The contact information is in the README file.
+
diff --git a/chrome/installer/mac/third_party/xz/README.chromium b/chrome/installer/mac/third_party/xz/README.chromium
index 881d23e..87671b3 100644
--- a/chrome/installer/mac/third_party/xz/README.chromium
+++ b/chrome/installer/mac/third_party/xz/README.chromium
@@ -1,12 +1,12 @@
 Name: XZ Utils
-URL: http://tukaani.org/xz/
-Source URL: http://git.tukaani.org/xz.git
-Version: 5.0.5
-Revision: a1bfda3214ed4a39a28fe609364be133c9f0f200
-Date: 2013-06-30 19:55:49 +0300
-License: Public domain
+URL: https://tukaani.org/xz/
+Source URL: https://github.com/tukaani-project/xz
+Version: 5.6.2
+Revision: 3ec664d3f652133136587a51d4505b1abe1acdd7
+License: 0BSD
 License File: LICENSE
 Shipped: yes
+Security critical: yes
 
 Description:
 XZ Utils is general-purpose data compression software implementing the
@@ -15,33 +15,50 @@
 the license is included in chrome://credits.
 
 Local Modifications:
-None.
+ - codereview.settings is added.
+ - patches/wunreachable-code-break.diff is applied. In xz/src/xz/args.c, the
+   “break” following a call to message_filters_help, a noreturn function, is
+   commented out to avoid triggering a -Wunreachable-code-break warning.
 
 The upstream source is present in the xz directory. Other entries in this
 directory are present for build integration:
-  - README.chromium.
-  - xz.gyp.
-  - config/mac/config.h, the ouptut of a "configure" run. SIZEOF_SIZE_T's
-    definition is made conditional on __LP64__. Various macros are undefined,
-    because feature selection is handled by xz.gyp. These macros are affected:
-     - HAVE_CHECK_CRC32
-     - HAVE_CHECK_CRC64
-     - HAVE_CHECK_SHA256
-     - HAVE_DECODER_ARM
-     - HAVE_DECODER_ARMTHUMB
-     - HAVE_DECODER_DELTA
-     - HAVE_DECODER_IA64
-     - HAVE_DECODER_LZMA1
-     - HAVE_DECODER_LZMA2
-     - HAVE_DECODER_POWERPC
-     - HAVE_DECODER_SPARC
-     - HAVE_DECODER_X86
-     - HAVE_ENCODER_ARM
-     - HAVE_ENCODER_ARMTHUMB
-     - HAVE_ENCODER_DELTA
-     - HAVE_ENCODER_IA64
-     - HAVE_ENCODER_LZMA1
-     - HAVE_ENCODER_LZMA2
-     - HAVE_ENCODER_POWERPC
-     - HAVE_ENCODER_SPARC
-     - HAVE_ENCODER_X86
+  - This README.chromium.
+  - BUILD.gn.
+  - lzma_decompress.export.
+  - A copy of the LICENSE file.
+  - The contents of the patches directory, containing local patches applied to
+    the upstream xz source.
+  - config/mac/config.h, the ouptut of a “configure” run, with these changes:
+     - HAVE_ARM64_CRC32’s definition is made conditional on __arm64__.
+     - SIZEOF_SIZE_T’s definition is made conditional on __LP64__.
+     - Various macros are undefined, because feature selection is handled by
+       BUILD.gn. These transformations can be made by running:
+       sed -E -e 's%^#define (HAVE_(CHECK|(EN|DE)CODER).*) 1$%/* #undef \1 */%'
+       These macros are affected:
+        - HAVE_CHECK_CRC32
+        - HAVE_CHECK_CRC64
+        - HAVE_CHECK_SHA256
+        - HAVE_DECODERS
+        - HAVE_DECODER_ARM
+        - HAVE_DECODER_ARM64
+        - HAVE_DECODER_ARMTHUMB
+        - HAVE_DECODER_DELTA
+        - HAVE_DECODER_IA64
+        - HAVE_DECODER_LZMA1
+        - HAVE_DECODER_LZMA2
+        - HAVE_DECODER_POWERPC
+        - HAVE_DECODER_RISCV
+        - HAVE_DECODER_SPARC
+        - HAVE_DECODER_X86
+        - HAVE_ENCODERS
+        - HAVE_ENCODER_ARM
+        - HAVE_ENCODER_ARM64
+        - HAVE_ENCODER_ARMTHUMB
+        - HAVE_ENCODER_DELTA
+        - HAVE_ENCODER_IA64
+        - HAVE_ENCODER_LZMA1
+        - HAVE_ENCODER_LZMA2
+        - HAVE_ENCODER_POWERPC
+        - HAVE_ENCODER_RISCV
+        - HAVE_ENCODER_SPARC
+        - HAVE_ENCODER_X86
diff --git a/chrome/installer/mac/third_party/xz/config/mac/config.h b/chrome/installer/mac/third_party/xz/config/mac/config.h
index 6bd3e81..3aba4048 100644
--- a/chrome/installer/mac/third_party/xz/config/mac/config.h
+++ b/chrome/installer/mac/third_party/xz/config/mac/config.h
@@ -11,6 +11,12 @@
    language is requested. */
 /* #undef ENABLE_NLS */
 
+/* Define to 1 if ARM64 CRC32 instruction is supported. See configure.ac for
+   details. */
+#if defined(__arm64__)
+#define HAVE_ARM64_CRC32 1
+#endif
+
 /* Define to 1 if bswap_16 is available. */
 /* #undef HAVE_BSWAP_16 */
 
@@ -23,11 +29,20 @@
 /* Define to 1 if you have the <byteswap.h> header file. */
 /* #undef HAVE_BYTESWAP_H */
 
-/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
-   CoreFoundation framework. */
-#define HAVE_CFLOCALECOPYCURRENT 1
+/* Define to 1 if you have the 'cap_rights_limit' function. */
+/* #undef HAVE_CAP_RIGHTS_LIMIT */
 
-/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+/* Define to 1 if the system has the type 'CC_SHA256_CTX'. */
+/* #undef HAVE_CC_SHA256_CTX */
+
+/* Define to 1 if you have the 'CC_SHA256_Init' function. */
+/* #undef HAVE_CC_SHA256_INIT */
+
+/* Define to 1 if you have the Mac OS X function
+   CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */
+#define HAVE_CFLOCALECOPYPREFERREDLANGUAGES 1
+
+/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in
    the CoreFoundation framework. */
 #define HAVE_CFPREFERENCESCOPYAPPVALUE 1
 
@@ -40,17 +55,31 @@
 /* Define to 1 if sha256 integrity check is enabled. */
 /* #undef HAVE_CHECK_SHA256 */
 
+/* Define to 1 if you have the 'clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if 'CLOCK_MONOTONIC' is declared in <time.h>. */
+#define HAVE_CLOCK_MONOTONIC 1
+
+/* Define to 1 if you have the <CommonCrypto/CommonDigest.h> header file. */
+/* #undef HAVE_COMMONCRYPTO_COMMONDIGEST_H */
+
+/* Define to 1 if you have the <cpuid.h> header file. */
+/* #undef HAVE_CPUID_H */
+
 /* Define if the GNU dcgettext() function is already present or preinstalled.
    */
 /* #undef HAVE_DCGETTEXT */
 
-/* Define to 1 if you have the declaration of `program_invocation_name', and
-   to 0 if you don't. */
-#define HAVE_DECL_PROGRAM_INVOCATION_NAME 0
+/* Define to 1 if any of HAVE_DECODER_foo have been defined. */
+/* #undef HAVE_DECODERS */
 
 /* Define to 1 if arm decoder is enabled. */
 /* #undef HAVE_DECODER_ARM */
 
+/* Define to 1 if arm64 decoder is enabled. */
+/* #undef HAVE_DECODER_ARM64 */
+
 /* Define to 1 if armthumb decoder is enabled. */
 /* #undef HAVE_DECODER_ARMTHUMB */
 
@@ -69,6 +98,9 @@
 /* Define to 1 if powerpc decoder is enabled. */
 /* #undef HAVE_DECODER_POWERPC */
 
+/* Define to 1 if riscv decoder is enabled. */
+/* #undef HAVE_DECODER_RISCV */
+
 /* Define to 1 if sparc decoder is enabled. */
 /* #undef HAVE_DECODER_SPARC */
 
@@ -78,9 +110,18 @@
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #define HAVE_DLFCN_H 1
 
+/* Define to 1 if you have the 'elf_aux_info' function. */
+/* #undef HAVE_ELF_AUX_INFO */
+
+/* Define to 1 if any of HAVE_ENCODER_foo have been defined. */
+/* #undef HAVE_ENCODERS */
+
 /* Define to 1 if arm encoder is enabled. */
 /* #undef HAVE_ENCODER_ARM */
 
+/* Define to 1 if arm64 encoder is enabled. */
+/* #undef HAVE_ENCODER_ARM64 */
+
 /* Define to 1 if armthumb encoder is enabled. */
 /* #undef HAVE_ENCODER_ARMTHUMB */
 
@@ -99,48 +140,59 @@
 /* Define to 1 if powerpc encoder is enabled. */
 /* #undef HAVE_ENCODER_POWERPC */
 
+/* Define to 1 if riscv encoder is enabled. */
+/* #undef HAVE_ENCODER_RISCV */
+
 /* Define to 1 if sparc encoder is enabled. */
 /* #undef HAVE_ENCODER_SPARC */
 
 /* Define to 1 if x86 encoder is enabled. */
 /* #undef HAVE_ENCODER_X86 */
 
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
+/* Define to 1 if __attribute__((__constructor__)) is supported for functions.
+ */
+#define HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR 1
 
-/* Define to 1 if you have the `futimens' function. */
-/* #undef HAVE_FUTIMENS */
+/* Define to 1 if you have the 'futimens' function. */
+#define HAVE_FUTIMENS 1
 
-/* Define to 1 if you have the `futimes' function. */
-#define HAVE_FUTIMES 1
+/* Define to 1 if you have the 'futimes' function. */
+/* #undef HAVE_FUTIMES */
 
-/* Define to 1 if you have the `futimesat' function. */
+/* Define to 1 if you have the 'futimesat' function. */
 /* #undef HAVE_FUTIMESAT */
 
+/* Define to 1 if you have the 'getauxval' function. */
+/* #undef HAVE_GETAUXVAL */
+
 /* Define to 1 if you have the <getopt.h> header file. */
 #define HAVE_GETOPT_H 1
 
-/* Define to 1 if you have the `getopt_long' function. */
+/* Define to 1 if you have the 'getopt_long' function. */
 #define HAVE_GETOPT_LONG 1
 
 /* Define if the GNU gettext() function is already present or preinstalled. */
 /* #undef HAVE_GETTEXT */
 
-/* Define if you have the iconv() function. */
+/* Define if you have the iconv() function and it works. */
 #define HAVE_ICONV 1
 
+/* Define to 1 if you have the <immintrin.h> header file. */
+/* #undef HAVE_IMMINTRIN_H */
+
 /* Define to 1 if you have the <inttypes.h> header file. */
 #define HAVE_INTTYPES_H 1
 
-/* Define to 1 if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H 1
+/* Define to 1 if Linux Landlock is supported. See configure.ac for details.
+ */
+/* #undef HAVE_LINUX_LANDLOCK */
+
+/* Define to 1 if .lz (lzip) decompression support is enabled. */
+#define HAVE_LZIP_DECODER 1
 
 /* Define to 1 if mbrtowc and mbstate_t are properly declared. */
 #define HAVE_MBRTOWC 1
 
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
 /* Define to 1 to enable bt2 match finder. */
 #define HAVE_MF_BT2 1
 
@@ -156,15 +208,45 @@
 /* Define to 1 to enable hc4 match finder. */
 #define HAVE_MF_HC4 1
 
+/* Define to 1 if you have the <minix/config.h> header file. */
+/* #undef HAVE_MINIX_CONFIG_H */
+
 /* Define to 1 if getopt.h declares extern int optreset. */
 #define HAVE_OPTRESET 1
 
-/* Define if you have POSIX threads libraries and header files. */
-#define HAVE_PTHREAD 1
+/* Define to 1 if you have the 'pledge' function. */
+/* #undef HAVE_PLEDGE */
+
+/* Define to 1 if you have the 'posix_fadvise' function. */
+/* #undef HAVE_POSIX_FADVISE */
+
+/* Define to 1 if 'program_invocation_name' is declared in <errno.h>. */
+/* #undef HAVE_PROGRAM_INVOCATION_NAME */
+
+/* Define to 1 if you have the 'pthread_condattr_setclock' function. */
+/* #undef HAVE_PTHREAD_CONDATTR_SETCLOCK */
 
 /* Have PTHREAD_PRIO_INHERIT. */
 #define HAVE_PTHREAD_PRIO_INHERIT 1
 
+/* Define to 1 if you have the 'SHA256Init' function. */
+/* #undef HAVE_SHA256INIT */
+
+/* Define to 1 if the system has the type 'SHA256_CTX'. */
+/* #undef HAVE_SHA256_CTX */
+
+/* Define to 1 if you have the <sha256.h> header file. */
+/* #undef HAVE_SHA256_H */
+
+/* Define to 1 if you have the 'SHA256_Init' function. */
+/* #undef HAVE_SHA256_INIT */
+
+/* Define to 1 if the system has the type 'SHA2_CTX'. */
+/* #undef HAVE_SHA2_CTX */
+
+/* Define to 1 if you have the <sha2.h> header file. */
+/* #undef HAVE_SHA2_H */
+
 /* Define to 1 if optimizing for size. */
 /* #undef HAVE_SMALL */
 
@@ -174,6 +256,9 @@
 /* Define to 1 if you have the <stdint.h> header file. */
 #define HAVE_STDINT_H 1
 
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
 /* Define to 1 if you have the <stdlib.h> header file. */
 #define HAVE_STDLIB_H 1
 
@@ -183,24 +268,37 @@
 /* Define to 1 if you have the <string.h> header file. */
 #define HAVE_STRING_H 1
 
-/* Define to 1 if `st_atimensec' is a member of `struct stat'. */
+/* Define to 1 if 'st_atimensec' is a member of 'struct stat'. */
 /* #undef HAVE_STRUCT_STAT_ST_ATIMENSEC */
 
-/* Define to 1 if `st_atimespec.tv_nsec' is a member of `struct stat'. */
+/* Define to 1 if 'st_atimespec.tv_nsec' is a member of 'struct stat'. */
 #define HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC 1
 
-/* Define to 1 if `st_atim.st__tim.tv_nsec' is a member of `struct stat'. */
+/* Define to 1 if 'st_atim.st__tim.tv_nsec' is a member of 'struct stat'. */
 /* #undef HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC */
 
-/* Define to 1 if `st_atim.tv_nsec' is a member of `struct stat'. */
+/* Define to 1 if 'st_atim.tv_nsec' is a member of 'struct stat'. */
 /* #undef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC */
 
-/* Define to 1 if `st_uatime' is a member of `struct stat'. */
+/* Define to 1 if 'st_uatime' is a member of 'struct stat'. */
 /* #undef HAVE_STRUCT_STAT_ST_UATIME */
 
+/* Define to 1 to if GNU/Linux-specific details are unconditionally wanted for
+   symbol versioning. Define to 2 to if these are wanted only if also PIC is
+   defined (allows building both shared and static liblzma at the same time
+   with Libtool if neither --with-pic nor --without-pic is used). This define
+   must be used together with liblzma_linux.map. */
+/* #undef HAVE_SYMBOL_VERSIONS_LINUX */
+
+/* Define to 1 if you have the 'sysctlbyname' function. */
+#define HAVE_SYSCTLBYNAME 1
+
 /* Define to 1 if you have the <sys/byteorder.h> header file. */
 /* #undef HAVE_SYS_BYTEORDER_H */
 
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#define HAVE_SYS_CDEFS_H 1
+
 /* Define to 1 if you have the <sys/endian.h> header file. */
 /* #undef HAVE_SYS_ENDIAN_H */
 
@@ -210,84 +308,119 @@
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #define HAVE_SYS_STAT_H 1
 
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
 /* Define to 1 if you have the <sys/types.h> header file. */
 #define HAVE_SYS_TYPES_H 1
 
-/* Define to 1 if the system has the type `uintptr_t'. */
+/* Define to 1 if the system has the type 'uintptr_t'. */
 #define HAVE_UINTPTR_T 1
 
 /* Define to 1 if you have the <unistd.h> header file. */
 #define HAVE_UNISTD_H 1
 
-/* Define to 1 if you have the `utime' function. */
+/* Define to 1 if _mm_set_epi64x and _mm_clmulepi64_si128 are usable. See
+   configure.ac for details. */
+/* #undef HAVE_USABLE_CLMUL */
+
+/* Define to 1 if you have the 'utime' function. */
 /* #undef HAVE_UTIME */
 
-/* Define to 1 if you have the `utimes' function. */
+/* Define to 1 if you have the 'utimes' function. */
 /* #undef HAVE_UTIMES */
 
 /* Define to 1 or 0, depending whether the compiler supports simple visibility
    declarations. */
 #define HAVE_VISIBILITY 1
 
-/* Define to 1 if you have the `wcwidth' function. */
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the 'wcwidth' function. */
 #define HAVE_WCWIDTH 1
 
-/* Define to 1 if the system has the type `_Bool'. */
+/* Define to 1 if the system has the type '_Bool'. */
 #define HAVE__BOOL 1
 
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
+/* Define to 1 if you have the '_futime' function. */
+/* #undef HAVE__FUTIME */
+
+/* Define to 1 if _mm_movemask_epi8 is available. */
+/* #undef HAVE__MM_MOVEMASK_EPI8 */
+
+/* Define to 1 if the GNU C extension __builtin_assume_aligned is supported.
+ */
+#define HAVE___BUILTIN_ASSUME_ALIGNED 1
+
+/* Define to 1 if the GNU C extensions __builtin_bswap16/32/64 are supported.
+ */
+#define HAVE___BUILTIN_BSWAPXX 1
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
 #define LT_OBJDIR ".libs/"
 
+/* Define to 1 when using POSIX threads (pthreads). */
+#define MYTHREAD_POSIX 1
+
+/* Define to 1 when using Windows Vista compatible threads. This uses features
+   that are not available on Windows XP. */
+/* #undef MYTHREAD_VISTA */
+
+/* Define to 1 when using Windows 95 (and thus XP) compatible threads. This
+   avoids use of features that were added in Windows Vista. */
+/* #undef MYTHREAD_WIN95 */
+
 /* Define to 1 to disable debugging code. */
 #define NDEBUG 1
 
-/* Define to 1 if your C compiler doesn't accept -c and -o together. */
-/* #undef NO_MINUS_C_MINUS_O */
-
 /* Name of package */
 #define PACKAGE "xz"
 
 /* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "lasse.collin@tukaani.org"
+#define PACKAGE_BUGREPORT "xz@tukaani.org"
 
 /* Define to the full name of this package. */
 #define PACKAGE_NAME "XZ Utils"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "XZ Utils 5.0.4"
+#define PACKAGE_STRING "XZ Utils 5.6.2"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "xz"
 
 /* Define to the home page for this package. */
-#define PACKAGE_URL "http://tukaani.org/xz/"
+#define PACKAGE_URL "https://tukaani.org/xz/"
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "5.0.4"
+#define PACKAGE_VERSION "5.6.2"
 
 /* Define to necessary symbol if this constant uses a non-standard name on
    your system. */
 /* #undef PTHREAD_CREATE_JOINABLE */
 
-/* The size of `size_t', as computed by sizeof. */
-#ifdef __LP64__
+/* The size of 'size_t', as computed by sizeof. */
+#if defined(___LP64__)
 #define SIZEOF_SIZE_T 8
 #else
 #define SIZEOF_SIZE_T 4
 #endif
 
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C89 standard headers exist (not just the ones
+   required in a freestanding environment). This macro is provided for
+   backward compatibility; new code need not use it. */
 #define STDC_HEADERS 1
 
 /* Define to 1 if the number of available CPU cores can be detected with
+   cpuset(2). */
+/* #undef TUKLIB_CPUCORES_CPUSET */
+
+/* Define to 1 if the number of available CPU cores can be detected with
    pstat_getdynamic(). */
 /* #undef TUKLIB_CPUCORES_PSTAT_GETDYNAMIC */
 
 /* Define to 1 if the number of available CPU cores can be detected with
+   sched_getaffinity() */
+/* #undef TUKLIB_CPUCORES_SCHED_GETAFFINITY */
+
+/* Define to 1 if the number of available CPU cores can be detected with
    sysconf(_SC_NPROCESSORS_ONLN) or sysconf(_SC_NPROC_ONLN). */
 /* #undef TUKLIB_CPUCORES_SYSCONF */
 
@@ -295,8 +428,8 @@
    sysctl(). */
 #define TUKLIB_CPUCORES_SYSCTL 1
 
-/* Define to 1 if the system supports fast unaligned access to 16-bit and
-   32-bit integers. */
+/* Define to 1 if the system supports fast unaligned access to 16-bit, 32-bit,
+   and 64-bit integers. */
 #define TUKLIB_FAST_UNALIGNED_ACCESS 1
 
 /* Define to 1 if the amount of physical memory can be detected with
@@ -317,40 +450,115 @@
 
 /* Define to 1 if the amount of physical memory can be detected with
    sysconf(_SC_PAGESIZE) and sysconf(_SC_PHYS_PAGES). */
-/* #undef TUKLIB_PHYSMEM_SYSCONF */
+#define TUKLIB_PHYSMEM_SYSCONF 1
 
 /* Define to 1 if the amount of physical memory can be detected with sysctl().
    */
-#define TUKLIB_PHYSMEM_SYSCTL 1
+/* #undef TUKLIB_PHYSMEM_SYSCTL */
 
 /* Define to 1 if the amount of physical memory can be detected with Linux
    sysinfo(). */
 /* #undef TUKLIB_PHYSMEM_SYSINFO */
 
-/* Enable extensions on AIX 3, Interix.  */
+/* Define to 1 to use unsafe type punning, e.g. char *x = ...; *(int *)x =
+   123; which violates strict aliasing rules and thus is undefined behavior
+   and might result in broken code. */
+/* #undef TUKLIB_USE_UNSAFE_TYPE_PUNNING */
+
+/* Enable extensions on AIX, Interix, z/OS.  */
 #ifndef _ALL_SOURCE
 # define _ALL_SOURCE 1
 #endif
+/* Enable general extensions on macOS.  */
+#ifndef _DARWIN_C_SOURCE
+#define _DARWIN_C_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__ 1
+#endif
 /* Enable GNU extensions on systems that have them.  */
 #ifndef _GNU_SOURCE
 # define _GNU_SOURCE 1
 #endif
-/* Enable threading extensions on Solaris.  */
+/* Enable X/Open compliant socket functions that do not require linking
+   with -lxnet on HP-UX 11.11.  */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+#define _HPUX_ALT_XOPEN_SOCKET_API 1
+#endif
+/* Identify the host operating system as Minix.
+   This macro does not affect the system headers' behavior.
+   A future release of Autoconf may stop defining this macro.  */
+#ifndef _MINIX
+/* # undef _MINIX */
+#endif
+/* Enable general extensions on NetBSD.
+   Enable NetBSD compatibility extensions on Minix.  */
+#ifndef _NETBSD_SOURCE
+#define _NETBSD_SOURCE 1
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+   Oddly enough, this does nothing on OpenBSD.  */
+#ifndef _OPENBSD_SOURCE
+#define _OPENBSD_SOURCE 1
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_SOURCE
+/* # undef _POSIX_SOURCE */
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_1_SOURCE
+/* # undef _POSIX_1_SOURCE */
+#endif
+/* Enable POSIX-compatible threading on Solaris.  */
 #ifndef _POSIX_PTHREAD_SEMANTICS
 # define _POSIX_PTHREAD_SEMANTICS 1
 #endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014.  */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014.  */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+#define __STDC_WANT_IEC_60559_BFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015.  */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+#define __STDC_WANT_IEC_60559_DFP_EXT__ 1
+#endif
+/* Enable extensions specified by C23 Annex F.  */
+#ifndef __STDC_WANT_IEC_60559_EXT__
+#define __STDC_WANT_IEC_60559_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015.  */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
+#endif
+/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015.  */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010.  */
+#ifndef __STDC_WANT_LIB_EXT2__
+#define __STDC_WANT_LIB_EXT2__ 1
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009.  */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+#define __STDC_WANT_MATH_SPEC_FUNCS__ 1
+#endif
 /* Enable extensions on HP NonStop.  */
 #ifndef _TANDEM_SOURCE
 # define _TANDEM_SOURCE 1
 #endif
-/* Enable general extensions on Solaris.  */
-#ifndef __EXTENSIONS__
-# define __EXTENSIONS__ 1
+/* Enable X/Open extensions.  Define to 500 only if necessary
+   to make mbstate_t available.  */
+#ifndef _XOPEN_SOURCE
+/* # undef _XOPEN_SOURCE */
 #endif
 
 
 /* Version number of package */
-#define VERSION "5.0.4"
+#define VERSION "5.6.2"
 
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
    significant byte first (like Motorola and SPARC, unlike Intel). */
@@ -364,26 +572,14 @@
 # endif
 #endif
 
-/* Enable large inode numbers on Mac OS X 10.5.  */
-#ifndef _DARWIN_USE_64_BIT_INODE
-# define _DARWIN_USE_64_BIT_INODE 1
-#endif
-
 /* Number of bits in a file offset, on hosts where this is settable. */
 /* #undef _FILE_OFFSET_BITS */
 
-/* Define for large files, on AIX-style hosts. */
+/* Define to 1 on platforms where this makes off_t a 64-bit type. */
 /* #undef _LARGE_FILES */
 
-/* Define to 1 if on MINIX. */
-/* #undef _MINIX */
-
-/* Define to 2 if the system does not provide POSIX.1 features except with
-   this defined. */
-/* #undef _POSIX_1_SOURCE */
-
-/* Define to 1 if you need to in order for `stat' and other things to work. */
-/* #undef _POSIX_SOURCE */
+/* Number of bits in time_t, on hosts where this is settable. */
+/* #undef _TIME_BITS */
 
 /* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
    <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
@@ -404,6 +600,9 @@
    used. */
 /* #undef __GETOPT_PREFIX */
 
+/* Define to 1 on platforms where this makes time_t a 64-bit type. */
+/* #undef __MINGW_USE_VC2005_COMPAT */
+
 /* Define to the type of a signed integer type of width exactly 32 bits if
    such a type exists and the standard includes do not define it. */
 /* #undef int32_t */
diff --git a/chrome/installer/mac/third_party/xz/patches/wunreachable-code-break.diff b/chrome/installer/mac/third_party/xz/patches/wunreachable-code-break.diff
new file mode 100644
index 0000000..4f8fdd7
--- /dev/null
+++ b/chrome/installer/mac/third_party/xz/patches/wunreachable-code-break.diff
@@ -0,0 +1,13 @@
+diff --git a/src/xz/args.c b/src/xz/args.c
+index eba1b97dc464..0eedfa10199e 100644
+--- a/src/xz/args.c
++++ b/src/xz/args.c
+@@ -478,7 +478,7 @@ parse_real(args_info *args, int argc, char **argv)
+ 		case OPT_FILTERS_HELP:
+ 			// This doesn't return.
+ 			message_filters_help();
+-			break;
++			// break;
+ 
+ 		case OPT_X86:
+ 			coder_add_filter(LZMA_FILTER_X86,
diff --git a/chrome/installer/mac/third_party/xz/xz b/chrome/installer/mac/third_party/xz/xz
index eecaf55..10d2363 160000
--- a/chrome/installer/mac/third_party/xz/xz
+++ b/chrome/installer/mac/third_party/xz/xz
@@ -1 +1 @@
-Subproject commit eecaf55632ca72e90eb2641376bce7cdbc7284f7
+Subproject commit 10d236393a338a55830db628356f022a91978b61
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc
index 90f6705..fe78a8b4 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
@@ -885,10 +885,6 @@
                  &ReadAnythingAppController::OnLanguagePrefChange)
       .SetMethod("getLanguagesEnabledInPref",
                  &ReadAnythingAppController::GetLanguagesEnabledInPref)
-      .SetMethod("turnedHighlightOn",
-                 &ReadAnythingAppController::TurnedHighlightOn)
-      .SetMethod("turnedHighlightOff",
-                 &ReadAnythingAppController::TurnedHighlightOff)
       .SetMethod("onHighlightGranularityChanged",
                  &ReadAnythingAppController::OnHighlightGranularityChanged)
       .SetMethod("getLineSpacingValue",
@@ -1556,18 +1552,6 @@
   read_aloud_model_.SetLanguageEnabled(lang, enabled);
 }
 
-void ReadAnythingAppController::TurnedHighlightOn() {
-  auto granularity = read_anything::mojom::HighlightGranularity::kOn;
-  page_handler_->OnHighlightGranularityChanged(granularity);
-  read_aloud_model_.set_highlight_granularity((int)granularity);
-}
-
-void ReadAnythingAppController::TurnedHighlightOff() {
-  auto granularity = read_anything::mojom::HighlightGranularity::kOff;
-  page_handler_->OnHighlightGranularityChanged(granularity);
-  read_aloud_model_.set_highlight_granularity((int)granularity);
-}
-
 void ReadAnythingAppController::OnHighlightGranularityChanged(
     const int granularity) {
   page_handler_->OnHighlightGranularityChanged(
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.h b/chrome/renderer/accessibility/read_anything_app_controller.h
index 2de89193..0475e6d 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.h
+++ b/chrome/renderer/accessibility/read_anything_app_controller.h
@@ -218,8 +218,6 @@
   void OnVoiceChange(const std::string& voice, const std::string& lang);
   void OnLanguagePrefChange(const std::string& lang, bool enabled);
   bool RequiresDistillation();
-  void TurnedHighlightOn();
-  void TurnedHighlightOff();
   void OnHighlightGranularityChanged(int granularity);
   double GetLineSpacingValue(int line_spacing) const;
   double GetLetterSpacingValue(int letter_spacing) const;
diff --git a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
index 85ebff7..5a5d524 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
@@ -356,9 +356,9 @@
 
   bool IsHighlightOn() { return controller_->IsHighlightOn(); }
 
-  void TurnedHighlightOn() { controller_->TurnedHighlightOn(); }
-
-  void TurnedHighlightOff() { controller_->TurnedHighlightOff(); }
+  void OnHighlightGranularityChanged(const int value) {
+    controller_->OnHighlightGranularityChanged(value);
+  }
 
   std::vector<ui::AXNodeID> GetChildren(ui::AXNodeID ax_node_id) {
     return controller_->GetChildren(ax_node_id);
@@ -584,10 +584,16 @@
 };
 
 TEST_F(ReadAnythingAppControllerTest, IsReadAloudEnabled) {
+// Read Aloud is currently only enabled by default on ChromeOS.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  EXPECT_TRUE(IsReadAloudEnabled());
+
+#else
   EXPECT_FALSE(IsReadAloudEnabled());
 
   scoped_feature_list_.InitAndEnableFeature(features::kReadAnythingReadAloud);
   EXPECT_TRUE(IsReadAloudEnabled());
+#endif  // IS_CHROMEOS_ASH
 }
 
 TEST_F(ReadAnythingAppControllerTest, OnLetterSpacingChange_ValidChange) {
@@ -698,6 +704,7 @@
   ASSERT_EQ(GetStoredVoice(), current_voice);
 }
 
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(ReadAnythingAppControllerTest,
        GetStoredVoice_NoAutoSwitching_ReturnsLatestVoiceRegardlessOfLang) {
   std::string current_lang = "it-IT";
@@ -712,6 +719,7 @@
   EXPECT_CALL(page_handler_, OnVoiceChange).Times(2);
   ASSERT_EQ(GetStoredVoice(), current_voice);
 }
+#endif  // !IS_CHROMEOS_ASH
 
 TEST_F(ReadAnythingAppControllerTest, GetStoredVoice_NoVoices_ReturnsEmpty) {
   scoped_feature_list_.InitWithFeatures(
@@ -798,7 +806,7 @@
   int color_value = 0;
   double speech_rate = 1.5;
   std::string voice_value = "Italian voice 3";
-  std::string language_value = "it-IT";
+  std::string language_value = "it";
   base::Value::Dict voices = base::Value::Dict();
   voices.Set(language_value, voice_value);
   base::Value::List languages_enabled_in_pref = base::Value::List();
@@ -807,6 +815,8 @@
       read_anything::mojom::HighlightGranularity::kDefaultValue;
   int highlight_granularity_value = 0;
 
+  SetLanguageCode(language_value);
+
   OnSettingsRestoredFromPrefs(
       line_spacing, letter_spacing, font_name, font_size, links_enabled,
       images_enabled, color, speech_rate, std::move(voices),
@@ -2340,7 +2350,8 @@
                   read_anything::mojom::HighlightGranularity::kOff))
       .Times(0);
 
-  TurnedHighlightOn();
+  OnHighlightGranularityChanged(
+      static_cast<int>(read_anything::mojom::HighlightGranularity::kOn));
 
   EXPECT_TRUE(IsHighlightOn());
 }
@@ -2355,7 +2366,8 @@
                   read_anything::mojom::HighlightGranularity::kOff))
       .Times(1);
 
-  TurnedHighlightOff();
+  OnHighlightGranularityChanged(
+      static_cast<int>(read_anything::mojom::HighlightGranularity::kOff));
 
   EXPECT_FALSE(IsHighlightOn());
 }
diff --git a/chrome/renderer/trusted_vault_encryption_keys_extension.cc b/chrome/renderer/trusted_vault_encryption_keys_extension.cc
index 60283e0..3d45712 100644
--- a/chrome/renderer/trusted_vault_encryption_keys_extension.cc
+++ b/chrome/renderer/trusted_vault_encryption_keys_extension.cc
@@ -82,7 +82,7 @@
 
 // Parses an array of key objects passed to `setClientEncryptionKeys()`.
 // The members of each object are `epoch` integer and `key` ArrayBuffer.
-bool ParseTrustedVaultKeyArray(
+bool ParseTrustedVaultKeyArrayMayDeleteFrame(
     v8::Local<v8::Context> context,
     v8::Local<v8::Array> array,
     std::vector<chrome::mojom::TrustedVaultKeyPtr>* trusted_vault_keys) {
@@ -122,11 +122,20 @@
 // is a map of security domain name strings to encryption_keys: A map of
 // security domain name strings to arrays of objects with members `epoch`
 // integer, and `key` ArrayBuffer.
-bool ParseTrustedVaultKeysFromMap(
+//
+// This method may run property callbacks during parsing of trusted vault key
+// objects, which could end up deleting the frame.
+// TrustedVaultEncryptionKeysExtension is frame-scoped, and therefore may have
+// been destroyed together with the frame by the time this method returns. Hence
+// `callback` must be weakly bound.
+void ParseTrustedVaultKeysFromMapMayDeleteFrame(
     v8::Local<v8::Context> context,
     v8::Local<v8::Map> map,
-    base::flat_map<std::string, std::vector<chrome::mojom::TrustedVaultKeyPtr>>*
-        trusted_vault_keys) {
+    base::OnceCallback<
+        void(std::optional<
+             base::flat_map<std::string,
+                            std::vector<chrome::mojom::TrustedVaultKeyPtr>>>)>
+        callback) {
   std::vector<
       std::pair<std::string, std::vector<chrome::mojom::TrustedVaultKeyPtr>>>
       result;
@@ -136,7 +145,8 @@
     v8::Local<v8::Value> key;
     if (!array->Get(context, i).ToLocal(&key) || !key->IsString()) {
       DVLOG(1) << "invalid map key";
-      return false;
+      std::move(callback).Run(std::nullopt);
+      return;
     }
     const std::string security_domain_name(
         *v8::String::Utf8Value(context->GetIsolate(), key));
@@ -144,22 +154,23 @@
     v8::Local<v8::Value> value;
     if (!array->Get(context, i + 1).ToLocal(&value) || !value->IsArray()) {
       DVLOG(1) << "invalid map value";
-      return false;
+      std::move(callback).Run(std::nullopt);
+      return;
     }
     std::vector<chrome::mojom::TrustedVaultKeyPtr> domain_keys;
-    if (!ParseTrustedVaultKeyArray(context, value.As<v8::Array>(),
-                                   &domain_keys)) {
+    if (!ParseTrustedVaultKeyArrayMayDeleteFrame(context, value.As<v8::Array>(),
+                                                 &domain_keys)) {
       DVLOG(1) << "parsing vault keys failed";
-      return false;
+      std::move(callback).Run(std::nullopt);
+      return;
     }
     result.emplace_back(std::move(security_domain_name),
                         std::move(domain_keys));
   }
-  *trusted_vault_keys =
+  std::move(callback).Run(
       base::flat_map<std::string,
                      std::vector<chrome::mojom::TrustedVaultKeyPtr>>(
-          std::move(result));
-  return true;
+          std::move(result)));
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
 
@@ -405,10 +416,23 @@
     return;
   }
 
-  base::flat_map<std::string, std::vector<chrome::mojom::TrustedVaultKeyPtr>>
-      trusted_vault_keys;
-  if (!ParseTrustedVaultKeysFromMap(context, encryption_keys.As<v8::Map>(),
-                                    &trusted_vault_keys)) {
+  ParseTrustedVaultKeysFromMapMayDeleteFrame(
+      context, encryption_keys.As<v8::Map>(),
+      base::BindOnce(
+          &TrustedVaultEncryptionKeysExtension::SetClientEncryptionKeysContinue,
+          weak_ptr_factory_.GetWeakPtr(), args, std::move(callback),
+          std::move(gaia_id)));
+}
+
+void TrustedVaultEncryptionKeysExtension::SetClientEncryptionKeysContinue(
+    gin::Arguments* args,
+    v8::Local<v8::Function> callback,
+    std::string gaia_id,
+    std::optional<
+        base::flat_map<std::string,
+                       std::vector<chrome::mojom::TrustedVaultKeyPtr>>>
+        trusted_vault_keys) {
+  if (!trusted_vault_keys) {
     DLOG(ERROR) << "Can't parse encryption keys object";
     RecordCallToSetClientEncryptionKeysToUma(kInvalidArgs);
     args->ThrowError();
@@ -421,13 +445,13 @@
     render_frame()->GetRemoteAssociatedInterfaces()->GetInterface(&remote_);
   }
 
-  for (const auto& [security_domain_name, keys] : trusted_vault_keys) {
+  for (const auto& [security_domain_name, keys] : *trusted_vault_keys) {
     trusted_vault::RecordCallToJsSetClientEncryptionKeysWithSecurityDomainToUma(
         trusted_vault::GetSecurityDomainByName(security_domain_name));
   }
 
   remote_->SetEncryptionKeys(
-      gaia_id, std::move(trusted_vault_keys),
+      gaia_id, std::move(*trusted_vault_keys),
       base::BindOnce(
           &TrustedVaultEncryptionKeysExtension::RunCompletionCallback,
           weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/renderer/trusted_vault_encryption_keys_extension.h b/chrome/renderer/trusted_vault_encryption_keys_extension.h
index 8983cbf..4e90a2d 100644
--- a/chrome/renderer/trusted_vault_encryption_keys_extension.h
+++ b/chrome/renderer/trusted_vault_encryption_keys_extension.h
@@ -45,6 +45,14 @@
 #if !BUILDFLAG(IS_ANDROID)
   void SetSyncEncryptionKeys(gin::Arguments* args);
   void SetClientEncryptionKeys(gin::Arguments* args);
+  void SetClientEncryptionKeysContinue(
+      gin::Arguments* args,
+      v8::Local<v8::Function> callback,
+      std::string gaia_id,
+      std::optional<
+          base::flat_map<std::string,
+                         std::vector<chrome::mojom::TrustedVaultKeyPtr>>>
+          trusted_vault_keys);
 #endif
   void AddTrustedSyncEncryptionRecoveryMethod(gin::Arguments* args);
   void RunCompletionCallback(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 9c2234c..9fc83e0 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -520,6 +520,7 @@
     "//components/subresource_filter/content/browser",
     "//components/subresource_filter/content/browser:test_support",
     "//components/subresource_filter/content/shared/browser",
+    "//components/subresource_filter/content/shared/browser:test_support",
     "//components/subresource_filter/core/browser",
     "//components/subresource_filter/core/common",
     "//components/supervised_user/core/browser",
@@ -658,6 +659,7 @@
     public_deps += [
       ":test_support_ui_android",
       "//chrome:chrome_android_core",
+      "//chrome/browser/password_manager/android/access_loss:public",
       "//components/feed/core/v2:feed_core_stubs",
     ]
 
@@ -3090,6 +3092,7 @@
       "../browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc",
       "../browser/ui/search/third_party_ntp_browsertest.cc",
       "../browser/ui/search_engines/search_engine_tab_helper_browsertest.cc",
+      "../browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller_browsertest.cc",
       "../browser/ui/startup/startup_browser_creator_browsertest.cc",
       "../browser/ui/sync/one_click_signin_links_delegate_impl_browsertest.cc",
       "../browser/ui/tab_modal_confirm_dialog_browsertest.cc",
@@ -5375,11 +5378,13 @@
       ]
     }
 
+    if (enterprise_data_controls) {
+      sources += [ "//chrome/browser/enterprise/data_protection/data_protection_clipboard_utils_browsertest.cc" ]
+    }
     if (enterprise_data_controls && !is_android) {
       sources += [
         "//chrome/browser/enterprise/data_controls/desktop_data_controls_dialog_browsertest.cc",
         "//chrome/browser/enterprise/data_protection/clipboard_browsertest.cc",
-        "//chrome/browser/enterprise/data_protection/data_protection_clipboard_utils_browsertest.cc",
       ]
       deps += [ "//chrome/browser/enterprise/data_controls:test_support" ]
     }
@@ -6227,6 +6232,7 @@
     "../browser/policy/chrome_browser_policy_connector_unittest.cc",
     "../browser/policy/cloud/user_policy_signin_service_unittest.cc",
     "../browser/policy/cloud/user_policy_signin_service_util_unittest.cc",
+    "../browser/policy/gen_ai_default_settings_policy_handler_unittest.cc",
     "../browser/policy/homepage_location_policy_handler_unittest.cc",
     "../browser/policy/javascript_policy_handler_unittest.cc",
     "../browser/policy/messaging_layer/public/report_client_unittest.cc",
@@ -6343,6 +6349,7 @@
     "../browser/storage_access_api/storage_access_grant_permission_context_unittest.cc",
     "../browser/storage_access_api/storage_access_header_service_factory_unittest.cc",
     "../browser/storage_access_api/storage_access_header_service_unittest.cc",
+    "../browser/subresource_filter/safe_browsing_child_navigation_throttle_unittest.cc",
     "../browser/subresource_filter/subresource_filter_history_observer_unittest.cc",
     "../browser/supervised_user/classify_url_navigation_throttle_unittest.cc",
     "../browser/supervised_user/supervised_user_browser_utils_unittest.cc",
@@ -10352,10 +10359,16 @@
     ]
   }
 
+  if (enterprise_data_controls) {
+    sources += [ "../browser/enterprise/data_protection/data_protection_clipboard_utils_unittest.cc" ]
+    deps += [
+      "//components/enterprise/data_controls/core/browser:features",
+      "//components/enterprise/data_controls/core/browser:test_support",
+    ]
+  }
   if ((enterprise_data_controls || enterprise_screenshot_protection) &&
       !is_android) {
     sources += [
-      "../browser/enterprise/data_protection/data_protection_clipboard_utils_unittest.cc",
       "../browser/enterprise/data_protection/paste_allowed_request_unittest.cc",
     ]
     deps += [ "../browser/enterprise/data_controls:unit_tests" ]
@@ -10376,12 +10389,6 @@
       "../browser/ui/startup/default_browser_prompt/default_browser_prompt_unittest.cc",
     ]
   }
-
-  if (is_win || is_mac || is_linux || is_chromeos) {
-    sources += [
-      "../browser/policy/gen_ai_default_settings_policy_handler_unittest.cc",
-    ]
-  }
 }
 
 static_library("test_support_unit") {
@@ -10440,7 +10447,10 @@
       "../browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h",
     ]
 
-    deps += [ "//chrome/browser/keyboard_accessory/test_utils/android" ]
+    deps += [
+      "//chrome/browser/keyboard_accessory/test_utils/android",
+      "//chrome/browser/password_manager/android/access_loss:test_support",
+    ]
   } else {
     sources += [
       "../browser/ui/autofill/test_autofill_popup_controller_autofill_client.h",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
index 2baeb857..fddcb633 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
@@ -196,13 +196,12 @@
 
     /** Tears down the AccountManagerFacade mock and signs out if user is signed in. */
     public void tearDownRule() {
-        AccountManagerFacadeProvider.resetInstanceForTests();
         if (mFakeAccountInfoService != null) AccountInfoServiceProvider.resetForTests();
     }
 
     /**
-     * Adds an observer that detects changes in the account state propagated by the
-     * IdentityManager object.
+     * Adds an observer that detects changes in the account state propagated by the IdentityManager
+     * object.
      */
     public void observeIdentityManager(IdentityManager identityManager) {
         identityManager.addObserver(mFakeAccountInfoService);
diff --git a/chrome/test/base/ash/util/BUILD.gn b/chrome/test/base/ash/util/BUILD.gn
index e330ac9..4d603d2 100644
--- a/chrome/test/base/ash/util/BUILD.gn
+++ b/chrome/test/base/ash/util/BUILD.gn
@@ -21,7 +21,11 @@
     "//chrome/browser/apps/app_service",
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/ash/system_web_apps",
+    "//chrome/browser/ui",
     "//chrome/browser/ui/ash/system_web_apps",
+    "//chrome/browser/web_applications:web_applications_test_support",
+    "//chrome/test:test_support",
+    "//content/test:test_support",
     "//storage/browser",
     "//testing/gtest",
     "//ui/aura",
diff --git a/chrome/test/base/ash/util/ash_test_util.cc b/chrome/test/base/ash/util/ash_test_util.cc
index 8366bdc8..db51090 100644
--- a/chrome/test/base/ash/util/ash_test_util.cc
+++ b/chrome/test/base/ash/util/ash_test_util.cc
@@ -18,6 +18,11 @@
 #include "chrome/browser/ash/file_manager/path_util.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
+#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "storage/browser/file_system/external_mount_points.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window.h"
@@ -43,6 +48,33 @@
   return view->GetWidget()->GetNativeWindow()->GetRootWindow();
 }
 
+// Creates the app launch params for `app_type` for testing.
+apps::AppLaunchParams GetAppLaunchParams(Profile* profile,
+                                         ash::SystemWebAppType app_type) {
+  std::optional<webapps::AppId> app_id =
+      ash::GetAppIdForSystemWebApp(profile, app_type);
+  if (!app_id) {
+    NOTREACHED() << "To launch system web apps, you should first call "
+                    "ash::SystemWebAppManager::InstallSystemAppsForTesting in "
+                    "your test.";
+  }
+  return apps::AppLaunchParams(
+      *app_id, apps::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest);
+}
+
+webapps::AppId CreateSystemWebAppImpl(Profile* profile,
+                                      apps::AppLaunchParams params) {
+  const webapps::AppId app_id = params.app_id;
+  base::RunLoop launch_wait;
+  apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithParams(
+      std::move(params),
+      base::BindLambdaForTesting(
+          [&](apps::LaunchResult&& result) { launch_wait.Quit(); }));
+  launch_wait.Run();
+  return app_id;
+}
+
 }  // namespace
 
 void Click(const views::View* view, int flags) {
@@ -83,18 +115,70 @@
   ash::SystemWebAppManager::GetForTest(profile)->InstallSystemAppsForTesting();
 }
 
-void CreateSystemWebApp(Profile* profile, ash::SystemWebAppType app_type) {
-  webapps::AppId app_id = *ash::GetAppIdForSystemWebApp(profile, app_type);
-  apps::AppLaunchParams params(
-      app_id, apps::LaunchContainer::kLaunchContainerWindow,
-      WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest);
+webapps::AppId CreateSystemWebApp(Profile* profile,
+                                  ash::SystemWebAppType app_type,
+                                  std::optional<int32_t> window_id) {
+  apps::AppLaunchParams params = GetAppLaunchParams(profile, app_type);
+  if (window_id) {
+    params.restore_id = *window_id;
+  }
+  return CreateSystemWebAppImpl(profile, std::move(params));
+}
 
-  base::RunLoop launch_wait;
-  apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithParams(
-      std::move(params),
-      base::BindLambdaForTesting(
-          [&](apps::LaunchResult&& result) { launch_wait.Quit(); }));
-  launch_wait.Run();
+webapps::AppId CreateOsUrlHandlerSystemWebApp(Profile* profile,
+                                              int32_t window_id,
+                                              const GURL& override_url) {
+  apps::AppLaunchParams params =
+      GetAppLaunchParams(profile, ash::SystemWebAppType::OS_URL_HANDLER);
+  params.restore_id = window_id;
+  params.override_url = override_url;
+  return CreateSystemWebAppImpl(profile, std::move(params));
+}
+
+Browser* CreateBrowser(Profile* profile,
+                       const std::vector<GURL>& urls,
+                       std::optional<size_t> active_url_index) {
+  Browser::CreateParams params(Browser::TYPE_NORMAL, profile,
+                               /*user_gesture=*/false);
+  Browser* browser = Browser::Create(params);
+  // Create a new tab and make sure the urls have loaded.
+  for (size_t i = 0; i < urls.size(); i++) {
+    content::TestNavigationObserver navigation_observer(urls[i]);
+    navigation_observer.StartWatchingNewWebContents();
+    chrome::AddTabAt(
+        browser, urls[i], /*index=*/-1,
+        /*foreground=*/!active_url_index || active_url_index.value() == i);
+    navigation_observer.Wait();
+  }
+  return browser;
+}
+
+Browser* CreateAndShowBrowser(Profile* profile,
+                              const std::vector<GURL>& urls,
+                              std::optional<size_t> active_url_index) {
+  Browser* browser = CreateBrowser(profile, urls, active_url_index);
+  browser->window()->Show();
+  return browser;
+}
+
+Browser* InstallAndLaunchPWA(Profile* profile,
+                             const GURL& start_url,
+                             bool launch_in_browser,
+                             const std::u16string& app_title) {
+  auto web_app_info =
+      web_app::WebAppInstallInfo::CreateWithStartUrlForTesting(start_url);
+  web_app_info->scope = start_url.GetWithoutFilename();
+  if (!launch_in_browser) {
+    web_app_info->user_display_mode =
+        web_app::mojom::UserDisplayMode::kStandalone;
+  }
+  web_app_info->title = app_title;
+  const webapps::AppId app_id =
+      web_app::test::InstallWebApp(profile, std::move(web_app_info));
+
+  return launch_in_browser
+             ? web_app::LaunchBrowserForWebAppInTab(profile, app_id)
+             : web_app::LaunchWebAppBrowserAndWait(profile, app_id);
 }
 
 }  // namespace ash::test
diff --git a/chrome/test/base/ash/util/ash_test_util.h b/chrome/test/base/ash/util/ash_test_util.h
index c1b08507..1a232ed 100644
--- a/chrome/test/base/ash/util/ash_test_util.h
+++ b/chrome/test/base/ash/util/ash_test_util.h
@@ -6,10 +6,13 @@
 #define CHROME_TEST_BASE_ASH_UTIL_ASH_TEST_UTIL_H_
 
 #include <string_view>
+#include <vector>
 
 #include "ash/webui/system_apps/public/system_web_app_type.h"
+#include "components/webapps/common/web_app_id.h"
 #include "ui/events/event_constants.h"
 
+class Browser;
 class Profile;
 
 namespace base {
@@ -37,7 +40,31 @@
 
 // Creates a system web app window (os settings, camera, files, etc.). Note that
 // a test needs to call `InstallSystemWebAppsForTesting()` prior to using this.
-void CreateSystemWebApp(Profile* profile, ash::SystemWebAppType app_type);
+webapps::AppId CreateSystemWebApp(
+    Profile* profile,
+    ash::SystemWebAppType app_type,
+    std::optional<int32_t> window_id = std::nullopt);
+
+// Creates a OS URL handler system web with given `window_id` and
+// `override_url`.
+webapps::AppId CreateOsUrlHandlerSystemWebApp(Profile* profile,
+                                              int32_t window_id,
+                                              const GURL& override_url);
+// Creates a browser and tabs with given `urls`. The active tab is indicated by
+// `active_url_index`. The browser is not shown after creation.
+Browser* CreateBrowser(Profile* profile,
+                       const std::vector<GURL>& urls,
+                       std::optional<size_t> active_url_index);
+
+Browser* CreateAndShowBrowser(
+    Profile* profile,
+    const std::vector<GURL>& urls,
+    std::optional<size_t> active_url_index = std::nullopt);
+
+Browser* InstallAndLaunchPWA(Profile* profile,
+                             const GURL& start_url,
+                             bool launch_in_browser,
+                             const std::u16string& app_title = u"A Web App");
 
 }  // namespace ash::test
 
diff --git a/chrome/test/data/banners/link_capturing/launch_detector.js b/chrome/test/data/banners/link_capturing/launch_detector.js
index 965d15a..7d5e850 100644
--- a/chrome/test/data/banners/link_capturing/launch_detector.js
+++ b/chrome/test/data/banners/link_capturing/launch_detector.js
@@ -52,3 +52,12 @@
     domAutomationController.send(doneMessage);
   }, delay);
 }
+
+function showParams(params) {
+  let output = decodeURI(params);
+  console.log('Query params passed in: ' + output);
+  // Make the query params easier to read on the page.
+  output = output.replace('?', '\n');
+  output = output.replace('&', '\n');
+  document.getElementById('debug').textContent = 'Params: ' + output;
+}
diff --git a/chrome/test/data/banners/link_capturing/scope_a/destination.html b/chrome/test/data/banners/link_capturing/scope_a/destination.html
index 68e5d29..aca2a67 100644
--- a/chrome/test/data/banners/link_capturing/scope_a/destination.html
+++ b/chrome/test/data/banners/link_capturing/scope_a/destination.html
@@ -5,10 +5,11 @@
   <script src="../launch_detector.js"></script>
 </head>
 
-<body onload="signalNavigationComplete(/*delay=*/ 0)">
+<body onload="signalNavigationComplete(/*delay=*/ 0); showParams(location.search);">
   <!-- Use `delay` to slow down execution of the test (so that you can
     see what is happening during manual runs). -->
   <h1>Destination in scope A</h1>
+  <pre id="debug"></pre>
 </body>
 
-</html>
\ No newline at end of file
+</html>
diff --git a/chrome/test/data/banners/link_capturing/scope_a/start.html b/chrome/test/data/banners/link_capturing/scope_a/start.html
index 3fff51d..59214cc 100644
--- a/chrome/test/data/banners/link_capturing/scope_a/start.html
+++ b/chrome/test/data/banners/link_capturing/scope_a/start.html
@@ -1,6 +1,7 @@
 <html>
 
 <head>
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Web app scope_a test page for link capturing tests</title>
   <script src="../launch_detector.js"></script>
   <script>
@@ -30,24 +31,58 @@
       }, delay);
     }
 
+    function getModifierString(event) {
+      let ctrl = event.ctrlKey;
+      let shift = event.shiftKey;
+      let meta = event.metaKey;
+      let left = event.button == 0;
+      let middle = event.button == 1;
+
+      if ((ctrl && left) || (meta && left)) {
+        middle = true;
+        left = false;
+        ctrl = false;
+        meta = false;
+      }
+
+      let modifier = 'click=';
+      if (ctrl) modifier += 'Ctrl ';
+      if (meta) modifier += 'Meta ';
+      if (shift) modifier += 'Shift ';
+      if (left) modifier += 'Left ';
+      if (middle) modifier += 'Middle ';
+      return modifier;
+    }
+
     window.addEventListener("load", async () => {
       navigator.serviceWorker.register("sw.js");
       serviceWorkerRegistration = await navigator.serviceWorker.ready;
       console.assert(serviceWorkerRegistration);
 
-      var links = document.querySelectorAll('.linkB, .linkX');
+      var links = document.querySelectorAll('.linkA, .linkB, .linkX');
       for (let link of links) {
-        let destination = link.classList.contains('linkB')
-            ? bDestinationUrl : xDestinationUrl;
-        link.setAttribute('href', destination);
+        link.addEventListener("click", (event) => {
+          // Pass the ID as a query param, so we can show it on the destination
+          // page.
+          let param = '?' + link.id + '&' + getModifierString(event);
+          let destination = link.classList.contains('linkA') ? aDestinationUrl :
+          link.classList.contains('linkB') ? bDestinationUrl : xDestinationUrl;
+          destination += param;
+          link.setAttribute('href', destination);
+        });
       }
       var buttons = document.querySelectorAll('.btnA, .btnB, .btnX');
       for (let button of buttons) {
-        button.addEventListener("click", () => {
+        button.addEventListener("click", (event) => {
+          // Pass the ID as a query param, so we can show it on the destination
+          // page.
+          let param = '?' + button.id + '&' + getModifierString(event);
+
           let target = button.getAttribute("data-target");
           let rel = button.getAttribute("data-rel");
           let url = button.classList.contains('btnA') ? aDestinationUrl :
           button.classList.contains('btnB') ? bDestinationUrl : xDestinationUrl;
+          url += param;
           if (rel) {
             window.open(url, target, rel);
           } else {
@@ -67,7 +102,7 @@
 <h1>Start page scope A</h1>
 
 <table>
-<tr><td><h2>Same scope (A)</h2></td><td><h2>Scope B</h2></td><td><h2>Scope X</h2></td></tr>
+<tr><td width="250px"><h2>Same scope (A)</h2></td><td width="250px"><h2>Scope B</h2></td><td width="250px"><h2>Scope X</h2></td></tr>
 <tr>
 <td>
 <!-- Links to same scope-->
diff --git a/chrome/test/data/banners/link_capturing/scope_b/destination.html b/chrome/test/data/banners/link_capturing/scope_b/destination.html
index 7e47980b..620aa987 100644
--- a/chrome/test/data/banners/link_capturing/scope_b/destination.html
+++ b/chrome/test/data/banners/link_capturing/scope_b/destination.html
@@ -5,10 +5,11 @@
   <script src="../launch_detector.js"></script>
 </head>
 
-<body onload="signalNavigationComplete(/*delay=*/ 0)">
+<body onload="signalNavigationComplete(/*delay=*/ 0); showParams(location.search);">
   <!-- Use `delay` to slow down execution of the test (so that you can
     see what is happening during manual runs). -->
   <h1>Destination in scope B</h1>
+  <pre id="debug"></pre>
 </body>
 
-</html>
\ No newline at end of file
+</html>
diff --git a/chrome/test/data/banners/link_capturing/scope_x/destination.html b/chrome/test/data/banners/link_capturing/scope_x/destination.html
index 35d63736..2f18147 100644
--- a/chrome/test/data/banners/link_capturing/scope_x/destination.html
+++ b/chrome/test/data/banners/link_capturing/scope_x/destination.html
@@ -5,10 +5,11 @@
   <script src="../launch_detector.js"></script>
 </head>
 
-<body onload="signalNavigationComplete(/*delay=*/ 0)">
+<body onload="signalNavigationComplete(/*delay=*/ 0); showParams(location.search);">
   <!-- Use `delay` to slow down execution of the test (so that you can
     see what is happening during manual runs). -->
   <h1>Destination in scope X (not installed)</h1>
+  <pre id="debug"></pre>
 </body>
 
 </html>
diff --git a/chrome/test/data/web_apps/link_capture_test_input.json b/chrome/test/data/web_apps/link_capture_test_input.json
index 820d3b9..d0a0332 100644
--- a/chrome/test/data/web_apps/link_capture_test_input.json
+++ b/chrome/test/data/web_apps/link_capture_test_input.json
@@ -15019,7 +15019,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15058,7 +15058,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15097,7 +15097,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15136,7 +15136,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15175,7 +15175,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15214,7 +15214,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15253,7 +15253,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15292,7 +15292,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15331,7 +15331,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15374,7 +15374,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15417,7 +15417,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15460,7 +15460,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15503,7 +15503,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15546,7 +15546,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15589,7 +15589,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -15632,7 +15632,7 @@
          }
       },
       "CaptureOn_AppWnd_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -18516,7 +18516,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2B_Direct_ViaLink_ShiftClick_WithoutOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19473,7 +19473,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19503,7 +19503,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19533,7 +19533,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19563,7 +19563,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19593,7 +19593,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19623,7 +19623,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19653,7 +19653,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19683,7 +19683,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_MiddleClick_WithoutOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19713,7 +19713,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19747,7 +19747,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19781,7 +19781,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19815,7 +19815,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19849,7 +19849,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetBlank": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19883,7 +19883,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19917,7 +19917,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetNoFrame": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
@@ -19951,7 +19951,7 @@
          }
       },
       "CaptureOn_Tab_ScopeA2X_Direct_ViaLink_ShiftClick_WithoutOpener_TargetSelf": {
-         "disabled": true,
+         "disabled": false,
          "expected_state": {
             "browsers": [ {
                "browser_type": "TYPE_NORMAL",
diff --git a/chrome/test/data/webui/chromeos/sanitize_ui/sanitize_ui_test.ts b/chrome/test/data/webui/chromeos/sanitize_ui/sanitize_ui_test.ts
index f542c96e..504eb61 100644
--- a/chrome/test/data/webui/chromeos/sanitize_ui/sanitize_ui_test.ts
+++ b/chrome/test/data/webui/chromeos/sanitize_ui/sanitize_ui_test.ts
@@ -33,7 +33,7 @@
     // Verify the header element exists
     assert(titleDiv);
     // Check the header content
-    assertEquals('Your device is sanitized', titleDiv!.textContent);
+    assertEquals('Safety reset has been completed', titleDiv!.textContent);
   });
 
   test('SanitizeDoneAccordionsAndLinksTest', async () => {
diff --git a/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts b/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts
index 30d7f7d..98526a2 100644
--- a/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts
@@ -356,12 +356,12 @@
     }
 
     function emitHighlight(highlightOn: boolean) {
-      if (highlightOn) {
-        chrome.readingMode.turnedHighlightOn();
-      } else {
-        chrome.readingMode.turnedHighlightOff();
-      }
-      emitEvent(app, ToolbarEvent.HIGHLIGHT_TOGGLE);
+      const highlightValue = highlightOn ? chrome.readingMode.autoHighlighting :
+                                           chrome.readingMode.noHighlighting;
+      chrome.readingMode.onHighlightGranularityChanged(highlightValue);
+      emitEvent(app, ToolbarEvent.HIGHLIGHT_CHANGE, {
+        detail: {data: highlightValue},
+      });
       return microtasksFinished();
     }
 
diff --git a/chrome/test/data/webui/side_panel/read_anything/app_style_updater_test.ts b/chrome/test/data/webui/side_panel/read_anything/app_style_updater_test.ts
index 2192f92..ad58244 100644
--- a/chrome/test/data/webui/side_panel/read_anything/app_style_updater_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/app_style_updater_test.ts
@@ -99,7 +99,8 @@
       '--color-read-anything-current-read-aloud-highlight-dark':
           expectedDarkColor,
     });
-    chrome.readingMode.turnedHighlightOn();
+    chrome.readingMode.onHighlightGranularityChanged(
+        chrome.readingMode.autoHighlighting);
     chrome.readingMode.colorTheme = chrome.readingMode.yellowTheme;
     updater.setHighlight();
     assertEquals(
@@ -110,7 +111,8 @@
     assertEquals(
         expectedDarkColor, computeStyle('--current-highlight-bg-color'));
 
-    chrome.readingMode.turnedHighlightOff();
+    chrome.readingMode.onHighlightGranularityChanged(
+        chrome.readingMode.noHighlighting);
     chrome.readingMode.colorTheme = chrome.readingMode.lightTheme;
     updater.setHighlight();
     assertEquals('transparent', computeStyle('--current-highlight-bg-color'));
@@ -195,7 +197,8 @@
       '--color-read-anything-link-visited-yellow': expectedYellowLinkVisited,
       '--color-read-anything-link-visited-dark': expectedDarkLinkVisited,
     });
-    chrome.readingMode.turnedHighlightOn();
+    chrome.readingMode.onHighlightGranularityChanged(
+        chrome.readingMode.autoHighlighting);
 
     // Verify default theme colors.
     chrome.readingMode.colorTheme = chrome.readingMode.defaultTheme;
@@ -263,7 +266,8 @@
     chrome.readingMode.letterSpacing = 3;
     chrome.readingMode.fontName = 'Andika';
     chrome.readingMode.colorTheme = chrome.readingMode.blueTheme;
-    chrome.readingMode.turnedHighlightOn();
+    chrome.readingMode.onHighlightGranularityChanged(
+        chrome.readingMode.autoHighlighting);
     const expectedBlueBackground = 'rgb(1, 2, 3)';
     const expectedBlueForeground = 'rgb(4, 5, 6)';
     const expectedBlueCurrentHighlight = 'rgb(7, 8, 9)';
diff --git a/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts b/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts
index 8b238ea..5a13e80a 100644
--- a/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts
@@ -1,47 +1,92 @@
 // Copyright 2024 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-
 import 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
 
+import {BrowserProxy} from '//resources/cr_components/color_change_listener/browser_proxy.js';
+import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
 import {flush} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {ToolbarEvent} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import type {HighlightMenu} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import {assertEquals} from 'chrome-untrusted://webui-test/chai_assert.js';
+import type {AppElement, ReadAnythingToolbarElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+import {assertEquals, assertStringContains, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
 
-import {emitEventWithTarget, suppressInnocuousErrors} from './common.js';
+import {stubAnimationFrame, suppressInnocuousErrors} from './common.js';
 import {FakeReadingMode} from './fake_reading_mode.js';
-
+import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js';
 
 suite('HighlightMenu', () => {
-  let highlightMenu: HighlightMenu;
+  let app: AppElement;
+  let toolbar: ReadAnythingToolbarElement;
+  let testBrowserProxy: TestColorUpdaterBrowserProxy;
+  let highlightButton: CrIconButtonElement;
 
   setup(() => {
     suppressInnocuousErrors();
+    testBrowserProxy = new TestColorUpdaterBrowserProxy();
+    BrowserProxy.setInstance(testBrowserProxy);
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     const readingMode = new FakeReadingMode();
     chrome.readingMode = readingMode as unknown as typeof chrome.readingMode;
+    chrome.readingMode.isReadAloudEnabled = true;
     chrome.readingMode.isPhraseHighlightingEnabled = true;
+    chrome.readingMode.isAutomaticWordHighlightingEnabled = true;
 
-    highlightMenu = document.createElement('highlight-menu');
-    document.body.appendChild(highlightMenu);
+    app = document.createElement('read-anything-app');
+    document.body.appendChild(app);
     flush();
+
+    toolbar = app.$.toolbar;
+    highlightButton =
+        toolbar.$.toolbarContainer.querySelector<CrIconButtonElement>(
+            '#highlight')!;
   });
 
-  test('highlight granularity change', async () => {
-    const highlights = [
-      chrome.readingMode.autoHighlighting,
-      chrome.readingMode.wordHighlighting,
-      chrome.readingMode.phraseHighlighting,
-      chrome.readingMode.sentenceHighlighting,
-      chrome.readingMode.noHighlighting,
-    ];
+  test('highlighting is on by default', () => {
+    assertEquals('read-anything:highlight-on', highlightButton.ironIcon);
+    assertStringContains(highlightButton.title, 'highlight');
+    assertEquals(0, chrome.readingMode.highlightGranularity);
+    assertTrue(chrome.readingMode.isHighlightOn());
+  });
 
-    highlights.forEach(highlight => {
-      emitEventWithTarget(
-          highlightMenu.$.menu, ToolbarEvent.HIGHLIGHT_CHANGE,
-          {detail: {data: highlight}});
-      assertEquals(highlight, chrome.readingMode.highlightGranularity);
+  test('click opens menu', () => {
+    stubAnimationFrame();
+    highlightButton.click();
+    flush();
+
+    const menu = toolbar.$.highlightMenu.$.menu.$.lazyMenu.get();
+    assertTrue(menu.open);
+  });
+
+  suite('dropdown menu', () => {
+    let options: HTMLButtonElement[];
+
+    setup(() => {
+      stubAnimationFrame();
+      highlightButton.click();
+      flush();
+      const menu = toolbar.$.highlightMenu.$.menu.$.lazyMenu.get();
+      assertTrue(menu.open);
+      options = Array.from(
+          menu.querySelectorAll<HTMLButtonElement>('.dropdown-item'));
+    });
+
+    test('has 5 items', () => {
+      assertEquals(options.length, 5);
+    });
+
+    test('selects highlight granularity', () => {
+      let index = 0;
+      options.forEach(option => {
+        option.click();
+        flush();
+        assertEquals(chrome.readingMode.highlightGranularity, index);
+        index++;
+      });
+    });
+
+    test('highlight off changes icon', () => {
+      options[4]!.click();
+      flush();
+      assertEquals('read-anything:highlight-off', highlightButton.ironIcon);
     });
   });
 });
diff --git a/chrome/test/data/webui/side_panel/read_anything/highlight_toggle_test.ts b/chrome/test/data/webui/side_panel/read_anything/highlight_toggle_test.ts
index 7b5fe003..69c8582 100644
--- a/chrome/test/data/webui/side_panel/read_anything/highlight_toggle_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/highlight_toggle_test.ts
@@ -8,13 +8,15 @@
 import {flush} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import type {ReadAnythingToolbarElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
 import {ToolbarEvent} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import {assertEquals, assertFalse, assertStringContains, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
+import type {AppElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+import {assertEquals, assertFalse, assertNotEquals, assertStringContains, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
 
 import {suppressInnocuousErrors} from './common.js';
 import {FakeReadingMode} from './fake_reading_mode.js';
 import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js';
 
 suite('HighlightToggle', () => {
+  let app: AppElement;
   let toolbar: ReadAnythingToolbarElement;
   let testBrowserProxy: TestColorUpdaterBrowserProxy;
   let highlightButton: CrIconButtonElement;
@@ -28,16 +30,21 @@
     const readingMode = new FakeReadingMode();
     chrome.readingMode = readingMode as unknown as typeof chrome.readingMode;
     chrome.readingMode.isReadAloudEnabled = true;
-
-    toolbar = document.createElement('read-anything-toolbar');
-    document.body.appendChild(toolbar);
+    app = document.createElement('read-anything-app');
+    document.body.appendChild(app);
     flush();
+
+    toolbar = app.$.toolbar;
     highlightButton =
-        toolbar.shadowRoot!.querySelector<CrIconButtonElement>('#highlight')!;
+        toolbar.$.toolbarContainer.querySelector<CrIconButtonElement>(
+            '#highlight')!;
+
+    assertNotEquals(toolbar, null, 'toolbar null');
+    assertNotEquals(highlightButton, null, 'highlight button null');
 
     highlightEmitted = false;
     document.addEventListener(
-        ToolbarEvent.HIGHLIGHT_TOGGLE, () => highlightEmitted = true);
+        ToolbarEvent.HIGHLIGHT_CHANGE, () => highlightEmitted = true);
   });
 
   suite('by default', () => {
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index a071f650..eedf87ce 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -815,6 +815,8 @@
       "//base",
       "//base/test:test_support",
       "//chrome/common:constants",
+      "//chrome/enterprise_companion:constants_test",
+      "//chrome/enterprise_companion:installer_paths",
       "//chrome/enterprise_companion/device_management_storage",
       "//chrome/updater/protos:omaha_proto",
       "//components/crx_file",
@@ -854,6 +856,7 @@
 
     data_deps = [
       ":updater_selfupdate_test_crx",
+      "//chrome/enterprise_companion:enterprise_companion_test",
       "//chrome/updater/test/test_installer:app_installers",
     ]
 
diff --git a/chrome/updater/DEPS b/chrome/updater/DEPS
index 7581c97a..a5e280d 100644
--- a/chrome/updater/DEPS
+++ b/chrome/updater/DEPS
@@ -3,6 +3,8 @@
   "+chrome/enterprise_companion:client",
   "+chrome/enterprise_companion/enterprise_companion_client.h",
   "+chrome/enterprise_companion/device_management_storage",
+  "+chrome/enterprise_companion/global_constants.h",
+  "+chrome/enterprise_companion/installer_paths.h",
   "+chrome/enterprise_companion/mojom",
   "+chrome/installer/util",
   "+components/crash/core/common",
diff --git a/chrome/updater/test/integration_test_commands.h b/chrome/updater/test/integration_test_commands.h
index de6c0ca..1462b9d6 100644
--- a/chrome/updater/test/integration_test_commands.h
+++ b/chrome/updater/test/integration_test_commands.h
@@ -197,6 +197,9 @@
   virtual void DMPushEnrollmentToken(const std::string& enrollment_token) = 0;
   virtual void DMDeregisterDevice() = 0;
   virtual void DMCleanup() = 0;
+  virtual void InstallEnterpriseCompanionApp(
+      const base::Value::Dict& external_overrides) = 0;
+  virtual void UninstallEnterpriseCompanionApp() = 0;
 
  protected:
   friend class base::RefCountedThreadSafe<IntegrationTestCommands>;
diff --git a/chrome/updater/test/integration_test_commands_system.cc b/chrome/updater/test/integration_test_commands_system.cc
index 9c5013e2..4f1617a 100644
--- a/chrome/updater/test/integration_test_commands_system.cc
+++ b/chrome/updater/test/integration_test_commands_system.cc
@@ -557,6 +557,16 @@
   }
   void DMDeregisterDevice() override { RunCommand("dm_deregister_device"); }
   void DMCleanup() override { RunCommand("dm_cleanup"); }
+  void InstallEnterpriseCompanionApp(
+      const base::Value::Dict& external_overrides) override {
+    RunCommand(
+        "install_enterprise_companion_app",
+        {Param("external_overrides",
+               StringFromValue(base::Value(external_overrides.Clone())))});
+  }
+  void UninstallEnterpriseCompanionApp() override {
+    RunCommand("uninstall_enterprise_companion_app");
+  }
 
  private:
   ~IntegrationTestCommandsSystem() override = default;
diff --git a/chrome/updater/test/integration_test_commands_user.cc b/chrome/updater/test/integration_test_commands_user.cc
index df8fc1b..0af2a914 100644
--- a/chrome/updater/test/integration_test_commands_user.cc
+++ b/chrome/updater/test/integration_test_commands_user.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/notreached.h"
+#include "base/values.h"
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/updater/test/integration_test_commands.h"
@@ -463,6 +464,15 @@
 
   void DMCleanup() override { updater::test::DMCleanup(updater_scope_); }
 
+  void InstallEnterpriseCompanionApp(
+      const base::Value::Dict& external_overrides) override {
+    updater::test::InstallEnterpriseCompanionApp(external_overrides);
+  }
+
+  void UninstallEnterpriseCompanionApp() override {
+    updater::test::UninstallEnterpriseCompanionApp();
+  }
+
  private:
   ~IntegrationTestCommandsUser() override = default;
 
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 22f85a82..1eef2b3e3 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -56,6 +56,7 @@
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/update_client/protocol_definition.h"
 #include "components/update_client/update_client.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
 #include "url/gurl.h"
@@ -679,6 +680,15 @@
 
   void DMCleanup() { test_commands_->DMCleanup(); }
 
+  void InstallEnterpriseCompanionApp(
+      const base::Value::Dict& external_overrides) {
+    test_commands_->InstallEnterpriseCompanionApp(external_overrides);
+  }
+
+  void UninstallEnterpriseCompanionApp() {
+    test_commands_->UninstallEnterpriseCompanionApp();
+  }
+
   scoped_refptr<IntegrationTestCommands> test_commands_;
 
 #if BUILDFLAG(IS_WIN)
@@ -1826,10 +1836,14 @@
       GTEST_SKIP();
     }
     DMCleanup();
+    UninstallEnterpriseCompanionApp();
     ASSERT_NO_FATAL_FAILURE(SetMachineManaged(true));
   }
 
   void TearDown() override {
+    if (IsSystemInstall(GetUpdaterScopeForTesting())) {
+      UninstallEnterpriseCompanionApp();
+    }
     DMCleanup();
     IntegrationTest::TearDown();
   }
@@ -2067,6 +2081,60 @@
   ASSERT_NO_FATAL_FAILURE(Uninstall());
 }
 
+TEST_F(IntegrationTestDeviceManagement, FetchPolicyViaCompanionApp) {
+  net::test_server::EmbeddedTestServer null_server;
+  ASSERT_TRUE(null_server.Start());
+
+  ASSERT_NO_FATAL_FAILURE(Install());
+  ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
+  InstallEnterpriseCompanionApp(
+      base::Value::Dict()
+          .Set("crash_upload_url", test_server_->crash_upload_url().spec())
+          .Set("dm_encrypted_reporting_url", null_server.base_url().spec())
+          .Set("dm_realtime_reporting_url", null_server.base_url().spec())
+          .Set("dm_server_url", test_server_->device_management_url().spec())
+          .Set("event_logging_url", null_server.base_url().spec()));
+  ASSERT_TRUE(WaitForUpdaterExit());
+
+  OmahaSettingsClientProto omaha_settings;
+  omaha_settings.set_install_default(
+      enterprise_management::INSTALL_DEFAULT_DISABLED);
+  omaha_settings.set_download_preference("not-cacheable");
+  ApplicationSettings app;
+  app.set_app_guid(kApp1.appid);
+  app.set_update(enterprise_management::AUTOMATIC_UPDATES_ONLY);
+  omaha_settings.mutable_application_settings()->Add(std::move(app));
+
+  DMPushEnrollmentToken(kEnrollmentToken);
+  ExpectDeviceManagementRegistrationRequestViaCompanionApp(
+      test_server_.get(), kEnrollmentToken, kDMToken);
+  ExpectDeviceManagementPolicyFetchRequestViaCompanionApp(
+      test_server_.get(), kDMToken, omaha_settings);
+
+  ExpectUpdateCheckRequest(test_server_.get());
+  ASSERT_NO_FATAL_FAILURE(RunWake(0));
+  ASSERT_TRUE(WaitForUpdaterExit());
+
+  // Verify the policies downloaded by the companion app.
+  scoped_refptr<device_management_storage::DMStorage> dm_storage =
+      device_management_storage::GetDefaultDMStorage();
+  ASSERT_NE(dm_storage, nullptr);
+  std::optional<OmahaSettingsClientProto> omaha_policy =
+      GetOmahaPolicySettings(dm_storage);
+  ASSERT_TRUE(omaha_policy);
+  EXPECT_EQ(omaha_policy->install_default(),
+            enterprise_management::INSTALL_DEFAULT_DISABLED);
+  EXPECT_EQ(omaha_policy->download_preference(), "not-cacheable");
+  ASSERT_GT(omaha_policy->application_settings_size(), 0);
+  const ApplicationSettings& app_policy =
+      omaha_policy->application_settings()[0];
+  EXPECT_EQ(app_policy.app_guid(), kApp1.appid);
+  EXPECT_EQ(app_policy.update(), enterprise_management::AUTOMATIC_UPDATES_ONLY);
+
+  ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(test_server_.get()));
+  ASSERT_NO_FATAL_FAILURE(Uninstall());
+}
+
 #if BUILDFLAG(IS_WIN)
 // RuntimeEnrollmentToken is supported on Windows only.
 TEST_F(IntegrationTestDeviceManagement, RuntimeEnrollmentToken) {
diff --git a/chrome/updater/test/integration_tests_helper.cc b/chrome/updater/test/integration_tests_helper.cc
index 3bb8c74..ccf3859 100644
--- a/chrome/updater/test/integration_tests_helper.cc
+++ b/chrome/updater/test/integration_tests_helper.cc
@@ -477,6 +477,11 @@
            WithSwitch("enrollment_token", Wrap(DMPushEnrollmentToken))},
           {"dm_deregister_device", WithSystemScope(Wrap(&DMDeregisterDevice))},
           {"dm_cleanup", WithSystemScope(Wrap(&DMCleanup))},
+          {"install_enterprise_companion_app",
+           WithSwitch("external_overrides",
+                      Wrap(&InstallEnterpriseCompanionApp))},
+          {"uninstall_enterprise_companion_app",
+           Wrap(&UninstallEnterpriseCompanionApp)},
       };
 
   const base::CommandLine* command_line =
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc
index ee0c27a..768d43b1 100644
--- a/chrome/updater/test/integration_tests_impl.cc
+++ b/chrome/updater/test/integration_tests_impl.cc
@@ -25,6 +25,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
+#include "base/json/json_file_value_serializer.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
@@ -51,6 +52,8 @@
 #include "build/build_config.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/enterprise_companion/device_management_storage/dm_storage.h"
+#include "chrome/enterprise_companion/global_constants.h"
+#include "chrome/enterprise_companion/installer_paths.h"
 #include "chrome/updater/activity.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/device_management/dm_policy_builder_for_testing.h"
@@ -71,7 +74,6 @@
 #include "chrome/updater/updater_version.h"
 #include "chrome/updater/util/util.h"
 #include "components/policy/proto/device_management_backend.pb.h"
-#include "crypto/secure_hash.h"
 #include "crypto/sha2.h"
 #include "net/http/http_status_code.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -97,25 +99,32 @@
 constexpr char kSelfUpdateCRXRun[] = PRODUCT_FULLNAME_STRING "_test.app";
 constexpr char kDoNothingCRXName[] = "updater_qualification_app_dmg.crx";
 constexpr char kDoNothingCRXRun[] = "updater_qualification_app_dmg.dmg";
+constexpr base::FilePath::CharType kCompanionAppExecutableName[] =
+    FILE_PATH_LITERAL("enterprise_companion");
+constexpr base::FilePath::CharType kCompanionAppTestExecutableName[] =
+    FILE_PATH_LITERAL("enterprise_companion_test");
 #elif BUILDFLAG(IS_WIN)
 constexpr char kSelfUpdateCRXRun[] = "UpdaterSetup_test.exe";
 constexpr char kDoNothingCRXName[] = "updater_qualification_app_exe.crx";
 constexpr char kDoNothingCRXRun[] = "qualification_app.exe";
+constexpr base::FilePath::CharType kCompanionAppExecutableName[] =
+    FILE_PATH_LITERAL("enterprise_companion.exe");
+constexpr base::FilePath::CharType kCompanionAppTestExecutableName[] =
+    FILE_PATH_LITERAL("enterprise_companion_test.exe");
 #elif BUILDFLAG(IS_LINUX)
 constexpr char kSelfUpdateCRXRun[] = "updater_test";
 constexpr char kDoNothingCRXName[] = "updater_qualification_app.crx";
 constexpr char kDoNothingCRXRun[] = "qualification_app";
+constexpr base::FilePath::CharType kCompanionAppExecutableName[] =
+    FILE_PATH_LITERAL("enterprise_companion");
+constexpr base::FilePath::CharType kCompanionAppTestExecutableName[] =
+    FILE_PATH_LITERAL("enterprise_companion_test");
 #endif
 
 std::string GetHashHex(const base::FilePath& file) {
-  std::unique_ptr<crypto::SecureHash> hasher(
-      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
   base::MemoryMappedFile mmfile;
   EXPECT_TRUE(mmfile.Initialize(file));  // Note: This fails with an empty file.
-  hasher->Update(mmfile.data(), mmfile.length());
-  uint8_t actual_hash[crypto::kSHA256Length] = {0};
-  hasher->Finish(actual_hash, sizeof(actual_hash));
-  return base::HexEncode(actual_hash);
+  return base::HexEncode(crypto::SHA256Hash(mmfile.bytes()));
 }
 
 std::string GetUpdateResponseForApp(
@@ -351,6 +360,35 @@
   test_server->ExpectOnce(request_matchers, response, response_status);
 }
 
+void ExpectDeviceManagementRequestViaCompanionApp(
+    ScopedServer* test_server,
+    const std::string& request_type,
+    const std::string& authorization_type,
+    const std::string& authorization_token,
+    net::HttpStatusCode response_status,
+    const std::string& response,
+    std::optional<GURL> target_url = {}) {
+  request::MatcherGroup request_matchers = {
+      request::GetPathMatcher(base::StringPrintf(
+          R"(%s\?.*agent=%sEnterpriseCompanion%s&apptype=Chrome)"
+          R"(&deviceid=%s.*&platform=.*&request=%s)",
+          test_server->device_management_path().c_str(), BROWSER_NAME_STRING,
+          kUpdaterVersion,
+          device_management_storage::GetDefaultDMStorage()
+              ->GetDeviceID()
+              .c_str(),
+          request_type.c_str())),
+      request::GetHeaderMatcher(
+          {{"Authorization",
+            base::StringPrintf("%s token=%s", authorization_type.c_str(),
+                               authorization_token.c_str())},
+           {"Content-Type", "application/protobuf"}})};
+  if (target_url) {
+    request_matchers.push_back(request::GetTargetURLMatcher(*target_url));
+  }
+  test_server->ExpectOnce(request_matchers, response, response_status);
+}
+
 }  // namespace
 
 AppUpdateExpectation::AppUpdateExpectation(
@@ -1414,10 +1452,8 @@
 
 std::set<base::FilePath::StringType> GetTestProcessNames() {
 #if BUILDFLAG(IS_MAC)
-  return {
-      GetExecutableRelativePath().BaseName().value(),
-      GetSetupExecutablePath().BaseName().value(),
-  };
+  return {GetExecutableRelativePath().BaseName().value(),
+          GetSetupExecutablePath().BaseName().value()};
 #elif BUILDFLAG(IS_WIN)
   return {
       GetExecutableRelativePath().BaseName().value(),
@@ -1436,6 +1472,10 @@
 #endif
 }
 
+std::set<base::FilePath::StringType> GetCompanionAppProcessNames() {
+  return {kCompanionAppExecutableName, kCompanionAppTestExecutableName};
+}
+
 #if BUILDFLAG(IS_WIN)
 VersionProcessFilter::VersionProcessFilter()
     : this_version_(base::Version(kUpdaterVersion)), older_version_([] {
@@ -1552,6 +1592,60 @@
 #endif
 }
 
+void InstallEnterpriseCompanionApp(
+    const base::Value::Dict& external_overrides) {
+  base::FilePath exe_path;
+  EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &exe_path));
+
+  int exit_code = -1;
+  base::CommandLine command(exe_path.Append(kCompanionAppTestExecutableName));
+  command.AppendSwitch("install");
+  base::Process process = base::LaunchProcess(command, {});
+  EXPECT_TRUE(process.IsValid());
+  EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_timeout(),
+                                             &exit_code));
+  EXPECT_EQ(exit_code, 0);
+
+  std::optional<base::FilePath> json_path =
+      enterprise_companion::GetOverridesFilePath();
+  EXPECT_TRUE(json_path);
+  JSONFileValueSerializer json_serializer(*json_path);
+  EXPECT_TRUE(json_serializer.Serialize(external_overrides));
+  VLOG(1) << "Enterprise companion app installed.";
+}
+
+void UninstallEnterpriseCompanionApp() {
+  std::optional<base::FilePath> install_dir =
+      enterprise_companion::GetInstallDirectory();
+  if (!install_dir) {
+    VLOG(1) << "Cannot find enterprise companion app installation directory, "
+            << "assume it does not exist.";
+    return;
+  }
+
+  base::CommandLine command_line(
+      install_dir->Append(kCompanionAppExecutableName));
+  command_line.AppendSwitch("uninstall");
+  base::Process uninstall_process = base::LaunchProcess(command_line, {});
+  if (!uninstall_process.IsValid()) {
+    VLOG(1) << "Failed to launch enterprise companion app for uninstall, "
+            << "assume it does not exist.";
+    return;
+  }
+
+  if (WaitForProcess(uninstall_process) != 0) {
+    VLOG(1) << "Failed to uninstall companion app, nuke it.";
+    for (const base::FilePath::StringType& process_name :
+         GetCompanionAppProcessNames()) {
+      KillProcesses(process_name, -1);
+      WaitForProcessesToExit(process_name, TestTimeouts::action_timeout());
+      EXPECT_FALSE(IsProcessRunning(process_name)) << process_name;
+    }
+    base::DeletePathRecursively(*install_dir);
+  }
+  VLOG(1) << "Enterprise companion app is removed.";
+}
+
 void ExpectDeviceManagementRegistrationRequest(
     ScopedServer* test_server,
     const std::string& enrollment_token,
@@ -1647,6 +1741,43 @@
                                 "GoogleDMToken", dm_token, net::HTTP_OK, "");
 }
 
+void ExpectDeviceManagementRegistrationRequestViaCompanionApp(
+    ScopedServer* test_server,
+    const std::string& enrollment_token,
+    const std::string& dm_token) {
+  ExpectDeviceManagementRequestViaCompanionApp(
+      test_server, "register_policy_agent", "GoogleEnrollmentToken",
+      enrollment_token, net::HTTP_OK, [&dm_token] {
+        enterprise_management::DeviceManagementResponse dm_response;
+        dm_response.mutable_register_response()->set_device_management_token(
+            dm_token);
+        return dm_response.SerializeAsString();
+      }());
+}
+
+void ExpectDeviceManagementPolicyFetchRequestViaCompanionApp(
+    ScopedServer* test_server,
+    const std::string& dm_token,
+    const ::wireless_android_enterprise_devicemanagement::
+        OmahaSettingsClientProto& omaha_settings,
+    bool first_request,
+    bool rotate_public_key,
+    std::optional<GURL> target_url) {
+  ExpectDeviceManagementRequestViaCompanionApp(
+      test_server, "policy", "GoogleDMToken", dm_token, net::HTTP_OK,
+      [&dm_token, &omaha_settings, first_request, rotate_public_key] {
+        std::unique_ptr<::enterprise_management::DeviceManagementResponse>
+            dm_response = GetDMResponseForOmahaPolicy(
+                first_request, rotate_public_key,
+                DMPolicyBuilderForTesting::SigningOption::kSignNormally,
+                dm_token,
+                device_management_storage::GetDefaultDMStorage()->GetDeviceID(),
+                omaha_settings);
+        return dm_response->SerializeAsString();
+      }(),
+      target_url);
+}
+
 void ExpectProxyPacScriptRequest(ScopedServer* test_server) {
   test_server->ExpectOnce(
       {request::GetPathMatcher(test_server->proxy_pac_path()),
diff --git a/chrome/updater/test/integration_tests_impl.h b/chrome/updater/test/integration_tests_impl.h
index da386aa4..d317a38 100644
--- a/chrome/updater/test/integration_tests_impl.h
+++ b/chrome/updater/test/integration_tests_impl.h
@@ -481,6 +481,12 @@
 
 void DMCleanup(UpdaterScope scope);
 
+// Installs the enterprise companion app, always at the system scope.
+void InstallEnterpriseCompanionApp(const base::Value::Dict& external_overrides);
+
+// Uninstalls the enterprise companion app, always at the system scope.
+void UninstallEnterpriseCompanionApp();
+
 void ExpectDeviceManagementRegistrationRequest(
     ScopedServer* test_server,
     const std::string& enrollment_token,
@@ -503,6 +509,18 @@
                                                 bool invalidate_token);
 void ExpectDeviceManagementPolicyValidationRequest(ScopedServer* test_server,
                                                    const std::string& dm_token);
+void ExpectDeviceManagementRegistrationRequestViaCompanionApp(
+    ScopedServer* test_server,
+    const std::string& enrollment_token,
+    const std::string& dm_token);
+void ExpectDeviceManagementPolicyFetchRequestViaCompanionApp(
+    ScopedServer* test_server,
+    const std::string& dm_token,
+    const ::wireless_android_enterprise_devicemanagement::
+        OmahaSettingsClientProto& omaha_settings,
+    bool first_request = true,
+    bool rotate_public_key = false,
+    std::optional<GURL> target_url = std::nullopt);
 void ExpectProxyPacScriptRequest(ScopedServer* test_server);
 
 #if BUILDFLAG(IS_MAC)
diff --git a/chrome/updater/test/server.h b/chrome/updater/test/server.h
index 4e5061eb..c7faee14 100644
--- a/chrome/updater/test/server.h
+++ b/chrome/updater/test/server.h
@@ -77,6 +77,8 @@
                   const std::string& response_body,
                   net::HttpStatusCode response_status_code = net::HTTP_OK);
 
+  GURL base_url() const { return test_server_->base_url(); }
+
   std::string update_path() const { return "/update"; }
   GURL update_url() const { return test_server_->GetURL(update_path()); }
 
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc
index a4877ea5..fcebdcc 100644
--- a/chrome/updater/updater.cc
+++ b/chrome/updater/updater.cc
@@ -36,6 +36,7 @@
 #include "chrome/updater/constants.h"
 #include "chrome/updater/crash_client.h"
 #include "chrome/updater/crash_reporter.h"
+#include "chrome/updater/ipc/ipc_support.h"
 #include "chrome/updater/update_usage_stats_task.h"
 #include "chrome/updater/updater_scope.h"
 #include "chrome/updater/updater_version.h"
@@ -45,10 +46,6 @@
 #include "third_party/crashpad/crashpad/client/crash_report_database.h"
 #include "third_party/crashpad/crashpad/client/settings.h"
 
-#if BUILDFLAG(IS_POSIX)
-#include "chrome/updater/ipc/ipc_support.h"
-#endif
-
 #if BUILDFLAG(IS_WIN)
 #include "base/debug/alias.h"
 #include "base/win/process_startup_helper.h"
@@ -160,12 +157,10 @@
   // and reports the crash.
   CHECK(!command_line->HasSwitch(kCrashMeSwitch)) << "--crash-me was used.";
 
-#if BUILDFLAG(IS_POSIX)
   // As long as this object is alive, all Mojo API surface relevant to IPC
   // connections is usable, and message pipes which span a process boundary will
   // continue to function.
   ScopedIPCSupportWrapper ipc_support;
-#endif
 
   // Only tasks and timers are supported on the main sequence.
   base::SingleThreadTaskExecutor main_task_executor;
diff --git a/chromecast/browser/android/BUILD.gn b/chromecast/browser/android/BUILD.gn
index 44a1d97..1061009e 100644
--- a/chromecast/browser/android/BUILD.gn
+++ b/chromecast/browser/android/BUILD.gn
@@ -188,7 +188,6 @@
 
 generate_product_config_srcjar("product_config_for_browser") {
   java_package = "org.chromium.chromecast.shell"
-  is_bundle_module = false
 }
 
 generate_jni("jni_headers") {
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
index 24c1459..d67d788 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
@@ -8,15 +8,15 @@
 import android.content.Context;
 
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BundleUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.build.BuildConfig;
 import org.chromium.ui.base.ResourceBundle;
 
 /**
- * Entry point for the Android cast shell application.  Handles initialization of information that
+ * Entry point for the Android cast shell application. Handles initialization of information that
  * needs to be shared across the main activity and the child services created.
  */
 public class CastApplication extends Application {
@@ -26,7 +26,6 @@
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
         ContextUtils.initApplicationContext(this);
-        BundleUtils.setIsBundle(ProductConfig.IS_BUNDLE);
         ResourceBundle.setAvailablePakLocales(ProductConfig.LOCALES);
         LibraryLoader.getInstance().setLinkerImplementation(ProductConfig.USE_CHROMIUM_LINKER);
         LibraryLoader.getInstance().setLibraryProcessType(isBrowserProcess()
@@ -42,7 +41,7 @@
     }
 
     private static boolean isBrowserProcess() {
-        return BundleUtils.isBundle()
+        return BuildConfig.IS_BUNDLE
                 ? ContextUtils.getProcessName().contains("cast_browser_process")
                 : !ContextUtils.getProcessName().contains(":");
     }
diff --git a/chromeos/ash/components/boca/babelorca/BUILD.gn b/chromeos/ash/components/boca/babelorca/BUILD.gn
index 099d9148..67e203b 100644
--- a/chromeos/ash/components/boca/babelorca/BUILD.gn
+++ b/chromeos/ash/components/boca/babelorca/BUILD.gn
@@ -15,8 +15,6 @@
     "oauth_token_fetcher.h",
     "request_data_wrapper.cc",
     "request_data_wrapper.h",
-    "response_callback_wrapper.h",
-    "response_callback_wrapper_impl.h",
     "tachyon_authed_client.h",
     "tachyon_authed_client_impl.cc",
     "tachyon_authed_client_impl.h",
@@ -27,6 +25,7 @@
     "tachyon_registrar.cc",
     "tachyon_registrar.h",
     "tachyon_request_data_provider.h",
+    "tachyon_request_error.h",
     "tachyon_utils.cc",
     "tachyon_utils.h",
     "token_data_wrapper.h",
@@ -81,7 +80,6 @@
 
   sources = [
     "oauth_token_fetcher_unittest.cc",
-    "response_callback_wrapper_impl_unittest.cc",
     "tachyon_authed_client_impl_unittest.cc",
     "tachyon_client_impl_unittest.cc",
     "tachyon_registrar_unittest.cc",
diff --git a/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.cc b/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.cc
index 780da48..054d42f 100644
--- a/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.cc
+++ b/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.cc
@@ -5,14 +5,14 @@
 #include "chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.h"
 
 #include <memory>
-#include <string_view>
+#include <string>
 #include <utility>
 
 #include "base/check.h"
 #include "base/run_loop.h"
 #include "base/types/expected.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
 
 namespace ash::babelorca {
@@ -22,23 +22,17 @@
 FakeTachyonAuthedClient::~FakeTachyonAuthedClient() = default;
 
 void FakeTachyonAuthedClient::StartAuthedRequest(
-    const net::NetworkTrafficAnnotationTag& annotation_tag,
-    std::unique_ptr<google::protobuf::MessageLite> request_proto,
-    std::string_view url,
-    int max_retries,
-    std::unique_ptr<ResponseCallbackWrapper> response_cb) {
-  StartAuthedRequestString(annotation_tag, request_proto->SerializeAsString(),
-                           url, max_retries, std::move(response_cb));
+    std::unique_ptr<RequestDataWrapper> request_data,
+    std::unique_ptr<google::protobuf::MessageLite> request_proto) {
+  StartAuthedRequestString(std::move(request_data),
+                           request_proto->SerializeAsString());
 }
 
 void FakeTachyonAuthedClient::StartAuthedRequestString(
-    const net::NetworkTrafficAnnotationTag& annotation_tag,
-    std::string request_string,
-    std::string_view url,
-    int max_retries,
-    std::unique_ptr<ResponseCallbackWrapper> response_cb) {
+    std::unique_ptr<RequestDataWrapper> request_data,
+    std::string request_string) {
   has_new_request_ = true;
-  response_cb_ = std::move(response_cb);
+  response_cb_ = std::move(request_data->response_cb);
   request_string_ = std::move(request_string);
   if (run_loop_) {
     run_loop_->Quit();
@@ -46,14 +40,12 @@
 }
 
 void FakeTachyonAuthedClient::ExecuteResponseCallback(
-    base::expected<std::string, ResponseCallbackWrapper::TachyonRequestError>
-        response) {
+    base::expected<std::string, TachyonRequestError> response) {
   CHECK(response_cb_);
-  response_cb_->Run(std::move(response));
-  response_cb_.reset();
+  std::move(response_cb_).Run(std::move(response));
 }
 
-std::unique_ptr<ResponseCallbackWrapper>
+RequestDataWrapper::ResponseCallback
 FakeTachyonAuthedClient::TakeResponseCallback() {
   return std::move(response_cb_);
 }
diff --git a/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.h b/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.h
index ce775b3a..4ad3db5 100644
--- a/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.h
+++ b/chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.h
@@ -6,12 +6,13 @@
 #define CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_FAKES_FAKE_TACHYON_AUTHED_CLIENT_H_
 
 #include <memory>
-#include <string_view>
+#include <string>
 
 #include "base/run_loop.h"
 #include "base/types/expected.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
+#include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_authed_client.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 
 namespace ash::babelorca {
 
@@ -26,30 +27,23 @@
 
   // TachyonAuthedClient:
   void StartAuthedRequest(
-      const net::NetworkTrafficAnnotationTag& annotation_tag,
-      std::unique_ptr<google::protobuf::MessageLite> request_proto,
-      std::string_view url,
-      int max_retries,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb) override;
+      std::unique_ptr<RequestDataWrapper> request_data,
+      std::unique_ptr<google::protobuf::MessageLite> request_proto) override;
   void StartAuthedRequestString(
-      const net::NetworkTrafficAnnotationTag& annotation_tag,
-      std::string request_string,
-      std::string_view url,
-      int max_retries,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb) override;
+      std::unique_ptr<RequestDataWrapper> request_data,
+      std::string request_string) override;
 
   void ExecuteResponseCallback(
-      base::expected<std::string, ResponseCallbackWrapper::TachyonRequestError>
-          response);
+      base::expected<std::string, TachyonRequestError> response);
 
-  std::unique_ptr<ResponseCallbackWrapper> TakeResponseCallback();
+  RequestDataWrapper::ResponseCallback TakeResponseCallback();
 
   std::string GetRequestString();
 
   void WaitForRequest();
 
  private:
-  std::unique_ptr<ResponseCallbackWrapper> response_cb_;
+  RequestDataWrapper::ResponseCallback response_cb_;
   std::string request_string_;
   std::unique_ptr<base::RunLoop> run_loop_;
   bool has_new_request_ = false;
diff --git a/chromeos/ash/components/boca/babelorca/request_data_wrapper.cc b/chromeos/ash/components/boca/babelorca/request_data_wrapper.cc
index dd8f7b2..475c6e9 100644
--- a/chromeos/ash/components/boca/babelorca/request_data_wrapper.cc
+++ b/chromeos/ash/components/boca/babelorca/request_data_wrapper.cc
@@ -4,12 +4,10 @@
 
 #include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
 
-#include <memory>
 #include <string>
 #include <string_view>
 #include <utility>
 
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace ash::babelorca {
@@ -18,7 +16,7 @@
     const net::NetworkTrafficAnnotationTag& annotation_tag_param,
     std::string_view url_param,
     int max_retries_param,
-    std::unique_ptr<ResponseCallbackWrapper> response_cb_param)
+    ResponseCallback response_cb_param)
     : annotation_tag(annotation_tag_param),
       url(std::move(url_param)),
       max_retries(max_retries_param),
diff --git a/chromeos/ash/components/boca/babelorca/request_data_wrapper.h b/chromeos/ash/components/boca/babelorca/request_data_wrapper.h
index 7808a3f8..8285249 100644
--- a/chromeos/ash/components/boca/babelorca/request_data_wrapper.h
+++ b/chromeos/ash/components/boca/babelorca/request_data_wrapper.h
@@ -5,29 +5,32 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_REQUEST_DATA_WRAPPER_H_
 #define CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_REQUEST_DATA_WRAPPER_H_
 
-#include <memory>
 #include <string>
 #include <string_view>
 
+#include "base/functional/callback.h"
+#include "base/types/expected.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace ash::babelorca {
 
-class ResponseCallbackWrapper;
-
 struct RequestDataWrapper {
+  using ResponseCallback = base::OnceCallback<void(
+      base::expected<std::string, TachyonRequestError>)>;
+
   RequestDataWrapper(
       const net::NetworkTrafficAnnotationTag& annotation_tag_param,
       std::string_view url_param,
       int max_retries_param,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb_param);
+      ResponseCallback response_cb_param);
 
   ~RequestDataWrapper();
 
   const net::NetworkTrafficAnnotationTag annotation_tag;
   const std::string_view url;
   const int max_retries;
-  std::unique_ptr<ResponseCallbackWrapper> response_cb;
+  ResponseCallback response_cb;
   int oauth_version = 0;
   int oauth_retry_num = 0;
   std::string content_data;
diff --git a/chromeos/ash/components/boca/babelorca/response_callback_wrapper.h b/chromeos/ash/components/boca/babelorca/response_callback_wrapper.h
deleted file mode 100644
index 58361e2..0000000
--- a/chromeos/ash/components/boca/babelorca/response_callback_wrapper.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_RESPONSE_CALLBACK_WRAPPER_H_
-#define CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_RESPONSE_CALLBACK_WRAPPER_H_
-
-#include <string>
-
-#include "base/types/expected.h"
-
-namespace ash::babelorca {
-
-class ResponseCallbackWrapper {
- public:
-  enum class TachyonRequestError {
-    kHttpError,
-    kNetworkError,
-    kInternalError,
-    kAuthError
-  };
-
-  ResponseCallbackWrapper(const ResponseCallbackWrapper&) = delete;
-  ResponseCallbackWrapper& operator=(const ResponseCallbackWrapper&) = delete;
-
-  virtual ~ResponseCallbackWrapper() = default;
-
-  virtual void Run(
-      base::expected<std::string, TachyonRequestError> response) = 0;
-
- protected:
-  ResponseCallbackWrapper() = default;
-};
-
-}  // namespace ash::babelorca
-
-#endif  // CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_RESPONSE_CALLBACK_WRAPPER_H_
diff --git a/chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h b/chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h
deleted file mode 100644
index bd11d14..0000000
--- a/chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_RESPONSE_CALLBACK_WRAPPER_IMPL_H_
-#define CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_RESPONSE_CALLBACK_WRAPPER_IMPL_H_
-
-#include <string>
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/location.h"
-#include "base/task/bind_post_task.h"
-#include "base/task/thread_pool.h"
-#include "base/types/expected.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-
-namespace ash::babelorca {
-
-template <typename ResponseType>
-class ResponseCallbackWrapperImpl : public ResponseCallbackWrapper {
- public:
-  using ResponseExpectedCallback = base::OnceCallback<void(
-      base::expected<ResponseType, TachyonRequestError>)>;
-
-  explicit ResponseCallbackWrapperImpl(ResponseExpectedCallback callback)
-      : callback_(std::move(callback)) {}
-
-  ResponseCallbackWrapperImpl(const ResponseCallbackWrapperImpl&) = delete;
-  ResponseCallbackWrapperImpl& operator=(const ResponseCallbackWrapperImpl&) =
-      delete;
-
-  ~ResponseCallbackWrapperImpl() override = default;
-
-  void Run(base::expected<std::string, TachyonRequestError> response) override {
-    CHECK(callback_);
-    if (!response.has_value()) {
-      std::move(callback_).Run(base::unexpected(response.error()));
-      return;
-    }
-    auto posted_cb = base::BindPostTaskToCurrentDefault(std::move(callback_));
-    base::ThreadPool::PostTask(
-        FROM_HERE, base::BindOnce(ParseAndReply, std::move(response.value()),
-                                  std::move(posted_cb)));
-  }
-
- private:
-  static void ParseAndReply(std::string response_string,
-                            ResponseExpectedCallback callback) {
-    ResponseType response_proto;
-    if (!response_proto.ParseFromString(response_string)) {
-      std::move(callback).Run(
-          base::unexpected(TachyonRequestError::kInternalError));
-      return;
-    }
-    std::move(callback).Run(std::move(response_proto));
-  }
-
-  ResponseExpectedCallback callback_;
-};
-
-}  // namespace ash::babelorca
-
-#endif  // CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_RESPONSE_CALLBACK_WRAPPER_IMPL_H_
diff --git a/chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl_unittest.cc b/chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl_unittest.cc
deleted file mode 100644
index 9ffa2864..0000000
--- a/chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl_unittest.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h"
-
-#include <memory>
-
-#include "base/test/task_environment.h"
-#include "base/test/test_future.h"
-#include "base/types/expected.h"
-#include "chromeos/ash/components/boca/babelorca/proto/testing_message.pb.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::babelorca {
-namespace {
-
-using TestingExpectedResponse =
-    base::expected<TestingMessage,
-                   ResponseCallbackWrapper::TachyonRequestError>;
-
-TEST(ResponseCallbackWrapperImplTest, RespondWithProtoOnSuccess) {
-  base::test::TaskEnvironment task_env;
-  static constexpr int kProtoFieldValue = 12345;
-  base::test::TestFuture<TestingExpectedResponse> test_future;
-  ResponseCallbackWrapperImpl<TestingMessage> response_callback(
-      test_future.GetCallback<TestingExpectedResponse>());
-  TestingMessage message_input;
-  message_input.set_int_field(kProtoFieldValue);
-
-  response_callback.Run(message_input.SerializeAsString());
-  TestingExpectedResponse result = test_future.Get();
-
-  ASSERT_TRUE(result.has_value());
-  EXPECT_EQ(result->int_field(), kProtoFieldValue);
-}
-
-TEST(ResponseCallbackWrapperImplTest, RespondWithErrorOnFailure) {
-  base::test::TaskEnvironment task_env;
-  base::test::TestFuture<TestingExpectedResponse> test_future;
-  ResponseCallbackWrapperImpl<TestingMessage> response_callback(
-      test_future.GetCallback<TestingExpectedResponse>());
-
-  response_callback.Run(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
-  TestingExpectedResponse result = test_future.Get();
-
-  ASSERT_FALSE(result.has_value());
-  EXPECT_EQ(result.error(),
-            ResponseCallbackWrapper::TachyonRequestError::kHttpError);
-}
-
-TEST(ResponseCallbackWrapperImplTest, RespondWithErrorOnParseFailure) {
-  base::test::TaskEnvironment task_env;
-  base::test::TestFuture<TestingExpectedResponse> test_future;
-  ResponseCallbackWrapperImpl<TestingMessage> response_callback(
-      test_future.GetCallback<TestingExpectedResponse>());
-
-  response_callback.Run("invalid message");
-  TestingExpectedResponse result = test_future.Get();
-
-  ASSERT_FALSE(result.has_value());
-  EXPECT_EQ(result.error(),
-            ResponseCallbackWrapper::TachyonRequestError::kInternalError);
-}
-
-}  // namespace
-}  // namespace ash::babelorca
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_authed_client.h b/chromeos/ash/components/boca/babelorca/tachyon_authed_client.h
index dbdfea9..ce4182bf 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_authed_client.h
+++ b/chromeos/ash/components/boca/babelorca/tachyon_authed_client.h
@@ -7,19 +7,14 @@
 
 #include <memory>
 #include <string>
-#include <string_view>
 
 namespace google::protobuf {
 class MessageLite;
 }  // namespace google::protobuf
 
-namespace net {
-struct NetworkTrafficAnnotationTag;
-}  // namespace net
-
 namespace ash::babelorca {
 
-class ResponseCallbackWrapper;
+struct RequestDataWrapper;
 
 class TachyonAuthedClient {
  public:
@@ -29,18 +24,12 @@
   virtual ~TachyonAuthedClient() = default;
 
   virtual void StartAuthedRequest(
-      const net::NetworkTrafficAnnotationTag& annotation_tag,
-      std::unique_ptr<google::protobuf::MessageLite> request_proto,
-      std::string_view url,
-      int max_retries,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb) = 0;
+      std::unique_ptr<RequestDataWrapper> request_data,
+      std::unique_ptr<google::protobuf::MessageLite> request_proto) = 0;
 
   virtual void StartAuthedRequestString(
-      const net::NetworkTrafficAnnotationTag& annotation_tag,
-      std::string request_string,
-      std::string_view url,
-      int max_retries,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb) = 0;
+      std::unique_ptr<RequestDataWrapper> request_data,
+      std::string request_string) = 0;
 
  protected:
   TachyonAuthedClient() = default;
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.cc b/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.cc
index e3d9046..a900e4f 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.cc
@@ -18,8 +18,8 @@
 #include "base/task/thread_pool.h"
 #include "base/types/expected.h"
 #include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_client.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "chromeos/ash/components/boca/babelorca/token_manager.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
@@ -46,47 +46,33 @@
 TachyonAuthedClientImpl::~TachyonAuthedClientImpl() = default;
 
 void TachyonAuthedClientImpl::StartAuthedRequest(
-    const net::NetworkTrafficAnnotationTag& annotation_tag,
-    std::unique_ptr<google::protobuf::MessageLite> request_proto,
-    std::string_view url,
-    int max_retries,
-    std::unique_ptr<ResponseCallbackWrapper> response_cb) {
+    std::unique_ptr<RequestDataWrapper> request_data,
+    std::unique_ptr<google::protobuf::MessageLite> request_proto) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto serialize_cb =
       base::BindOnce(SerializeProtoToString, std::move(request_proto));
   auto reply_post_cb =
       base::BindOnce(&TachyonAuthedClientImpl::OnRequestProtoSerialized,
-                     weak_ptr_factory_.GetWeakPtr(), annotation_tag, url,
-                     max_retries, std::move(response_cb));
+                     weak_ptr_factory_.GetWeakPtr(), std::move(request_data));
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, std::move(serialize_cb), std::move(reply_post_cb));
 }
 
 void TachyonAuthedClientImpl::StartAuthedRequestString(
-    const net::NetworkTrafficAnnotationTag& annotation_tag,
-    std::string request_string,
-    std::string_view url,
-    int max_retries,
-    std::unique_ptr<ResponseCallbackWrapper> response_cb) {
-  OnRequestProtoSerialized(annotation_tag, url, max_retries,
-                           std::move(response_cb), request_string);
+    std::unique_ptr<RequestDataWrapper> request_data,
+    std::string request_string) {
+  OnRequestProtoSerialized(std::move(request_data), request_string);
 }
 
 void TachyonAuthedClientImpl::OnRequestProtoSerialized(
-    const net::NetworkTrafficAnnotationTag& annotation_tag,
-    std::string_view url,
-    int max_retries,
-    std::unique_ptr<ResponseCallbackWrapper> response_cb,
+    std::unique_ptr<RequestDataWrapper> request_data,
     std::optional<std::string> request_string) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!request_string) {
-    response_cb->Run(base::unexpected(
-        ResponseCallbackWrapper::TachyonRequestError::kInternalError));
+    std::move(request_data->response_cb)
+        .Run(base::unexpected(TachyonRequestError::kInternalError));
     return;
   }
-  std::unique_ptr<RequestDataWrapper> request_data =
-      std::make_unique<RequestDataWrapper>(annotation_tag, url, max_retries,
-                                           std::move(response_cb));
   request_data->content_data = std::move(*request_string);
   const std::string* oauth_token = oauth_token_manager_->GetTokenString();
   if (oauth_token) {
@@ -104,8 +90,8 @@
     bool has_oauth_token) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!has_oauth_token) {
-    request_data->response_cb->Run(base::unexpected(
-        ResponseCallbackWrapper::TachyonRequestError::kAuthError));
+    std::move(request_data->response_cb)
+        .Run(base::unexpected(TachyonRequestError::kAuthError));
     return;
   }
   std::string oauth_token = *(oauth_token_manager_->GetTokenString());
@@ -121,8 +107,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   static int constexpr kMaxAuthRetries = 1;
   if (request_data->oauth_retry_num >= kMaxAuthRetries) {
-    request_data->response_cb->Run(base::unexpected(
-        ResponseCallbackWrapper::TachyonRequestError::kAuthError));
+    std::move(request_data->response_cb)
+        .Run(base::unexpected(TachyonRequestError::kAuthError));
     return;
   }
   ++(request_data->oauth_retry_num);
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.h b/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.h
index 6847ee2..b61ea48 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.h
+++ b/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl.h
@@ -7,18 +7,17 @@
 
 #include <memory>
 #include <optional>
-#include <string_view>
 
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
-#include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_authed_client.h"
 
 namespace ash::babelorca {
 
 class TachyonClient;
 class TokenManager;
+struct RequestDataWrapper;
 
 class TachyonAuthedClientImpl : public TachyonAuthedClient {
  public:
@@ -32,24 +31,15 @@
 
   // TachyonAuthedClient:
   void StartAuthedRequest(
-      const net::NetworkTrafficAnnotationTag& annotation_tag,
-      std::unique_ptr<google::protobuf::MessageLite> request_proto,
-      std::string_view url,
-      int max_retries,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb) override;
+      std::unique_ptr<RequestDataWrapper> request_data,
+      std::unique_ptr<google::protobuf::MessageLite> request_proto) override;
   void StartAuthedRequestString(
-      const net::NetworkTrafficAnnotationTag& annotation_tag,
-      std::string request_string,
-      std::string_view url,
-      int max_retries,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb) override;
+      std::unique_ptr<RequestDataWrapper> request_data,
+      std::string request_string) override;
 
  private:
   void OnRequestProtoSerialized(
-      const net::NetworkTrafficAnnotationTag& annotation_tag,
-      std::string_view url,
-      int max_retries,
-      std::unique_ptr<ResponseCallbackWrapper> response_cb,
+      std::unique_ptr<RequestDataWrapper> request_data,
       std::optional<std::string> request_string);
 
   void StartAuthedRequestInternal(
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl_unittest.cc b/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl_unittest.cc
index 88d37c8..3381d50 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl_unittest.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_authed_client_impl_unittest.cc
@@ -15,8 +15,8 @@
 #include "chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_client.h"
 #include "chromeos/ash/components/boca/babelorca/fakes/fake_token_manager.h"
 #include "chromeos/ash/components/boca/babelorca/proto/testing_message.pb.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h"
+#include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -24,9 +24,7 @@
 namespace ash::babelorca {
 namespace {
 
-using ExpectedTestingMessage =
-    base::expected<TestingMessage,
-                   ResponseCallbackWrapper::TachyonRequestError>;
+using ExpectedTestingMessage = base::expected<std::string, TachyonRequestError>;
 
 constexpr char kOAuthToken1[] = "oauth-token1";
 constexpr char kOAuthToken2[] = "oauth-token2";
@@ -60,9 +58,10 @@
 
   const std::string& request_string() { return request_string_; }
 
-  std::unique_ptr<ResponseCallbackWrapperImpl<TestingMessage>> response_cb() {
-    return std::make_unique<ResponseCallbackWrapperImpl<TestingMessage>>(
-        test_future_.GetCallback());
+  std::unique_ptr<RequestDataWrapper> request_data_wrapper() {
+    return std::make_unique<RequestDataWrapper>(TRAFFIC_ANNOTATION_FOR_TESTS,
+                                                kUrl, kMaxRetries,
+                                                test_future_.GetCallback());
   }
 
   base::test::TestFuture<ExpectedTestingMessage>* test_future() {
@@ -86,9 +85,8 @@
   fake_token_manager()->SetFetchedVersion(1);
 
   CreateAuthedClient();
-  authed_client()->StartAuthedRequest(TRAFFIC_ANNOTATION_FOR_TESTS,
-                                      request_message(), kUrl, kMaxRetries,
-                                      response_cb());
+  authed_client()->StartAuthedRequest(request_data_wrapper(),
+                                      request_message());
   fake_client_ptr()->WaitForRequest();
 
   EXPECT_THAT(fake_client_ptr()->GetOAuthToken(), testing::StrEq(kOAuthToken1));
@@ -109,8 +107,7 @@
 
   CreateAuthedClient();
   authed_client()->StartAuthedRequestString(
-      TRAFFIC_ANNOTATION_FOR_TESTS, request_message()->SerializeAsString(),
-      kUrl, kMaxRetries, response_cb());
+      request_data_wrapper(), request_message()->SerializeAsString());
   fake_client_ptr()->WaitForRequest();
 
   EXPECT_THAT(fake_client_ptr()->GetOAuthToken(), testing::StrEq(kOAuthToken1));
@@ -126,9 +123,8 @@
 
 TEST_F(TachyonAuthedClientImplTest, NotInitiallyAuthed) {
   CreateAuthedClient();
-  authed_client()->StartAuthedRequest(TRAFFIC_ANNOTATION_FOR_TESTS,
-                                      request_message(), kUrl, kMaxRetries,
-                                      response_cb());
+  authed_client()->StartAuthedRequest(request_data_wrapper(),
+                                      request_message());
   fake_token_manager()->WaitForForceFetchRequest();
   fake_token_manager()->SetTokenString(
       std::make_unique<std::string>(kOAuthToken1));
@@ -153,9 +149,8 @@
   fake_token_manager()->SetFetchedVersion(1);
 
   CreateAuthedClient();
-  authed_client()->StartAuthedRequest(TRAFFIC_ANNOTATION_FOR_TESTS,
-                                      request_message(), kUrl, kMaxRetries,
-                                      response_cb());
+  authed_client()->StartAuthedRequest(request_data_wrapper(),
+                                      request_message());
   fake_client_ptr()->WaitForRequest();
   fake_client_ptr()->ExecuteAuthFailCb();
   fake_token_manager()->WaitForForceFetchRequest();
@@ -182,9 +177,8 @@
   fake_token_manager()->SetFetchedVersion(1);
 
   CreateAuthedClient();
-  authed_client()->StartAuthedRequest(TRAFFIC_ANNOTATION_FOR_TESTS,
-                                      request_message(), kUrl, kMaxRetries,
-                                      response_cb());
+  authed_client()->StartAuthedRequest(request_data_wrapper(),
+                                      request_message());
   fake_client_ptr()->WaitForRequest();
   // Simulate new token fetched before auth failure callback.
   fake_token_manager()->SetTokenString(
@@ -210,9 +204,8 @@
   fake_token_manager()->SetFetchedVersion(1);
 
   CreateAuthedClient();
-  authed_client()->StartAuthedRequest(TRAFFIC_ANNOTATION_FOR_TESTS,
-                                      request_message(), kUrl, kMaxRetries,
-                                      response_cb());
+  authed_client()->StartAuthedRequest(request_data_wrapper(),
+                                      request_message());
   fake_client_ptr()->WaitForRequest();
   // Simulate new token fetched before auth failure callback.
   fake_token_manager()->SetTokenString(
@@ -223,21 +216,18 @@
   fake_client_ptr()->ExecuteAuthFailCb();
 
   EXPECT_EQ(test_future()->Get(),
-            base::unexpected(
-                ResponseCallbackWrapper::TachyonRequestError::kAuthError));
+            base::unexpected(TachyonRequestError::kAuthError));
 }
 
 TEST_F(TachyonAuthedClientImplTest, TokenFetchFailed) {
   CreateAuthedClient();
-  authed_client()->StartAuthedRequest(TRAFFIC_ANNOTATION_FOR_TESTS,
-                                      request_message(), kUrl, kMaxRetries,
-                                      response_cb());
+  authed_client()->StartAuthedRequest(request_data_wrapper(),
+                                      request_message());
   fake_token_manager()->WaitForForceFetchRequest();
   fake_token_manager()->ExecuteFetchCallback(/*success=*/false);
 
   EXPECT_EQ(test_future()->Get(),
-            base::unexpected(
-                ResponseCallbackWrapper::TachyonRequestError::kAuthError));
+            base::unexpected(TachyonRequestError::kAuthError));
 }
 
 }  // namespace
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_client_impl.cc b/chromeos/ash/components/boca/babelorca/tachyon_client_impl.cc
index 67d5bfd..003d4a0 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_client_impl.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_client_impl.cc
@@ -15,7 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/types/expected.h"
 #include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
@@ -82,13 +82,13 @@
     std::unique_ptr<std::string> response_body) {
   if (url_loader->NetError() != net::OK &&
       url_loader->NetError() != net::ERR_HTTP_RESPONSE_CODE_FAILURE) {
-    request_data->response_cb->Run(base::unexpected(
-        ResponseCallbackWrapper::TachyonRequestError::kNetworkError));
+    std::move(request_data->response_cb)
+        .Run(base::unexpected(TachyonRequestError::kNetworkError));
     return;
   }
   if (!url_loader->ResponseInfo() || !url_loader->ResponseInfo()->headers) {
-    request_data->response_cb->Run(base::unexpected(
-        ResponseCallbackWrapper::TachyonRequestError::kInternalError));
+    std::move(request_data->response_cb)
+        .Run(base::unexpected(TachyonRequestError::kInternalError));
     return;
   }
   const int response_code =
@@ -98,16 +98,16 @@
     return;
   }
   if (!network::IsSuccessfulStatus(response_code)) {
-    request_data->response_cb->Run(base::unexpected(
-        ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+    std::move(request_data->response_cb)
+        .Run(base::unexpected(TachyonRequestError::kHttpError));
     return;
   }
   if (!response_body) {
-    request_data->response_cb->Run(base::unexpected(
-        ResponseCallbackWrapper::TachyonRequestError::kInternalError));
+    std::move(request_data->response_cb)
+        .Run(base::unexpected(TachyonRequestError::kInternalError));
     return;
   }
-  request_data->response_cb->Run(std::move(*response_body));
+  std::move(request_data->response_cb).Run(std::move(*response_body));
 }
 
 }  // namespace ash::babelorca
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_client_impl_unittest.cc b/chromeos/ash/components/boca/babelorca/tachyon_client_impl_unittest.cc
index 7ed05c27..6d7b4ad2 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_client_impl_unittest.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_client_impl_unittest.cc
@@ -13,8 +13,7 @@
 #include "base/types/expected.h"
 #include "chromeos/ash/components/boca/babelorca/proto/testing_message.pb.h"
 #include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -28,9 +27,7 @@
 namespace ash::babelorca {
 namespace {
 
-using ExpectedTestingMessage =
-    base::expected<TestingMessage,
-                   ResponseCallbackWrapper::TachyonRequestError>;
+using ExpectedTestingMessage = base::expected<std::string, TachyonRequestError>;
 using RequestDataPtr = std::unique_ptr<RequestDataWrapper>;
 
 constexpr char kOAuthToken[] = "oauth-token";
@@ -42,12 +39,9 @@
 class TachyonClientImplTest : public testing::Test {
  protected:
   RequestDataPtr request_data() {
-    auto response_cb =
-        std::make_unique<ResponseCallbackWrapperImpl<TestingMessage>>(
-            result_future_.GetCallback());
     auto request_data = std::make_unique<RequestDataWrapper>(
         kTrafficAnnotationTag, kUrl, /*max_retries_param=*/1,
-        std::move(response_cb));
+        result_future_.GetCallback());
     request_data->content_data = "request-body";
     return request_data;
   }
@@ -78,7 +72,9 @@
 
   auto result = result_future()->Get();
   ASSERT_TRUE(result.has_value());
-  EXPECT_EQ(result.value().int_field(), 9999);
+  TestingMessage result_proto;
+  ASSERT_TRUE(result_proto.ParseFromString(result.value()));
+  EXPECT_EQ(result_proto.int_field(), 9999);
   EXPECT_FALSE(auth_failure_future()->IsReady());
 }
 
@@ -94,8 +90,7 @@
 
   auto result = result_future()->Get();
   ASSERT_FALSE(result.has_value());
-  EXPECT_EQ(result.error(),
-            ResponseCallbackWrapper::TachyonRequestError::kNetworkError);
+  EXPECT_EQ(result.error(), TachyonRequestError::kNetworkError);
   EXPECT_FALSE(auth_failure_future()->IsReady());
 }
 
@@ -110,8 +105,7 @@
 
   auto result = result_future()->Get();
   ASSERT_FALSE(result.has_value());
-  EXPECT_EQ(result.error(),
-            ResponseCallbackWrapper::TachyonRequestError::kHttpError);
+  EXPECT_EQ(result.error(), TachyonRequestError::kHttpError);
   EXPECT_FALSE(auth_failure_future()->IsReady());
 }
 
@@ -131,7 +125,6 @@
             request_data_ptr->annotation_tag);
   EXPECT_EQ(auth_request_data->url, request_data_ptr->url);
   EXPECT_EQ(auth_request_data->max_retries, request_data_ptr->max_retries);
-  EXPECT_EQ(auth_request_data->response_cb, request_data_ptr->response_cb);
   EXPECT_FALSE(result_future()->IsReady());
 }
 
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_registrar.cc b/chromeos/ash/components/boca/babelorca/tachyon_registrar.cc
index ad4565530d..3972e85 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_registrar.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_registrar.cc
@@ -17,8 +17,7 @@
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon.pb.h"
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon_common.pb.h"
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon_enums.pb.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h"
+#include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_authed_client.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_constants.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_utils.h"
@@ -54,13 +53,15 @@
   register_data->mutable_device_id()->set_id(client_uuid);
   register_data->mutable_device_id()->set_type(DeviceIdType::CLIENT_UUID);
 
-  auto response_callback_wrapper =
-      std::make_unique<ResponseCallbackWrapperImpl<SignInGaiaResponse>>(
-          base::BindOnce(&TachyonRegistrar::OnResponse,
-                         weak_ptr_factory.GetWeakPtr(), std::move(success_cb)));
+  auto response_callback =
+      base::BindOnce(&TachyonRegistrar::OnResponse,
+                     weak_ptr_factory.GetWeakPtr(), std::move(success_cb));
+
   authed_client_->StartAuthedRequest(
-      network_annotation_tag_.get(), std::move(signin_request), kSigninGaiaUrl,
-      kMaxRetries, std::move(response_callback_wrapper));
+      std::make_unique<RequestDataWrapper>(network_annotation_tag_.get(),
+                                           kSigninGaiaUrl, kMaxRetries,
+                                           std::move(response_callback)),
+      std::move(signin_request));
 }
 
 std::optional<std::string> TachyonRegistrar::GetTachyonToken() {
@@ -70,14 +71,18 @@
 
 void TachyonRegistrar::OnResponse(
     base::OnceCallback<void(bool)> success_cb,
-    base::expected<SignInGaiaResponse,
-                   ResponseCallbackWrapper::TachyonRequestError> response) {
+    base::expected<std::string, TachyonRequestError> response) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!response.has_value()) {
     std::move(success_cb).Run(false);
     return;
   }
-  tachyon_token_ = std::move(response->auth_token().payload());
+  SignInGaiaResponse signin_response;
+  if (!signin_response.ParseFromString(response.value())) {
+    std::move(success_cb).Run(false);
+    return;
+  }
+  tachyon_token_ = std::move(signin_response.auth_token().payload());
   std::move(success_cb).Run(true);
 }
 
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_registrar.h b/chromeos/ash/components/boca/babelorca/tachyon_registrar.h
index 4dd9551..b4916e5 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_registrar.h
+++ b/chromeos/ash/components/boca/babelorca/tachyon_registrar.h
@@ -16,7 +16,7 @@
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
 #include "base/types/expected.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 
 namespace net {
 struct NetworkTrafficAnnotationTag;
@@ -24,7 +24,6 @@
 
 namespace ash::babelorca {
 
-class SignInGaiaResponse;
 class TachyonAuthedClient;
 
 // Register user with Tachyon and store tachyon token to be used by other
@@ -48,10 +47,8 @@
   std::optional<std::string> GetTachyonToken();
 
  private:
-  void OnResponse(
-      base::OnceCallback<void(bool)> success_cb,
-      base::expected<SignInGaiaResponse,
-                     ResponseCallbackWrapper::TachyonRequestError> response);
+  void OnResponse(base::OnceCallback<void(bool)> success_cb,
+                  base::expected<std::string, TachyonRequestError> response);
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_registrar_unittest.cc b/chromeos/ash/components/boca/babelorca/tachyon_registrar_unittest.cc
index ca0479d..8b9a0a9 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_registrar_unittest.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_registrar_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/types/expected.h"
 #include "chromeos/ash/components/boca/babelorca/fakes/fake_tachyon_authed_client.h"
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon.pb.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -46,8 +46,8 @@
   TachyonRegistrar registrar(&authed_client, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   registrar.Register(kClientUuid, test_future.GetCallback());
-  authed_client.ExecuteResponseCallback(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+  authed_client.ExecuteResponseCallback(
+      base::unexpected(TachyonRequestError::kHttpError));
 
   EXPECT_FALSE(test_future.Get());
   std::optional<std::string> tachyon_token = registrar.GetTachyonToken();
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_request_error.h b/chromeos/ash/components/boca/babelorca/tachyon_request_error.h
new file mode 100644
index 0000000..41ae4f4
--- /dev/null
+++ b/chromeos/ash/components/boca/babelorca/tachyon_request_error.h
@@ -0,0 +1,19 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_TACHYON_REQUEST_ERROR_H_
+#define CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_TACHYON_REQUEST_ERROR_H_
+
+namespace ash::babelorca {
+
+enum class TachyonRequestError {
+  kHttpError,
+  kNetworkError,
+  kInternalError,
+  kAuthError
+};
+
+}
+
+#endif  // CHROMEOS_ASH_COMPONENTS_BOCA_BABELORCA_TACHYON_REQUEST_ERROR_H_
diff --git a/chromeos/ash/components/boca/babelorca/transcript_sender.cc b/chromeos/ash/components/boca/babelorca/transcript_sender.cc
index 0ea87a53..32e7c2b6 100644
--- a/chromeos/ash/components/boca/babelorca/transcript_sender.cc
+++ b/chromeos/ash/components/boca/babelorca/transcript_sender.cc
@@ -23,11 +23,11 @@
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon.pb.h"
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon_common.pb.h"
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon_enums.pb.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h"
+#include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_authed_client.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_constants.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_request_data_provider.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_utils.h"
 #include "media/mojo/mojom/speech_recognition_result.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -191,18 +191,17 @@
     return;
   }
 
-  auto response_callback_wrapper =
-      std::make_unique<ResponseCallbackWrapperImpl<InboxSendResponse>>(
-          base::BindOnce(&TranscriptSender::OnSendResponse,
-                         weak_ptr_factory.GetWeakPtr()));
+  auto response_callback_wrapper = base::BindOnce(
+      &TranscriptSender::OnSendResponse, weak_ptr_factory.GetWeakPtr());
   authed_client_->StartAuthedRequestString(
-      network_traffic_annotation_, std::move(request_string), kSendMessageUrl,
-      max_retries, std::move(response_callback_wrapper));
+      std::make_unique<RequestDataWrapper>(
+          network_traffic_annotation_, kSendMessageUrl, max_retries,
+          std::move(response_callback_wrapper)),
+      std::move(request_string));
 }
 
 void TranscriptSender::OnSendResponse(
-    base::expected<InboxSendResponse,
-                   ResponseCallbackWrapper::TachyonRequestError> response) {
+    base::expected<std::string, TachyonRequestError> response) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (response.has_value()) {
     errors_num_ = 0;
diff --git a/chromeos/ash/components/boca/babelorca/transcript_sender.h b/chromeos/ash/components/boca/babelorca/transcript_sender.h
index 7701a49..8d1f15e 100644
--- a/chromeos/ash/components/boca/babelorca/transcript_sender.h
+++ b/chromeos/ash/components/boca/babelorca/transcript_sender.h
@@ -18,7 +18,7 @@
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
 #include "base/types/expected.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace media {
@@ -32,7 +32,6 @@
 namespace ash::babelorca {
 
 class BabelOrcaMessage;
-class InboxSendResponse;
 class TachyonAuthedClient;
 class TachyonRequestDataProvider;
 
@@ -74,8 +73,7 @@
   void Send(int max_retries, std::string message);
 
   void OnSendResponse(
-      base::expected<InboxSendResponse,
-                     ResponseCallbackWrapper::TachyonRequestError> response);
+      base::expected<std::string, TachyonRequestError> response);
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/chromeos/ash/components/boca/babelorca/transcript_sender_unittest.cc b/chromeos/ash/components/boca/babelorca/transcript_sender_unittest.cc
index a4cfb779..ddf25e2 100644
--- a/chromeos/ash/components/boca/babelorca/transcript_sender_unittest.cc
+++ b/chromeos/ash/components/boca/babelorca/transcript_sender_unittest.cc
@@ -15,9 +15,9 @@
 #include "chromeos/ash/components/boca/babelorca/proto/babel_orca_message.pb.h"
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon.pb.h"
 #include "chromeos/ash/components/boca/babelorca/proto/tachyon_enums.pb.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper.h"
-#include "chromeos/ash/components/boca/babelorca/response_callback_wrapper_impl.h"
+#include "chromeos/ash/components/boca/babelorca/request_data_wrapper.h"
 #include "chromeos/ash/components/boca/babelorca/tachyon_constants.h"
+#include "chromeos/ash/components/boca/babelorca/tachyon_request_error.h"
 #include "media/mojo/mojom/speech_recognition_result.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -186,15 +186,15 @@
                                              /*is_final=*/true);
   EXPECT_TRUE(sender.SendTranscriptionUpdate(transcript1, kLanguage));
   authed_client.WaitForRequest();
-  authed_client.ExecuteResponseCallback(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+  authed_client.ExecuteResponseCallback(
+      base::unexpected(TachyonRequestError::kHttpError));
 
   media::SpeechRecognitionResult transcript2(kTranscriptText,
                                              /*is_final=*/false);
   EXPECT_TRUE(sender.SendTranscriptionUpdate(transcript2, kLanguage));
   authed_client.WaitForRequest();
-  authed_client.ExecuteResponseCallback(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+  authed_client.ExecuteResponseCallback(
+      base::unexpected(TachyonRequestError::kHttpError));
 
   media::SpeechRecognitionResult transcript3(kTranscriptText,
                                              /*is_final=*/false);
@@ -221,8 +221,8 @@
                                              /*is_final=*/true);
   EXPECT_TRUE(sender.SendTranscriptionUpdate(transcript1, kLanguage));
   authed_client.WaitForRequest();
-  authed_client.ExecuteResponseCallback(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+  authed_client.ExecuteResponseCallback(
+      base::unexpected(TachyonRequestError::kHttpError));
 
   // Successful request, should reset error count.
   media::SpeechRecognitionResult transcript2(kTranscriptText,
@@ -238,8 +238,8 @@
                                              /*is_final=*/false);
   EXPECT_TRUE(sender.SendTranscriptionUpdate(transcript3, kLanguage));
   authed_client.WaitForRequest();
-  authed_client.ExecuteResponseCallback(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+  authed_client.ExecuteResponseCallback(
+      base::unexpected(TachyonRequestError::kHttpError));
 
   EXPECT_FALSE(failure_future.IsReady());
 }
@@ -261,32 +261,32 @@
                                              /*is_final=*/true);
   EXPECT_TRUE(sender.SendTranscriptionUpdate(transcript1, kLanguage));
   authed_client.WaitForRequest();
-  std::unique_ptr<ResponseCallbackWrapper> response_cb1 =
+  RequestDataWrapper::ResponseCallback response_cb1 =
       authed_client.TakeResponseCallback();
 
   media::SpeechRecognitionResult transcript2(kTranscriptText,
                                              /*is_final=*/false);
   EXPECT_TRUE(sender.SendTranscriptionUpdate(transcript2, kLanguage));
   authed_client.WaitForRequest();
-  std::unique_ptr<ResponseCallbackWrapper> response_cb2 =
+  RequestDataWrapper::ResponseCallback response_cb2 =
       authed_client.TakeResponseCallback();
 
   media::SpeechRecognitionResult transcript3(kTranscriptText,
                                              /*is_final=*/false);
   EXPECT_TRUE(sender.SendTranscriptionUpdate(transcript3, kLanguage));
   authed_client.WaitForRequest();
-  std::unique_ptr<ResponseCallbackWrapper> response_cb3 =
+  RequestDataWrapper::ResponseCallback response_cb3 =
       authed_client.TakeResponseCallback();
 
-  response_cb1->Run(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
-  response_cb2->Run(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+  std::move(response_cb1)
+      .Run(base::unexpected(TachyonRequestError::kHttpError));
+  std::move(response_cb2)
+      .Run(base::unexpected(TachyonRequestError::kHttpError));
 
   EXPECT_TRUE(failure_future.IsReady());
 
-  response_cb3->Run(base::unexpected(
-      ResponseCallbackWrapper::TachyonRequestError::kHttpError));
+  std::move(response_cb3)
+      .Run(base::unexpected(TachyonRequestError::kHttpError));
 
   media::SpeechRecognitionResult transcript4(kTranscriptText,
                                              /*is_final=*/false);
diff --git a/chromeos/ash/components/boca/on_task/on_task_session_manager.cc b/chromeos/ash/components/boca/on_task/on_task_session_manager.cc
index ead0a3f7..7c34949 100644
--- a/chromeos/ash/components/boca/on_task/on_task_session_manager.cc
+++ b/chromeos/ash/components/boca/on_task/on_task_session_manager.cc
@@ -14,6 +14,7 @@
 #include "base/sequence_checker.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
+#include "chromeos/ash/components/boca/on_task/on_task_blocklist.h"
 #include "chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h"
 #include "components/sessions/core/session_id.h"
 #include "url/gurl.h"
@@ -25,6 +26,22 @@
 // Delay in seconds before we attempt to add a tab.
 constexpr int kRetryAddTabTime = 3;
 
+OnTaskBlocklist::RestrictionLevel NavigationTypeToRestrictionLevel(
+    ::boca::LockedNavigationOptions::NavigationType navigation_type) {
+  switch (navigation_type) {
+    case ::boca::LockedNavigationOptions::OPEN_NAVIGATION:
+      return OnTaskBlocklist::RestrictionLevel::kNoRestrictions;
+    case ::boca::LockedNavigationOptions::BLOCK_NAVIGATION:
+      return OnTaskBlocklist::RestrictionLevel::kLimitedNavigation;
+    case ::boca::LockedNavigationOptions::DOMAIN_NAVIGATION:
+      return OnTaskBlocklist::RestrictionLevel::kSameDomainNavigation;
+    case ::boca::LockedNavigationOptions::LIMITED_NAVIGATION:
+      return OnTaskBlocklist::RestrictionLevel::kOneLevelDeepNavigation;
+    default:
+      return OnTaskBlocklist::RestrictionLevel::kNoRestrictions;
+  }
+}
+
 }  // namespace
 
 OnTaskSessionManager::OnTaskSessionManager(
@@ -67,7 +84,25 @@
   for (const ::boca::ContentConfig& content_config : bundle.content_configs()) {
     CHECK(content_config.has_url());
     const GURL url(content_config.url());
-    system_web_app_launch_helper_->AddTab(url);
+    OnTaskBlocklist::RestrictionLevel restriction_level;
+    if (content_config.has_locked_navigation_options()) {
+      ::boca::LockedNavigationOptions_NavigationType navigation_type =
+          content_config.locked_navigation_options().navigation_type();
+      restriction_level = NavigationTypeToRestrictionLevel(navigation_type);
+    } else {
+      restriction_level = OnTaskBlocklist::RestrictionLevel::kNoRestrictions;
+    }
+    // TODO (b/358197253): Stop the window tracker briefly while adding the new
+    // tabs before resuming it.
+    system_web_app_launch_helper_->AddTab(url, restriction_level);
+  }
+  if (const SessionID window_id =
+          system_web_app_manager_->GetActiveSystemWebAppWindowID();
+      window_id.is_valid()) {
+    system_web_app_manager_->SetWindowTrackerForSystemWebAppWindow(window_id);
+    bool is_lock_mode = bundle.locked();
+    system_web_app_manager_->SetPinStateForSystemWebAppWindow(
+        /*pinned=*/is_lock_mode, window_id);
   }
 }
 
@@ -86,20 +121,23 @@
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-void OnTaskSessionManager::SystemWebAppLaunchHelper::AddTab(GURL url) {
+void OnTaskSessionManager::SystemWebAppLaunchHelper::AddTab(
+    GURL url,
+    OnTaskBlocklist::RestrictionLevel restriction_level) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (launch_in_progress_) {
     base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&SystemWebAppLaunchHelper::AddTab,
-                       weak_ptr_factory_.GetWeakPtr(), url),
+                       weak_ptr_factory_.GetWeakPtr(), url, restriction_level),
         base::Seconds(kRetryAddTabTime));
     return;
   }
   if (const SessionID window_id =
           system_web_app_manager_->GetActiveSystemWebAppWindowID();
       window_id.is_valid()) {
-    system_web_app_manager_->CreateBackgroundTabWithUrl(window_id, url);
+    system_web_app_manager_->CreateBackgroundTabWithUrl(window_id, url,
+                                                        restriction_level);
   }
 }
 
diff --git a/chromeos/ash/components/boca/on_task/on_task_session_manager.h b/chromeos/ash/components/boca/on_task/on_task_session_manager.h
index ab9dda3..57a1fbf6 100644
--- a/chromeos/ash/components/boca/on_task/on_task_session_manager.h
+++ b/chromeos/ash/components/boca/on_task/on_task_session_manager.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "chromeos/ash/components/boca/boca_session_manager.h"
+#include "chromeos/ash/components/boca/on_task/on_task_blocklist.h"
 #include "chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h"
 #include "chromeos/ash/components/boca/proto/bundle.pb.h"
 #include "url/gurl.h"
@@ -47,7 +48,7 @@
     ~SystemWebAppLaunchHelper();
 
     void LaunchBocaSWA();
-    void AddTab(GURL url);
+    void AddTab(GURL url, OnTaskBlocklist::RestrictionLevel restriction_level);
 
    private:
     // Callback triggered when the Boca SWA is launched. Normally at the onset
diff --git a/chromeos/ash/components/boca/on_task/on_task_session_manager_unittest.cc b/chromeos/ash/components/boca/on_task/on_task_session_manager_unittest.cc
index ac4978f..0372657 100644
--- a/chromeos/ash/components/boca/on_task/on_task_session_manager_unittest.cc
+++ b/chromeos/ash/components/boca/on_task/on_task_session_manager_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/functional/callback.h"
+#include "chromeos/ash/components/boca/on_task/on_task_blocklist.h"
 #include "chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h"
 #include "chromeos/ash/components/boca/proto/roster.pb.h"
 #include "chromeos/ash/components/boca/proto/session.pb.h"
@@ -22,8 +23,11 @@
 namespace ash::boca {
 namespace {
 
-constexpr char kTestUrl1[] = "https://www.google.com";
-constexpr char kTestUrl2[] = "https://www.youtube.com";
+constexpr char kTestUrl1[] = "https://www.test1.com";
+constexpr char kTestUrl2[] = "https://www.test2.com";
+constexpr char kTestUrl3[] = "https://www.test3.com";
+constexpr char kTestUrl4[] = "https://www.test4.com";
+constexpr char kTestUrl5[] = "https://www.test5.com";
 
 // Mock implementation of the `OnTaskSystemWebAppManager`.
 class OnTaskSystemWebAppManagerMock : public OnTaskSystemWebAppManager {
@@ -47,7 +51,9 @@
               (override));
   MOCK_METHOD(void,
               CreateBackgroundTabWithUrl,
-              (SessionID window_id, GURL),
+              (SessionID window_id,
+               GURL url,
+               OnTaskBlocklist::RestrictionLevel restriction_level),
               (override));
 };
 
@@ -133,13 +139,13 @@
 TEST_F(OnTaskSessionManagerTest, ShouldOpenTabsOnBundleUpdated) {
   const SessionID kWindowId = SessionID::NewUnique();
   EXPECT_CALL(*system_web_app_manager_ptr_, GetActiveSystemWebAppWindowID())
-      .Times(2)
+      .Times(3)
       .WillRepeatedly(Return(kWindowId));
   EXPECT_CALL(*system_web_app_manager_ptr_,
-              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl1)))
+              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl1), _))
       .Times(1);
   EXPECT_CALL(*system_web_app_manager_ptr_,
-              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl2)))
+              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl2), _))
       .Times(1);
 
   ::boca::Bundle bundle;
@@ -150,9 +156,9 @@
 
 TEST_F(OnTaskSessionManagerTest, ShouldIgnoreWhenNoBocaSWAOpenOnBundleUpdated) {
   EXPECT_CALL(*system_web_app_manager_ptr_, GetActiveSystemWebAppWindowID())
-      .Times(2)
+      .Times(3)
       .WillRepeatedly(Return(SessionID::InvalidValue()));
-  EXPECT_CALL(*system_web_app_manager_ptr_, CreateBackgroundTabWithUrl(_, _))
+  EXPECT_CALL(*system_web_app_manager_ptr_, CreateBackgroundTabWithUrl(_, _, _))
       .Times(0);
 
   ::boca::Bundle bundle;
@@ -187,11 +193,19 @@
       .Times(1)
       .InSequence(s);
   EXPECT_CALL(*system_web_app_manager_ptr_,
-              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl1)))
+              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl1), _))
       .Times(1)
       .InSequence(s);
   EXPECT_CALL(*system_web_app_manager_ptr_,
-              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl2)))
+              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl2), _))
+      .Times(1)
+      .InSequence(s);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              SetWindowTrackerForSystemWebAppWindow(kWindowId))
+      .Times(1)
+      .InSequence(s);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              SetPinStateForSystemWebAppWindow(false, kWindowId))
       .Times(1)
       .InSequence(s);
 
@@ -202,5 +216,83 @@
   session_manager_->OnBundleUpdated(bundle);
 }
 
+TEST_F(OnTaskSessionManagerTest, ShouldApplyRestrictionsToTabsOnBundleUpdated) {
+  const SessionID kWindowId = SessionID::NewUnique();
+  EXPECT_CALL(*system_web_app_manager_ptr_, GetActiveSystemWebAppWindowID())
+      .WillRepeatedly(Return(kWindowId));
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              CreateBackgroundTabWithUrl(
+                  kWindowId, GURL(kTestUrl1),
+                  OnTaskBlocklist::RestrictionLevel::kNoRestrictions))
+      .Times(1);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              CreateBackgroundTabWithUrl(
+                  kWindowId, GURL(kTestUrl2),
+                  OnTaskBlocklist::RestrictionLevel::kLimitedNavigation))
+      .Times(1);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              CreateBackgroundTabWithUrl(
+                  kWindowId, GURL(kTestUrl3),
+                  OnTaskBlocklist::RestrictionLevel::kSameDomainNavigation))
+      .Times(1);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              CreateBackgroundTabWithUrl(
+                  kWindowId, GURL(kTestUrl4),
+                  OnTaskBlocklist::RestrictionLevel::kOneLevelDeepNavigation))
+      .Times(1);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              CreateBackgroundTabWithUrl(
+                  kWindowId, GURL(kTestUrl5),
+                  OnTaskBlocklist::RestrictionLevel::kNoRestrictions))
+      .Times(1);
+
+  ::boca::Bundle bundle;
+  ::boca::ContentConfig* const content_config_1 =
+      bundle.mutable_content_configs()->Add();
+  content_config_1->set_url(kTestUrl1);
+  content_config_1->mutable_locked_navigation_options()->set_navigation_type(
+      ::boca::LockedNavigationOptions::OPEN_NAVIGATION);
+  ::boca::ContentConfig* const content_config_2 =
+      bundle.mutable_content_configs()->Add();
+  content_config_2->set_url(kTestUrl2);
+  content_config_2->mutable_locked_navigation_options()->set_navigation_type(
+      ::boca::LockedNavigationOptions::BLOCK_NAVIGATION);
+  ::boca::ContentConfig* const content_config_3 =
+      bundle.mutable_content_configs()->Add();
+  content_config_3->set_url(kTestUrl3);
+  content_config_3->mutable_locked_navigation_options()->set_navigation_type(
+      ::boca::LockedNavigationOptions::DOMAIN_NAVIGATION);
+  ::boca::ContentConfig* const content_config_4 =
+      bundle.mutable_content_configs()->Add();
+  content_config_4->set_url(kTestUrl4);
+  content_config_4->mutable_locked_navigation_options()->set_navigation_type(
+      ::boca::LockedNavigationOptions::LIMITED_NAVIGATION);
+  ::boca::ContentConfig* const content_config_5 =
+      bundle.mutable_content_configs()->Add();
+  content_config_5->set_url(kTestUrl5);
+  session_manager_->OnBundleUpdated(bundle);
+}
+
+TEST_F(OnTaskSessionManagerTest, ShouldPinBocaSWAWhenLockedOnBundleUpdated) {
+  const SessionID kWindowId = SessionID::NewUnique();
+  EXPECT_CALL(*system_web_app_manager_ptr_, GetActiveSystemWebAppWindowID())
+      .Times(2)
+      .WillRepeatedly(Return(kWindowId));
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              CreateBackgroundTabWithUrl(kWindowId, GURL(kTestUrl1), _))
+      .Times(1);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              SetWindowTrackerForSystemWebAppWindow(kWindowId))
+      .Times(1);
+  EXPECT_CALL(*system_web_app_manager_ptr_,
+              SetPinStateForSystemWebAppWindow(true, kWindowId))
+      .Times(1);
+
+  ::boca::Bundle bundle;
+  bundle.add_content_configs()->set_url(kTestUrl1);
+  bundle.set_locked(true);
+  session_manager_->OnBundleUpdated(bundle);
+}
+
 }  // namespace
 }  // namespace ash::boca
diff --git a/chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h b/chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h
index 288cb6dd..9856936 100644
--- a/chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h
+++ b/chromeos/ash/components/boca/on_task/on_task_system_web_app_manager.h
@@ -6,6 +6,7 @@
 #define CHROMEOS_ASH_COMPONENTS_BOCA_ON_TASK_ON_TASK_SYSTEM_WEB_APP_MANAGER_H_
 
 #include "base/functional/callback_forward.h"
+#include "chromeos/ash/components/boca/on_task/on_task_blocklist.h"
 #include "components/sessions/core/session_id.h"
 #include "url/gurl.h"
 
@@ -41,9 +42,12 @@
   // id.
   virtual void SetWindowTrackerForSystemWebAppWindow(SessionID window_id) = 0;
 
-  // Creates a background tab with the given URL in the specified Boca SWA
-  // window.
-  virtual void CreateBackgroundTabWithUrl(SessionID window_id, GURL url) = 0;
+  // Creates a background tab with the given URL and restriction_level in the
+  // specified Boca SWA window.
+  virtual void CreateBackgroundTabWithUrl(
+      SessionID window_id,
+      GURL url,
+      OnTaskBlocklist::RestrictionLevel restriction_level) = 0;
 
  protected:
   OnTaskSystemWebAppManager() = default;
diff --git a/chromeos/ash/components/growth/campaigns_configuration_provider.cc b/chromeos/ash/components/growth/campaigns_configuration_provider.cc
index e83d5fbb7..8afca420 100644
--- a/chromeos/ash/components/growth/campaigns_configuration_provider.cc
+++ b/chromeos/ash/components/growth/campaigns_configuration_provider.cc
@@ -5,6 +5,7 @@
 #include "chromeos/ash/components/growth/campaigns_configuration_provider.h"
 
 #include <cstring>
+#include <string>
 
 #include "ash/constants/ash_switches.h"
 #include "base/command_line.h"
@@ -92,7 +93,7 @@
   if (HasDebugClearEventsSwitch()) {
     return {};
   } else {
-    return {growth::GetGrowthCampaignsEventNamePrefix()};
+    return {std::string(growth::GetGrowthCampaignsEventNamePrefix())};
   }
 }
 
diff --git a/chromeos/ash/components/growth/campaigns_manager.cc b/chromeos/ash/components/growth/campaigns_manager.cc
index f7d9bc8..0d388d9 100644
--- a/chromeos/ash/components/growth/campaigns_manager.cc
+++ b/chromeos/ash/components/growth/campaigns_manager.cc
@@ -5,6 +5,8 @@
 #include "chromeos/ash/components/growth/campaigns_manager.h"
 
 #include <optional>
+#include <string_view>
+#include <utility>
 
 #include "ash/constants/ash_pref_names.h"
 #include "ash/constants/ash_switches.h"
@@ -14,6 +16,7 @@
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/syslog_logging.h"
@@ -38,8 +41,6 @@
 inline constexpr char kCampaignFileName[] = "campaigns.json";
 
 inline constexpr char kEventKey[] = "event_to_be_cleared";
-inline constexpr char kEventTemplate[] =
-    "name:%s;comparator:any;window:3650;storage:3650";
 
 inline constexpr char kOobeCompleteFlagFilePath[] =
     "/home/chronos/.oobe_completed";
@@ -211,12 +212,11 @@
   return matcher_.opened_app_id();
 }
 
-void CampaignsManager::SetOpenedApp(const std::string& app_id) {
-  matcher_.SetOpenedApp(app_id);
-
+void CampaignsManager::SetOpenedApp(std::string app_id) {
   if (!app_id.empty()) {
     RecordEvent(GetEventName(CampaignEvent::kAppOpened, app_id));
   }
+  matcher_.SetOpenedApp(std::move(app_id));
 }
 
 const Trigger& CampaignsManager::GetTrigger() const {
@@ -284,16 +284,16 @@
           action_type));
 }
 
-void CampaignsManager::ClearEvent(CampaignEvent event, const std::string& id) {
+void CampaignsManager::ClearEvent(CampaignEvent event, std::string_view id) {
   ClearEvent(GetEventName(event, id));
 }
 
-void CampaignsManager::ClearEvent(const std::string& event) {
+void CampaignsManager::ClearEvent(std::string_view event) {
   std::map<std::string, std::string> conditions_params;
   // Event can be put in any key starting with `event_`.
   // Please see `components/feature_engagement/README.md#featureconfig`.
-  conditions_params[kEventKey] =
-      base::StringPrintf(kEventTemplate, event.c_str());
+  conditions_params[kEventKey] = base::StrCat(
+      {"name:", event, ";comparator:any;window:3650;storage:3650"});
   client_->ClearConfig(conditions_params);
 }
 
diff --git a/chromeos/ash/components/growth/campaigns_manager.h b/chromeos/ash/components/growth/campaigns_manager.h
index dc4fff1..d6c9bc59 100644
--- a/chromeos/ash/components/growth/campaigns_manager.h
+++ b/chromeos/ash/components/growth/campaigns_manager.h
@@ -5,6 +5,8 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_GROWTH_CAMPAIGNS_MANAGER_H_
 #define CHROMEOS_ASH_COMPONENTS_GROWTH_CAMPAIGNS_MANAGER_H_
 
+#include <string>
+
 #include "base/component_export.h"
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
@@ -74,7 +76,7 @@
 
   // Set the current opened app. Used in `CampaignsMatcher` for matching
   // opened app targeting.
-  void SetOpenedApp(const std::string& app_id);
+  void SetOpenedApp(std::string app_id);
 
   // Get latest trigger.
   const Trigger& GetTrigger() const;
@@ -101,8 +103,8 @@
                      const base::Value::Dict* params);
 
   // Clear event stored in the Feature Engagement framework.
-  void ClearEvent(CampaignEvent event, const std::string& id);
-  void ClearEvent(const std::string& event);
+  void ClearEvent(CampaignEvent event, std::string_view id);
+  void ClearEvent(std::string_view event);
 
   // Record event to the Feature Engagement framework. Event will be stored and
   // could be used for targeting.
diff --git a/chromeos/ash/components/growth/campaigns_matcher.cc b/chromeos/ash/components/growth/campaigns_matcher.cc
index b499c4d2..9aec5067 100644
--- a/chromeos/ash/components/growth/campaigns_matcher.cc
+++ b/chromeos/ash/components/growth/campaigns_matcher.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <optional>
 #include <string_view>
+#include <utility>
 
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
@@ -374,8 +375,8 @@
   campaigns_ = campaigns;
 }
 
-void CampaignsMatcher::SetOpenedApp(const std::string& app_id) {
-  opened_app_id_ = app_id;
+void CampaignsMatcher::SetOpenedApp(std::string app_id) {
+  opened_app_id_ = std::move(app_id);
 }
 
 void CampaignsMatcher::SetActiveUrl(const GURL& url) {
diff --git a/chromeos/ash/components/growth/campaigns_matcher.h b/chromeos/ash/components/growth/campaigns_matcher.h
index a9bf13c..b77b3bd 100644
--- a/chromeos/ash/components/growth/campaigns_matcher.h
+++ b/chromeos/ash/components/growth/campaigns_matcher.h
@@ -5,6 +5,8 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_GROWTH_CAMPAIGNS_MATCHER_H_
 #define CHROMEOS_ASH_COMPONENTS_GROWTH_CAMPAIGNS_MATCHER_H_
 
+#include <string>
+
 #include "base/time/time.h"
 #include "chromeos/ash/components/growth/campaigns_manager_client.h"
 #include "chromeos/ash/components/growth/campaigns_model.h"
@@ -30,7 +32,7 @@
   void FilterAndSetCampaigns(CampaignsPerSlot* campaigns);
 
   const std::string& opened_app_id() const { return opened_app_id_; }
-  void SetOpenedApp(const std::string& app_id);
+  void SetOpenedApp(std::string app_id);
   void SetOobeCompleteTime(base::Time time);
 
   const Trigger& trigger() const { return trigger_; }
diff --git a/chromeos/ash/components/growth/campaigns_utils.cc b/chromeos/ash/components/growth/campaigns_utils.cc
index 9890222..2dfceed 100644
--- a/chromeos/ash/components/growth/campaigns_utils.cc
+++ b/chromeos/ash/components/growth/campaigns_utils.cc
@@ -4,13 +4,13 @@
 
 #include "chromeos/ash/components/growth/campaigns_utils.h"
 
-#include <cstring>
-#include <optional>
+#include <algorithm>
 #include <string>
+#include <string_view>
 
-#include "base/containers/flat_map.h"
-#include "base/no_destructor.h"
-#include "base/strings/stringprintf.h"
+#include "base/containers/fixed_flat_map.h"
+#include "base/notreached.h"
+#include "base/strings/strcat.h"
 #include "chromeos/ash/components/growth/campaigns_constants.h"
 #include "url/gurl.h"
 
@@ -18,65 +18,42 @@
 
 namespace {
 
-// Only event name with this prefix can be processed by the Feature Engagement
-// framework.
-constexpr char kGrowthCampaignsEventNamePrefix[] =
-    "ChromeOSAshGrowthCampaigns_";
-
-// All event names will be prefixed by `kGrowthCampaignsEventNamePrefix`.
-// `CampaignEvent::kImpression` and `CampaaignEvent::kDismissed` event names
-// will be suffixed by campaign id.
-// E.g.
-// `ChromeOSAshGrowthCampaigns_CampaignId_Impression`
-// `ChromeOSAshGrowthCampaigns_CampaignId_Dismissed`
-constexpr char kCampaignEventNameImpressionTemplate[] = "Campaign%s_Impression";
-constexpr char kCampaignEventNameDismissedTemplate[] = "Campaign%s_Dismissed";
-constexpr char kCampaignEventNameGroupImpressionTemplate[] =
-    "Group%s_Impression";
-constexpr char kCampaignEventNameGroupDismissedTemplate[] = "Group%s_Dismissed";
-
-// `CampaignEvent::kAppOpened` event names will be suffixed by individual app id
-// (e.g. [hash]).
-// E.g. `ChromeOSAshGrowthCampaigns_AppOpened_AppId_[hash]`.
-// TODO: b/342282901 - Migrate `CampaignEvent::kAppOpened` to
-// `CampaignEvent::kEvent`, which can be used instead for similar case.
-constexpr char kCampaignEventNameAppOpenedTemplate[] = "AppOpened_AppId_%s";
-
-// `CampaignEvent::kEvent` event names, which is used for recording the Feature
-// Engagement events which then used for event targeting.
-// E.g. `ChromeOSAshGrowthCampaigns_Event_DocsOpened`.
-constexpr char kCampaignEventNameEventTemplate[] = "Event_%s";
-
-// TODO: b/341721256 - Get the app ids from their constants files.
-// PWA:
-constexpr char kGoogleDocsAppIdPwa[] = "mpnpojknpmmopombnjdcgaaiekajbnjb";
-constexpr char kGoogleDriveAppIdPwa[] = "aghbiahbpaijignceidepookljebhfak";
-constexpr char kGmailAppIdPwa[] = "fmgjjmmmlfnkbppncabfkddbjimcfncm";
-constexpr char kGooglePhotosAppIdPwa[] = "ncmjhecbjeaamljdfahankockkkdmedg";
-
-// ARC:
-constexpr char kGoogleDocsAppIdArc[] = "cgiadblnmjkjbhignimpegeiplgoidhe";
-constexpr char kGoogleDriveAppIdArc[] = "ljmhbofhbaapdhebeafbhlcapoiipfbi";
-constexpr char kGmailAppIdArc[] = "hhkfkjpmacfncmbapfohfocpjpdnobjg";
-constexpr char kGooglePhotosAppIdArc[] = "fdbkkojdbojonckghlanfaopfakedeca";
-
-// Domain name:
-constexpr char kGoogleDocsAppDomain[] = "docs.google.com";
-constexpr char kGoogleDriveAppDomain[] = "drive.google.com";
-constexpr char kGmailAppDomain[] = "mail.google.com";
-constexpr char kGooglePhotosAppDomain[] = "photos.google.com";
-
-// A list of supported apps group events.
-// NOTE: An app can be grouped in multiple groups.
-constexpr char kGoogleDocsOpenedEvent[] = "DocsOpened";
-constexpr char kGoogleDriveOpenedEvent[] = "DriveOpened";
-constexpr char kGmailOpenedEvent[] = "GmailOpened";
-constexpr char kGooglePhotosOpenedEvent[] = "PhotosOpened";
-
 // The mapping of `app_id` or URL `domain` to `app_group_id`.
-const base::flat_map<std::string, std::string>& GetAppGroupIdMap() {
-  static const base::NoDestructor<base::flat_map<std::string, std::string>>
-      app_group_id_map({
+const auto& GetAppGroupIdMap() {
+  // TODO: b/341721256 - Get the app ids from their constants files.
+  // PWA:
+  static constexpr char kGoogleDocsAppIdPwa[] =
+      "mpnpojknpmmopombnjdcgaaiekajbnjb";
+  static constexpr char kGoogleDriveAppIdPwa[] =
+      "aghbiahbpaijignceidepookljebhfak";
+  static constexpr char kGmailAppIdPwa[] = "fmgjjmmmlfnkbppncabfkddbjimcfncm";
+  static constexpr char kGooglePhotosAppIdPwa[] =
+      "ncmjhecbjeaamljdfahankockkkdmedg";
+
+  // ARC:
+  static constexpr char kGoogleDocsAppIdArc[] =
+      "cgiadblnmjkjbhignimpegeiplgoidhe";
+  static constexpr char kGoogleDriveAppIdArc[] =
+      "ljmhbofhbaapdhebeafbhlcapoiipfbi";
+  static constexpr char kGmailAppIdArc[] = "hhkfkjpmacfncmbapfohfocpjpdnobjg";
+  static constexpr char kGooglePhotosAppIdArc[] =
+      "fdbkkojdbojonckghlanfaopfakedeca";
+
+  // Domain name:
+  static constexpr char kGoogleDocsAppDomain[] = "docs.google.com";
+  static constexpr char kGoogleDriveAppDomain[] = "drive.google.com";
+  static constexpr char kGmailAppDomain[] = "mail.google.com";
+  static constexpr char kGooglePhotosAppDomain[] = "photos.google.com";
+
+  // A list of supported apps group events.
+  // NOTE: An app can be grouped in multiple groups.
+  static constexpr char kGoogleDocsOpenedEvent[] = "DocsOpened";
+  static constexpr char kGoogleDriveOpenedEvent[] = "DriveOpened";
+  static constexpr char kGmailOpenedEvent[] = "GmailOpened";
+  static constexpr char kGooglePhotosOpenedEvent[] = "PhotosOpened";
+
+  static constexpr auto kAppGroupIdMap =
+      base::MakeFixedFlatMap<std::string_view, std::string_view>({
           // Docs:
           {kGoogleDocsAppIdPwa, kGoogleDocsOpenedEvent},
           {kGoogleDocsAppIdArc, kGoogleDocsOpenedEvent},
@@ -94,59 +71,48 @@
           {kGooglePhotosAppIdArc, kGooglePhotosOpenedEvent},
           {kGooglePhotosAppDomain, kGooglePhotosOpenedEvent},
       });
-  return *app_group_id_map;
+  return kAppGroupIdMap;
 }
 
 }  // namespace
 
-std::string GetGrowthCampaignsEventNamePrefix() {
-  return kGrowthCampaignsEventNamePrefix;
+std::string_view GetGrowthCampaignsEventNamePrefix() {
+  // Only event name with this prefix can be processed by the Feature Engagement
+  // framework.
+  return "ChromeOSAshGrowthCampaigns_";
 }
 
-std::string GetEventName(CampaignEvent event, const std::string& id) {
-  const char* event_name = nullptr;
+std::string GetEventName(CampaignEvent event, std::string_view id) {
   switch (event) {
     case CampaignEvent::kImpression:
-      event_name = kCampaignEventNameImpressionTemplate;
-      break;
+      return base::StrCat({"Campaign", id, "_Impression"});
     case CampaignEvent::kDismissed:
-      event_name = kCampaignEventNameDismissedTemplate;
-      break;
+      return base::StrCat({"Campaign", id, "_Dismissed"});
     case CampaignEvent::kAppOpened:
-      event_name = kCampaignEventNameAppOpenedTemplate;
-      break;
+      // TODO: b/342282901 - Migrate `CampaignEvent::kAppOpened` to
+      // `CampaignEvent::kEvent`, which can be used instead for similar case.
+      return base::StrCat({"AppOpened_AppId_", id});
     case CampaignEvent::kEvent:
-      event_name = kCampaignEventNameEventTemplate;
-      break;
+      return base::StrCat({"Event_", id});
     case CampaignEvent::kGroupImpression:
-      event_name = kCampaignEventNameGroupImpressionTemplate;
-      break;
+      return base::StrCat({"Group", id, "_Impression"});
     case CampaignEvent::kGroupDismissed:
-      event_name = kCampaignEventNameGroupDismissedTemplate;
-      break;
+      return base::StrCat({"Group", id, "_Dismissed"});
   }
-
-  return base::StringPrintf(event_name, id.c_str());
+  NOTREACHED();
 }
 
-std::optional<std::string> GetAppGroupId(const std::string& app_id) {
-  auto it = GetAppGroupIdMap().find(app_id);
-  if (it == GetAppGroupIdMap().end()) {
-    return std::nullopt;
-  }
-
-  return it->second;
+std::string_view GetAppGroupId(std::string_view app_id) {
+  const auto& map = GetAppGroupIdMap();
+  const auto it = map.find(app_id);
+  return (it == map.end()) ? std::string_view() : it->second;
 }
 
-std::optional<std::string> GetAppGroupId(const GURL& url) {
-  auto it = GetAppGroupIdMap().cbegin();
-  for (; it != GetAppGroupIdMap().cend(); ++it) {
-    if (url.DomainIs(it->first)) {
-      return it->second;
-    }
-  }
-
-  return std::nullopt;
+std::string_view GetAppGroupId(const GURL& url) {
+  const auto& map = GetAppGroupIdMap();
+  const auto it = std::ranges::find_if(
+      map, [&](const auto& elem) { return url.DomainIs(elem.first); });
+  return (it == map.end()) ? std::string_view() : it->second;
 }
 
 }  // namespace growth
diff --git a/chromeos/ash/components/growth/campaigns_utils.h b/chromeos/ash/components/growth/campaigns_utils.h
index 000ef96..e8d0f1f1 100644
--- a/chromeos/ash/components/growth/campaigns_utils.h
+++ b/chromeos/ash/components/growth/campaigns_utils.h
@@ -5,8 +5,8 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_GROWTH_CAMPAIGNS_UTILS_H_
 #define CHROMEOS_ASH_COMPONENTS_GROWTH_CAMPAIGNS_UTILS_H_
 
-#include <optional>
 #include <string>
+#include <string_view>
 
 #include "base/component_export.h"
 #include "chromeos/ash/components/growth/campaigns_constants.h"
@@ -17,24 +17,24 @@
 
 // A util function to add the `kGrowthCampaignsEventNamePrefix`.
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_GROWTH_UTILS)
-std::string GetGrowthCampaignsEventNamePrefix();
+std::string_view GetGrowthCampaignsEventNamePrefix();
 
 // TODO: b/341955045 - Separate for UIEvent and AppOpenedEvent.
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_GROWTH_UTILS)
-std::string GetEventName(CampaignEvent event, const std::string& id);
+std::string GetEventName(CampaignEvent event, std::string_view id);
 
 // Returns the app group id by individual app id.
 // E.g. Gmail PWA and ARC apps could be grouped by `Gmail` group id.
 // Some campaigns may use the app group id to do configuration.
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_GROWTH_UTILS)
-std::optional<std::string> GetAppGroupId(const std::string& app_id);
+std::string_view GetAppGroupId(const std::string_view app_id);
 
 // Returns the app group id by URL.
 // E.g. Gmail website can be grouped with other Gmail PWA and ARC apps by
 // `Gmail` group id. Some campaigns may use the app group id to do
 // configuration.
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_GROWTH_UTILS)
-std::optional<std::string> GetAppGroupId(const GURL& url);
+std::string_view GetAppGroupId(const GURL& url);
 
 }  // namespace growth
 
diff --git a/chromeos/ash/components/policy/BUILD.gn b/chromeos/ash/components/policy/BUILD.gn
index e8e859e..5137f83 100644
--- a/chromeos/ash/components/policy/BUILD.gn
+++ b/chromeos/ash/components/policy/BUILD.gn
@@ -4,84 +4,30 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos_ash, "Non-Chrome-OS builds must not depend on //ash")
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos")
 
 component("policy") {
   output_name = "chromeos_ash_components_policy"
   defines = [ "IS_CHROMEOS_ASH_COMPONENTS_POLICY_IMPL" ]
 
-  public = [
-    "restriction_schedule/device_restriction_schedule_controller.h",
-    "weekly_time/checked_util.h",
-    "weekly_time/time_utils.h",
-    "weekly_time/weekly_time.h",
-    "weekly_time/weekly_time_checked.h",
-    "weekly_time/weekly_time_interval.h",
-    "weekly_time/weekly_time_interval_checked.h",
-  ]
+  public = []
 
-  sources = [
-    "restriction_schedule/device_restriction_schedule_controller.cc",
-    "weekly_time/checked_util.cc",
-    "weekly_time/time_utils.cc",
-    "weekly_time/weekly_time.cc",
-    "weekly_time/weekly_time_checked.cc",
-    "weekly_time/weekly_time_interval.cc",
-    "weekly_time/weekly_time_interval_checked.cc",
-  ]
+  sources = []
 
   public_deps = [
-    "//base",
-    "//components/policy/proto",
-    "//third_party/abseil-cpp:absl",
-    "//third_party/icu",
+    "restriction_schedule",
+    "weekly_time",
   ]
 
-  deps = [
-    "//base:i18n",
-    "//chromeos/constants",
-    "//components/prefs",
-  ]
-}
-
-source_set("test_support") {
-  testonly = true
-
-  public = [ "weekly_time/test_support.h" ]
-
-  sources = [ "weekly_time/test_support.cc" ]
-
-  public_deps = [ "//base" ]
-
-  deps = [
-    "//chromeos/ash/components/policy",
-    "//testing/gtest",
-  ]
+  deps = []
 }
 
 source_set("unit_tests") {
   testonly = true
 
-  sources = [
-    "restriction_schedule/device_restriction_schedule_controller_unittest.cc",
-    "weekly_time/checked_util_unittest.cc",
-    "weekly_time/time_utils_unittest.cc",
-    "weekly_time/weekly_time_checked_unittest.cc",
-    "weekly_time/weekly_time_interval_checked_unittest.cc",
-    "weekly_time/weekly_time_interval_unittest.cc",
-    "weekly_time/weekly_time_unittest.cc",
-  ]
-
   deps = [
-    ":policy",
-    ":test_support",
-    "//base",
-    "//base:i18n",
-    "//base/test:test_support",
-    "//chromeos/constants",
-    "//components/policy/proto",
-    "//components/prefs:test_support",
-    "//testing/gtest",
-    "//third_party/icu",
+    "restriction_schedule:unit_tests",
+    "weekly_time:unit_tests",
+    "weekly_time:unit_tests_checked",
   ]
 }
diff --git a/chromeos/ash/components/policy/restriction_schedule/BUILD.gn b/chromeos/ash/components/policy/restriction_schedule/BUILD.gn
new file mode 100644
index 0000000..266cf3b
--- /dev/null
+++ b/chromeos/ash/components/policy/restriction_schedule/BUILD.gn
@@ -0,0 +1,42 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos")
+
+source_set("restriction_schedule") {
+  defines = [ "IS_CHROMEOS_ASH_COMPONENTS_POLICY_IMPL" ]
+
+  public = [ "device_restriction_schedule_controller.h" ]
+
+  sources = [ "device_restriction_schedule_controller.cc" ]
+
+  public_deps = [
+    "//base",
+    "//components/prefs",
+  ]
+
+  deps = [
+    "//chromeos/ash/components/policy/weekly_time",
+    "//chromeos/constants",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [ "device_restriction_schedule_controller_unittest.cc" ]
+
+  deps = [
+    ":restriction_schedule",
+    "//base",
+    "//base/test:test_support",
+    "//chromeos/ash/components/policy/weekly_time",
+    "//chromeos/ash/components/policy/weekly_time:test_support",
+    "//chromeos/constants",
+    "//components/prefs:test_support",
+    "//testing/gmock",
+  ]
+}
diff --git a/chromeos/ash/components/policy/weekly_time/BUILD.gn b/chromeos/ash/components/policy/weekly_time/BUILD.gn
new file mode 100644
index 0000000..75eb64a2
--- /dev/null
+++ b/chromeos/ash/components/policy/weekly_time/BUILD.gn
@@ -0,0 +1,118 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos")
+
+component("weekly_time") {
+  output_name = "chromeos_ash_components_policy_weekly_time"
+  defines = [ "IS_CHROMEOS_ASH_COMPONENTS_POLICY_IMPL" ]
+
+  public_deps = [
+    ":weekly_time_checked",
+    ":weekly_time_internal",
+  ]
+}
+
+source_set("weekly_time_internal") {
+  visibility = [ ":weekly_time" ]
+  defines = [ "IS_CHROMEOS_ASH_COMPONENTS_POLICY_IMPL" ]
+
+  public = [
+    "time_utils.h",
+    "weekly_time.h",
+    "weekly_time_interval.h",
+  ]
+
+  sources = [
+    "time_utils.cc",
+    "weekly_time.cc",
+    "weekly_time_interval.cc",
+  ]
+
+  public_deps = [
+    "//base",
+    "//third_party/icu",
+  ]
+
+  deps = [
+    "//base:i18n",
+    "//components/policy/proto",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "time_utils_unittest.cc",
+    "weekly_time_interval_unittest.cc",
+    "weekly_time_unittest.cc",
+  ]
+
+  deps = [
+    ":weekly_time",
+    "//base",
+    "//base:i18n",
+    "//base/test:test_support",
+    "//components/policy/proto",
+    "//testing/gtest",
+    "//third_party/icu",
+  ]
+}
+
+source_set("weekly_time_checked") {
+  visibility = [ ":weekly_time" ]
+  defines = [ "IS_CHROMEOS_ASH_COMPONENTS_POLICY_IMPL" ]
+
+  public = [
+    "checked_util.h",
+    "weekly_time_checked.h",
+    "weekly_time_interval_checked.h",
+  ]
+
+  sources = [
+    "checked_util.cc",
+    "weekly_time_checked.cc",
+    "weekly_time_interval_checked.cc",
+  ]
+
+  public_deps = [ "//base" ]
+
+  deps = []
+}
+
+source_set("test_support") {
+  testonly = true
+
+  public = [ "test_support.h" ]
+
+  sources = [ "test_support.cc" ]
+
+  public_deps = [
+    ":weekly_time",
+    "//base",
+  ]
+
+  deps = [ "//testing/gtest" ]
+}
+
+source_set("unit_tests_checked") {
+  testonly = true
+
+  sources = [
+    "checked_util_unittest.cc",
+    "weekly_time_checked_unittest.cc",
+    "weekly_time_interval_checked_unittest.cc",
+  ]
+
+  deps = [
+    ":test_support",
+    ":weekly_time",
+    "//base",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 09cd974..1d32aec8 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -3178,85 +3178,86 @@
         </message>
 
         <!-- Sanitize UI -->
-        <message name="IDS_SANITIZE" desc="Name of the Sanitize web app" translateable="false">
-          Sanitize
+        <message name="IDS_SANITIZE" desc="Name of the Safety reset web app">
+          Safety reset
         </message>
-        <message name="IDS_SANITIZE_DONE_HEADING" desc="Name of the 'Safety reset done' window" translateable="false">
-          Your device is sanitized
+        <message name="IDS_SANITIZE_DONE_HEADING" desc="Name of the 'Safety reset done' window">
+          Safety reset has been completed
         </message>
-        <message name="IDS_SANITIZE_DONE_DESCRIPTION" desc="Description of the safety reset done dialog" translateable="false">
-          Your ChromeOS device was reset to safe defaults.
+        <message name="IDS_SANITIZE_DONE_DESCRIPTION" desc="Description of the safety reset done dialog">
+          Your Chromebook was reset to safe defaults. You can adjust these changes anytime in Settings.
         </message>
-        <message name="IDS_SANITIZE_DONE_ROLLBACK" desc="Description of how the user can roll back changes" translateable="false">
-          We made changes to make your device more secure, you can undo some of our changes below.
+        <message name="IDS_SANITIZE_DONE_ROLLBACK" desc="Summary title">
+          Summary
         </message>
-        <message name="IDS_SANITIZE_DONE" desc="Name of the button that will close the sanitize done dialog" translateable="false">
+        <message name="IDS_SANITIZE_DONE" desc="Name of the button that will close the safety reset done dialog">
           Done
         </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_TITLE" translateable="false">
-          Your Extensions
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_REENABLE" translateable="false">
-          Re-enable extensions you trust
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_TITLE" translateable="false">
-          Your ChromeOS Settings
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_INPUT" translateable="false">
-          Verify your input method
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_NETWORK" translateable="false">
-          Check your current network
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_TITLE" translateable="false">
-          Your Chrome Settings
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_SITE_CONTENT" translateable="false">
-          Verify your site content settings
-        </message>
-        <message name="IDS_SANITZIE_DONE_ACCORDION_CHROME_STARTUP" translateable="false">
-          Check your Chrome startup preferences
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_HOMEPAGE" translateable="false">
-          Verify the status of your homepage
-        </message>
-        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_LANGUAGES" translateable="false">
-          Verify your language settings
-        </message>
-        <message name="IDS_SANITIZE_DONE_BUTTON_EXTENSIONS" translateable="false">
+        <message name="IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_TITLE" desc="Accordion title for extension resets">
           Extensions
         </message>
-        <message name="IDS_SANITIZE_DONE_BUTTON_CHROMEOS_INPUT" translateable="false">
-          ChromeOS Input
+        <message name="IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_REENABLE" desc="Instructions to re-enable extensions">
+          Only turn on extensions you trust
         </message>
-        <message name="IDS_SANITIZE_DONE_BUTTON_CHROMEOS_NETWORK" translateable="false">
-          ChromeOS Network
+        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_TITLE" desc="Accordion title for ChromeOS resets">
+          ChromeOS Settings
         </message>
-        <message name="IDS_SANITIZE_DONE_BUTTON_CHROME_STARTUP" translateable="false">
-          Chrome Startup
+        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_INPUT" desc="Instructions to adjust ChromeOS Inputs">
+          Input method
         </message>
-        <message name="IDS_SANITIZE_DONE_BUTTON_CHROME_HOMEPAGE" translateable="false">
-          Chrome Homepage
+        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_NETWORK" desc="Instructions to adjust ChromeOS Network">
+          Network
         </message>
-        <message name="IDS_SANITIZE_DONE_BUTTON_CHROME_LANGUAGES" translateable="false">
-          Chrome Languages
+        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_TITLE" desc="Accordion title for Chrome resets">
+          Chrome Settings
         </message>
-        <message name="IDS_SANITIZE_HEADING" translateable="false" desc="Name of the 'Safety reset' window">
-          Sanitize your device
+        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_SITE_CONTENT" desc="Instructions to adjust Chrome site content settings">
+          Site content
         </message>
-        <message name="IDS_SANITIZE_DESCRIPTION" translateable="false" desc="Description of the sanitization feature on the sanitize window">
-          Getting unwanted pop-ups, or other unexpected behavior? Sometimes,
-          apps and extensions that you install can change your ChromeOS settings
-          without you knowing.
+        <message name="IDS_SANITZIE_DONE_ACCORDION_CHROME_STARTUP" desc="Instruction to adjust Chrome startup settings">
+          Startup preferences
         </message>
-        <message name="IDS_SANITIZE_WARNING" translateable="false" desc="Warning text in the 'Sanitize' window">
-          This will disable extensions and reset your settings to safe defaults.
-          Tabs, files, and cookies will be preserved.
+        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_HOMEPAGE" desc="Instructions to adjust Chrome homepage settings">
+          Homepage
+        </message>
+        <message name="IDS_SANITIZE_DONE_ACCORDION_CHROME_LANGUAGES" desc="Instruction to adjust Chrome language settings">
+          Language
+        </message>
+        <message name="IDS_SANITIZE_DONE_BUTTON_EXTENSIONS" desc="Button label to redirect to Chrome Extensions page">
+          Extensions
+        </message>
+        <message name="IDS_SANITIZE_DONE_BUTTON_CHROMEOS_INPUT" desc="Button label to redirect to ChromeOS Input Settings">
+          Input settings
+        </message>
+        <message name="IDS_SANITIZE_DONE_BUTTON_CHROMEOS_NETWORK" desc="Button label to redirect to ChromeOS Network Settings">
+          Network settings
+        </message>
+        <message name="IDS_SANITIZE_DONE_BUTTON_CHROME_SITE_CONTENT" desc="Button label to redirect to Chrome Site Content Settings">
+          Site content settings
+        </message>
+        <message name="IDS_SANITIZE_DONE_BUTTON_CHROME_STARTUP" desc="Button label to redirect to Chrome Startup Settings">
+          Startup settings
+        </message>
+        <message name="IDS_SANITIZE_DONE_BUTTON_CHROME_HOMEPAGE" desc="Button label to redirect to Chrome Homepage Settings">
+          Homepage settings
+        </message>
+        <message name="IDS_SANITIZE_DONE_BUTTON_CHROME_LANGUAGES" desc="Button label to redirecto to Chrome Language Settings">
+          Language settings
+        </message>
+        <message name="IDS_SANITIZE_HEADING" desc="Name of the 'Safety reset' window">
+          Safety reset
+        </message>
+        <message name="IDS_SANITIZE_DESCRIPTION" desc="Description of the safety reset feature">
+          Safety reset can help remove unwanted pop-ups, fix network issues, and address other unexpected issues.
+        </message>
+        <message name="IDS_SANITIZE_WARNING" desc="Warning text in the safety reset">
+          Safety reset turns off Chrome browser extensions and resets network and other settings to safe defaults.
+          Your default search engine will be reset, but your tabs, files, cookies, and history won’t be changed.
         </message>
         <message name="IDS_SANITIZE_FEEDBACK" translateable="false" desc="Feedback label in the Reset Profile Settings dialog">
           Help make ChromeOS better by reporting the current settings
         </message>
-        <message name="IDS_SANITIZE_CANCEL" translateable="false" desc="Button label to cancel proceeding with sanitize">
+        <message name="IDS_SANITIZE_CANCEL" desc="Button label to cancel proceeding with the safety reset">
           Cancel
         </message>
 
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE.png.sha1
new file mode 100644
index 0000000..dd630c9
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE.png.sha1
@@ -0,0 +1 @@
+85d0c300038a95d2eb4c58f2c18c477ff4825b05
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_CANCEL.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_CANCEL.png.sha1
new file mode 100644
index 0000000..aeef82b
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_CANCEL.png.sha1
@@ -0,0 +1 @@
+71d4bed16a697e95f5adae296c497ad6b186f962
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DESCRIPTION.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..b1a81ebb
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+79c1f0bed66a9a53e77e4d871eedf93ba64d146e
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE.png.sha1
new file mode 100644
index 0000000..8280b7d
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE.png.sha1
@@ -0,0 +1 @@
+0cbcfb53a5fc798ec4d4befb7cb423adf4076ccf
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_INPUT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_INPUT.png.sha1
new file mode 100644
index 0000000..ba264ea0
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_INPUT.png.sha1
@@ -0,0 +1 @@
+5f7ec3c36de73b2a73a4410e3e5fc874209bf02c
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_NETWORK.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_NETWORK.png.sha1
new file mode 100644
index 0000000..2140b0342
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_NETWORK.png.sha1
@@ -0,0 +1 @@
+9f028958379acb2d7c532f6ee04dabcb4e150275
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_TITLE.png.sha1
new file mode 100644
index 0000000..387055e
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROMEOS_TITLE.png.sha1
@@ -0,0 +1 @@
+6d2d09ed7568991a14c273504162dbbad4329792
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_HOMEPAGE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_HOMEPAGE.png.sha1
new file mode 100644
index 0000000..1ad0dac
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_HOMEPAGE.png.sha1
@@ -0,0 +1 @@
+a321fc022a9b0452fee6e6bc27afe399e8d659d7
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_LANGUAGES.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_LANGUAGES.png.sha1
new file mode 100644
index 0000000..456a5cc
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_LANGUAGES.png.sha1
@@ -0,0 +1 @@
+bd6e536bdfd5b209498e4e096fac9f2987557721
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_SITE_CONTENT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_SITE_CONTENT.png.sha1
new file mode 100644
index 0000000..8751ea83
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_SITE_CONTENT.png.sha1
@@ -0,0 +1 @@
+ae9bdb8877a22e0ebaa6a0a773dbcf767c41baf8
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_TITLE.png.sha1
new file mode 100644
index 0000000..d8aca523
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_CHROME_TITLE.png.sha1
@@ -0,0 +1 @@
+b05906f4e089d79be4d097ac07e2987c0ef69caa
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_REENABLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_REENABLE.png.sha1
new file mode 100644
index 0000000..b8eb951
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_REENABLE.png.sha1
@@ -0,0 +1 @@
+662c248275a14cb9f34837c43960fec1bd0b0b40
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_TITLE.png.sha1
new file mode 100644
index 0000000..ff167d5
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ACCORDION_EXTENSIONS_TITLE.png.sha1
@@ -0,0 +1 @@
+bce90c278baa47907205312846f6ef63d46f171c
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROMEOS_INPUT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROMEOS_INPUT.png.sha1
new file mode 100644
index 0000000..d133cd0
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROMEOS_INPUT.png.sha1
@@ -0,0 +1 @@
+477e71026efd4a8839b45f032b291662f66ad2d4
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROMEOS_NETWORK.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROMEOS_NETWORK.png.sha1
new file mode 100644
index 0000000..03bd3cb1
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROMEOS_NETWORK.png.sha1
@@ -0,0 +1 @@
+b6e7685b7c6f6dfcc0742bcc93462eab9ae5a6e8
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_HOMEPAGE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_HOMEPAGE.png.sha1
new file mode 100644
index 0000000..dac1cf9
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_HOMEPAGE.png.sha1
@@ -0,0 +1 @@
+5c23e8b80cd5294ebbc9feb9e8d33231799b37f2
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_LANGUAGES.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_LANGUAGES.png.sha1
new file mode 100644
index 0000000..a51044c4
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_LANGUAGES.png.sha1
@@ -0,0 +1 @@
+75dfae1f393deeb15c01ecac84b9009e85a0a334
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_SITE_CONTENT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_SITE_CONTENT.png.sha1
new file mode 100644
index 0000000..5d3f1b9
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_SITE_CONTENT.png.sha1
@@ -0,0 +1 @@
+af214ac272113ebf5b46fef8a435a3a0ac786d9e
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_STARTUP.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_STARTUP.png.sha1
new file mode 100644
index 0000000..fbb2389
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_CHROME_STARTUP.png.sha1
@@ -0,0 +1 @@
+ec35565a00c5802fab951fe4b2bfe3869ae5e28b
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_EXTENSIONS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_EXTENSIONS.png.sha1
new file mode 100644
index 0000000..e70dc044
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_BUTTON_EXTENSIONS.png.sha1
@@ -0,0 +1 @@
+9b093a2d3cea6e84fd074b15bdd96fd21c8a2b86
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_DESCRIPTION.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..7272927
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+fffc87b7d1deefa2426c7627dc62ef36f96b2e78
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_HEADING.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_HEADING.png.sha1
new file mode 100644
index 0000000..d5ab0bfc
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_HEADING.png.sha1
@@ -0,0 +1 @@
+b5b16e5597413f3b6c5c297e2e168969823fb22e
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ROLLBACK.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ROLLBACK.png.sha1
new file mode 100644
index 0000000..0889e4e
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_DONE_ROLLBACK.png.sha1
@@ -0,0 +1 @@
+c0b14fccf0a886690e607637a6e6037e421b1279
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_HEADING.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_HEADING.png.sha1
new file mode 100644
index 0000000..b58faca
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_HEADING.png.sha1
@@ -0,0 +1 @@
+b09cd8ec463d33a922e028f131451da2513c4642
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITIZE_WARNING.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITIZE_WARNING.png.sha1
new file mode 100644
index 0000000..7851c4a
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITIZE_WARNING.png.sha1
@@ -0,0 +1 @@
+f07870e3e9447ced5e6e5a2fa2a59ff35e421b47
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SANITZIE_DONE_ACCORDION_CHROME_STARTUP.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SANITZIE_DONE_ACCORDION_CHROME_STARTUP.png.sha1
new file mode 100644
index 0000000..637f6a9e
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SANITZIE_DONE_ACCORDION_CHROME_STARTUP.png.sha1
@@ -0,0 +1 @@
+ce1eb138968aa390d2857fdb8b8105d70ee93822
\ No newline at end of file
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 4328608..eee81f1 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-130-6668.0-1725243046-benchmark-130.0.6701.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-130-6668.28-1725850545-benchmark-130.0.6707.0-r1-redacted.afdo.xz
diff --git a/clank b/clank
index 4720ec1..e5ba0da 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 4720ec1e1fe6d7a9f35ea36cf45c1b9b19da4a2b
+Subproject commit e5ba0da2a173ac40347c806053698ca2624857ea
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 4863f5107..77894ac 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -912,6 +912,8 @@
     "mock_single_field_form_fill_router.cc",
     "mock_single_field_form_fill_router.h",
     "payments/credit_card_access_manager_test_api.h",
+    "payments/credit_card_access_manager_test_base.cc",
+    "payments/credit_card_access_manager_test_base.h",
     "payments/mock_iban_access_manager.cc",
     "payments/mock_iban_access_manager.h",
     "payments/mock_test_payments_network_interface.cc",
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index cf76d01..56f39e41 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -257,6 +257,7 @@
   }
   // When a non-default source is active, shadow predictions between this
   // non-default source and default are emitted. Compute default predictions.
+  context.pattern_source = PatternSource::kDefault;
   context.active_features.clear();
   AssignBestFieldTypes(ParseFieldTypesWithPatterns(context),
                        HeuristicSource::kDefault);
diff --git a/components/autofill/core/browser/heuristic_source.cc b/components/autofill/core/browser/heuristic_source.cc
index 2f47c12..106400c 100644
--- a/components/autofill/core/browser/heuristic_source.cc
+++ b/components/autofill/core/browser/heuristic_source.cc
@@ -34,10 +34,10 @@
       return PatternSource::kLegacy;
 #else
     case HeuristicSource::kDefault:
+    case HeuristicSource::kExperimental:
       return PatternSource::kDefault;
     case HeuristicSource::kPredictionImprovements:
       return PatternSource::kPredictionImprovements;
-    case HeuristicSource::kExperimental:
 #endif
     case autofill::HeuristicSource::kMachineLearning:
       return std::nullopt;
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_utils.cc b/components/autofill/core/browser/metrics/autofill_metrics_utils.cc
index a8a1fcf3..cd9d559 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_utils.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_utils.cc
@@ -19,20 +19,6 @@
 constexpr DenseSet<FieldType> kFieldTypesOfATypicalStoreLocatorForm = {
     ADDRESS_HOME_CITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP};
 
-bool IsCvcOnlyForm(const FormStructure& form) {
-  if (form.fields().size() != 1) {
-    return false;
-  }
-  // Theoretically we don't need to check
-  // CREDIT_CARD_STANDALONE_VERIFICATION_CODE type here since if it's
-  // CREDIT_CARD_STANDALONE_VERIFICATION_CODE, the form type would be treated as
-  // kStandaloneCvcForm already. Add CREDIT_CARD_STANDALONE_VERIFICATION_CODE
-  // here just for completion.
-  static constexpr FieldTypeSet kCvcTypes = {
-      CREDIT_CARD_VERIFICATION_CODE, CREDIT_CARD_STANDALONE_VERIFICATION_CODE};
-  return kCvcTypes.contains(form.fields()[0]->Type().GetStorableType());
-}
-
 bool IsEmailOnlyForm(const FormStructure& form) {
   bool has_email_field = false;
   for (const auto& field : form.fields()) {
@@ -82,9 +68,7 @@
         }
         break;
       case FormType::kCreditCardForm:
-        form_types.insert(IsCvcOnlyForm(form)
-                              ? FormTypeNameForLogging::kStandaloneCvcForm
-                              : FormTypeNameForLogging::kCreditCardForm);
+        form_types.insert(FormTypeNameForLogging::kCreditCardForm);
         break;
       case FormType::kStandaloneCvcForm:
         form_types.insert(FormTypeNameForLogging::kStandaloneCvcForm);
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_utils_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_utils_unittest.cc
index ca8e5a8e..8c8f757 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_utils_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_utils_unittest.cc
@@ -189,21 +189,12 @@
         FormTypesForLoggingTestData(
             {CREDIT_CARD_STANDALONE_VERIFICATION_CODE},
             {FormTypeNameForLogging::kStandaloneCvcForm}),
-        // A standalone CVC form (with legacy CREDIT_CARD_VERIFICATION_CODE
-        // field) is not considered a credit card form.
-        FormTypesForLoggingTestData(
-            {CREDIT_CARD_VERIFICATION_CODE},
-            {FormTypeNameForLogging::kStandaloneCvcForm}),
-        // A single field address form has no credit card form types.
+        // An address form has no credit card form types.
         FormTypesForLoggingTestData({NAME_FIRST}, {}),
         // A form containing an address field and a credit card field, has one
         // credit card form type.
-        FormTypesForLoggingTestData({CREDIT_CARD_NUMBER, ADDRESS_HOME_LINE1},
-                                    {FormTypeNameForLogging::kCreditCardForm}),
-        // A form containing an address field and a cvc field, has one credit
-        // card form type.
         FormTypesForLoggingTestData(
-            {CREDIT_CARD_VERIFICATION_CODE, ADDRESS_HOME_LINE1},
+            {CREDIT_CARD_NUMBER, ADDRESS_HOME_LINE1},
             {FormTypeNameForLogging::kCreditCardForm})));
 
 // Test fixture for testing `GetFormTypesForLogging()`.
diff --git a/components/autofill/core/browser/metrics/payments/cvc_storage_metrics_unittest.cc b/components/autofill/core/browser/metrics/payments/cvc_storage_metrics_unittest.cc
index ce3ffec..ee7bc12 100644
--- a/components/autofill/core/browser/metrics/payments/cvc_storage_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/payments/cvc_storage_metrics_unittest.cc
@@ -10,39 +10,27 @@
 
 namespace autofill::autofill_metrics {
 
-namespace {
-constexpr char kCardGuid[] = "10000000-0000-0000-0000-000000000001";
-}  // namespace
-
 // Enum class for different CVC form types, which is used to parameterize the
 // metric test.
 enum class CvcFormType {
   kNormalCreditCardForm,
-  // A single field form with CREDIT_CARD_VERIFICATION_CODE.
   kStandaloneCvcWithLegacyVerificationCodeField,
-  // A single field form with CREDIT_CARD_STANDALONE_VERIFICATION_CODE.
   kStandaloneCvcForm,
 };
 
-// Params of CvcStorageMetricsTest:
-// -- CvcFormType form_type: Indicates which type of CVC form.
-// -- bool using_local_card: Indicates which type of card is used. If true, use
-// local card. Otherwise, use masked server card.
-class CvcStorageMetricsTest
-    : public AutofillMetricsBaseTest,
-      public testing::Test,
-      public testing::WithParamInterface<std::tuple<CvcFormType, bool>> {
+class CvcStorageMetricsTest : public AutofillMetricsBaseTest,
+                              public testing::Test,
+                              public testing::WithParamInterface<CvcFormType> {
  public:
   CvcStorageMetricsTest() = default;
   ~CvcStorageMetricsTest() override = default;
 
   const FormData& form() const { return form_; }
   const CreditCard& card() const { return card_; }
-  bool using_local_card() const { return std::get<1>(GetParam()); }
 
   void SetUp() override {
     SetUpHelper();
-    form_type_ = std::get<0>(GetParam());
+    form_type_ = GetParam();
 
     // Set up the form data. Reset form action to skip the IsFormMixedContent
     // check.
@@ -50,21 +38,9 @@
                                .fields = GetTestFormDataFields(),
                                .action = ""});
 
-    if (using_local_card()) {
-      card_ = test::WithCvc(test::GetCreditCard(), /*cvc=*/u"789");
-      card_.set_guid(kCardGuid);
-      personal_data().test_payments_data_manager().AddCreditCard(card_);
-      // Disable mandatory reauth as it is not part of this test and will
-      // interfere with the card retrieval flow.
-      personal_data()
-          .payments_data_manager()
-          .SetPaymentMethodsMandatoryReauthEnabled(false);
-    } else {
-      // Add a masked server card.
-      card_ = test::WithCvc(test::GetMaskedServerCard());
-      card_.set_guid(kCardGuid);
-      personal_data().test_payments_data_manager().AddServerCreditCard(card_);
-    }
+    // Add a masked server card.
+    card_ = test::WithCvc(test::GetMaskedServerCard());
+    personal_data().test_payments_data_manager().AddServerCreditCard(card_);
   }
 
   void TearDown() override { TearDownHelper(); }
@@ -88,8 +64,10 @@
   std::string GetExpectedHistogramName() {
     switch (form_type_) {
       case CvcFormType::kNormalCreditCardForm:
-        return "Autofill.FormEvents.CreditCard";
+      // TODO: crbug.com/356694842 - StandaloneCvc fields should log as
+      // StandaloneCvc instead of CreditCard.
       case CvcFormType::kStandaloneCvcWithLegacyVerificationCodeField:
+        return "Autofill.FormEvents.CreditCard";
       case CvcFormType::kStandaloneCvcForm:
         return "Autofill.FormEvents.StandaloneCvc";
     }
@@ -99,8 +77,8 @@
   std::string GetHistogramNameForEmptyRecord() {
     switch (form_type_) {
       case CvcFormType::kNormalCreditCardForm:
-        return "Autofill.FormEvents.StandaloneCvc";
       case CvcFormType::kStandaloneCvcWithLegacyVerificationCodeField:
+        return "Autofill.FormEvents.StandaloneCvc";
       case CvcFormType::kStandaloneCvcForm:
         return "Autofill.FormEvents.CreditCard";
     }
@@ -162,16 +140,14 @@
                              SuggestionType::kCreditCardEntry);
   autofill_manager().AuthenticateThenFillCreditCardForm(
       form(), form().fields().back(),
-      *personal_data().payments_data_manager().GetCreditCardByGUID(kCardGuid),
+      *personal_data().payments_data_manager().GetCreditCardByInstrumentId(
+          card().instrument_id()),
       {.trigger_source = AutofillTriggerSource::kPopup});
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples(GetExpectedHistogramName()),
       BucketsInclude(
-          base::Bucket(using_local_card()
-                           ? FORM_EVENT_LOCAL_SUGGESTION_FILLED
-                           : FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED,
-                       1),
+          base::Bucket(FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED, 1),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_SELECTED, 1),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_SELECTED_ONCE,
                        1)));
@@ -179,16 +155,14 @@
   // Simulate selecting the suggestion again.
   autofill_manager().AuthenticateThenFillCreditCardForm(
       form(), form().fields().front(),
-      *personal_data().payments_data_manager().GetCreditCardByGUID(kCardGuid),
+      *personal_data().payments_data_manager().GetCreditCardByInstrumentId(
+          card().instrument_id()),
       {.trigger_source = AutofillTriggerSource::kPopup});
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples(GetExpectedHistogramName()),
       BucketsInclude(
-          base::Bucket(using_local_card()
-                           ? FORM_EVENT_LOCAL_SUGGESTION_FILLED
-                           : FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED,
-                       2),
+          base::Bucket(FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED, 2),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_SELECTED, 2),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_SELECTED_ONCE,
                        1)));
@@ -207,22 +181,18 @@
   // Simulate filling the suggestion with CVC.
   autofill_manager().AuthenticateThenFillCreditCardForm(
       form(), form().fields().front(),
-      *personal_data().payments_data_manager().GetCreditCardByGUID(kCardGuid),
+      *personal_data().payments_data_manager().GetCreditCardByInstrumentId(
+          card().instrument_id()),
       {.trigger_source = AutofillTriggerSource::kPopup});
-  if (!using_local_card()) {
-    test_api(autofill_manager())
-        .OnCreditCardFetched(form(), form().fields().front(),
-                             AutofillTriggerSource::kPopup,
-                             CreditCardFetchResult::kSuccess, &card());
-  }
+  test_api(autofill_manager())
+      .OnCreditCardFetched(form(), form().fields().front(),
+                           AutofillTriggerSource::kPopup,
+                           CreditCardFetchResult::kSuccess, &card());
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples(GetExpectedHistogramName()),
       BucketsInclude(
-          base::Bucket(using_local_card()
-                           ? FORM_EVENT_LOCAL_SUGGESTION_FILLED
-                           : FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED,
-                       1),
+          base::Bucket(FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_FILLED, 1),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_FILLED_ONCE,
                        1)));
@@ -230,22 +200,17 @@
   // Fill the suggestion again.
   autofill_manager().AuthenticateThenFillCreditCardForm(
       form(), form().fields().front(),
-      *personal_data().payments_data_manager().GetCreditCardByGUID(kCardGuid),
+      *personal_data().payments_data_manager().GetCreditCardByInstrumentId(
+          card().instrument_id()),
       {.trigger_source = AutofillTriggerSource::kPopup});
-  if (!using_local_card()) {
-    test_api(autofill_manager())
-        .OnCreditCardFetched(form(), form().fields().front(),
-                             AutofillTriggerSource::kPopup,
-                             CreditCardFetchResult::kSuccess, &card());
-  }
-
+  test_api(autofill_manager())
+      .OnCreditCardFetched(form(), form().fields().front(),
+                           AutofillTriggerSource::kPopup,
+                           CreditCardFetchResult::kSuccess, &card());
   EXPECT_THAT(
       histogram_tester.GetAllSamples(GetExpectedHistogramName()),
       BucketsInclude(
-          base::Bucket(using_local_card()
-                           ? FORM_EVENT_LOCAL_SUGGESTION_FILLED
-                           : FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED,
-                       2),
+          base::Bucket(FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 2),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_FILLED, 2),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_FILLED_ONCE,
                        1)));
@@ -266,31 +231,24 @@
       form(), form().fields().front().global_id());
   autofill_manager().AuthenticateThenFillCreditCardForm(
       form(), form().fields().front(),
-      *personal_data().payments_data_manager().GetCreditCardByGUID(kCardGuid),
+      *personal_data().payments_data_manager().GetCreditCardByInstrumentId(
+          card().instrument_id()),
       {.trigger_source = AutofillTriggerSource::kPopup});
-  if (!using_local_card()) {
-    test_api(autofill_manager())
-        .OnCreditCardFetched(form(), form().fields().front(),
-                             AutofillTriggerSource::kPopup,
-                             CreditCardFetchResult::kSuccess, &card());
-  }
+  test_api(autofill_manager())
+      .OnCreditCardFetched(form(), form().fields().front(),
+                           AutofillTriggerSource::kPopup,
+                           CreditCardFetchResult::kSuccess, &card());
   SubmitForm(form());
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples(GetExpectedHistogramName()),
       BucketsInclude(
           base::Bucket(
-              using_local_card()
-                  ? FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE
-                  : FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE,
-              1),
+              FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 1),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_WILL_SUBMIT_ONCE,
                        1),
-          base::Bucket(
-              using_local_card()
-                  ? FORM_EVENT_LOCAL_SUGGESTION_SUBMITTED_ONCE
-                  : FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE,
-              1),
+          base::Bucket(FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE,
+                       1),
           base::Bucket(FORM_EVENT_SUGGESTION_FOR_CARD_WITH_CVC_SUBMITTED_ONCE,
                        1)));
   histogram_tester.ExpectTotalCount(GetHistogramNameForEmptyRecord(), 0);
@@ -299,11 +257,8 @@
 INSTANTIATE_TEST_SUITE_P(
     ,
     CvcStorageMetricsTest,
-    testing::Combine(
-        testing::Values(
-            CvcFormType::kNormalCreditCardForm,
-            CvcFormType::kStandaloneCvcWithLegacyVerificationCodeField,
-            CvcFormType::kStandaloneCvcForm),
-        testing::Bool()));
+    testing::Values(CvcFormType::kNormalCreditCardForm,
+                    CvcFormType::kStandaloneCvcWithLegacyVerificationCodeField,
+                    CvcFormType::kStandaloneCvcForm));
 
 }  // namespace autofill::autofill_metrics
diff --git a/components/autofill/core/browser/metrics/quality_metrics.cc b/components/autofill/core/browser/metrics/quality_metrics.cc
index 09a91b35..cc2b9f8 100644
--- a/components/autofill/core/browser/metrics/quality_metrics.cc
+++ b/components/autofill/core/browser/metrics/quality_metrics.cc
@@ -16,6 +16,7 @@
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/filling_product.h"
 #include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/heuristic_source.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics_utils.h"
 #include "components/autofill/core/browser/metrics/field_filling_stats_and_score_metrics.h"
 #include "components/autofill/core/browser/metrics/granular_filling_metrics_utils.h"
@@ -206,7 +207,8 @@
     AutofillMetrics::LogOverallPredictionQualityMetrics(
         form_interactions_ukm_logger, form, *field, metric_type);
     AutofillMetrics::LogEmailFieldPredictionMetrics(*field);
-    autofill_metrics::LogShadowPredictionComparison(*field);
+    autofill_metrics::LogShadowPredictionComparison(*field,
+                                                    GetActiveHeuristicSource());
   }
 }
 
diff --git a/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc b/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc
index 38135d14..dc6d5be 100644
--- a/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc
+++ b/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc
@@ -40,9 +40,10 @@
   }
 }
 
-void LogRegexShadowPredictions(const AutofillField& field) {
+void LogRegexShadowPredictions(const AutofillField& field,
+                               HeuristicSource active_source) {
 #if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS)
-  if (GetActiveHeuristicSource() == HeuristicSource::kDefault) {
+  if (active_source == HeuristicSource::kDefault) {
     base::UmaHistogramSparse(
         "Autofill.ShadowPredictions.DefaultHeuristicToDefaultServer",
         GetShadowPrediction(field.heuristic_type(), field.server_type(),
@@ -52,7 +53,7 @@
   // If the experimental source is active, emit shadow predictions against the
   // default patterns. `FormStructure::DetermineNonActiveHeuristicTypes()`
   // ensures that they were computed.
-  if (GetActiveHeuristicSource() == HeuristicSource::kExperimental) {
+  if (active_source == HeuristicSource::kExperimental) {
     base::UmaHistogramSparse(
         "Autofill.ShadowPredictions.ExperimentalToDefault",
         GetShadowPrediction(
@@ -107,8 +108,9 @@
   return encoding;
 }
 
-void LogShadowPredictionComparison(const AutofillField& field) {
-  LogRegexShadowPredictions(field);
+void LogShadowPredictionComparison(const AutofillField& field,
+                                   HeuristicSource active_source) {
+  LogRegexShadowPredictions(field, active_source);
   LogMlShadowPredictions(field);
 }
 
diff --git a/components/autofill/core/browser/metrics/shadow_prediction_metrics.h b/components/autofill/core/browser/metrics/shadow_prediction_metrics.h
index 117f7cc..56eeece 100644
--- a/components/autofill/core/browser/metrics/shadow_prediction_metrics.h
+++ b/components/autofill/core/browser/metrics/shadow_prediction_metrics.h
@@ -41,7 +41,10 @@
 
 // Logs Autofill.ShadowPredictions.* metrics by comparing the submitted
 // values to the actual and hypothetical predictions.
-void LogShadowPredictionComparison(const AutofillField& field);
+// Unfortunately, this code cannot rely on `GetActiveHeuristicSource()` because
+// tests need to simulate that experimental patterns are active.
+void LogShadowPredictionComparison(const AutofillField& field,
+                                   HeuristicSource active_source);
 
 }  // namespace autofill::autofill_metrics
 
diff --git a/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc b/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
index f61a6dd..d68f09a84 100644
--- a/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
@@ -9,19 +9,28 @@
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_parsing/buildflags.h"
-#include "components/autofill/core/browser/metrics/autofill_metrics_test_base.h"
-#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/form_data_test_api.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/form_structure_test_api.h"
+#include "components/autofill/core/browser/heuristic_source.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using ::autofill::mojom::SubmissionSource;
 using ::base::Bucket;
 using ::testing::IsEmpty;
 using ::testing::UnorderedElementsAre;
 
 namespace autofill::autofill_metrics {
 
+namespace {
+
+#if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS)
+void LogShadowPredictions(FormStructure& form, HeuristicSource active_source) {
+  for (const std::unique_ptr<AutofillField>& field : form) {
+    LogShadowPredictionComparison(*field, active_source);
+  }
+}
+#endif
+
 // These mirrors some of the values of `AutofillPredictionsComparisonResult`
 // defined in tools/metrics/histograms/enums.xml. The
 // `AutofillPredictionsComparisonResult` represents all the type-specific
@@ -46,27 +55,6 @@
 #endif
 };
 
-namespace {
-
-// Get a form with 2 fields.
-FormData GetFormWith2Fields(const GURL& form_origin) {
-  return test::GetFormData(
-      {.description_for_logging = "ShadowPredictions",
-       .fields =
-           {
-               {
-                   .label = u"Name",
-                   .name = u"name",
-               },
-               {
-                   .label = u"Email",
-                   .name = u"email",
-               },
-           },
-       .renderer_id = test::MakeFormRendererId(),
-       .main_frame_origin = url::Origin::Create(form_origin)});
-}
-
 // Test that various combinations of predictions and values are mapped to the
 // correct value in the metric enum.
 TEST(AutofillShadowPredictionComparisonTest,
@@ -124,76 +112,42 @@
   }
 }
 
-class AutofillShadowPredictionMetricsTest : public AutofillMetricsBaseTest,
-                                            public testing::Test {
- public:
-  void SetUp() override { SetUpHelper(); }
-  void TearDown() override { TearDownHelper(); }
-};
-
-// When shadow predictions are not calculated, the shadow prediction metrics
-// should report `0`.
-// TODO(crbug.com/364593932): Shadow predictions only get emitted when
-// `HeuristicSource::kExperimental` is active. Find a way to so in tests.
-TEST_F(AutofillShadowPredictionMetricsTest,
-       DISABLED_SubmissionWithoutShadowPredictions) {
-  FormData form = GetFormWith2Fields(autofill_client_->form_origin());
-  test_api(form).field(0).set_value(
-      u"Elvis Aaron Presley");  // A known `NAME_FULL`.
-  test_api(form).field(1).set_value(
-      u"buddy@gmail.com");  // A known `EMAIL_ADDRESS`.
-
-  std::vector<FieldType> heuristic_types = {NAME_FULL, EMAIL_ADDRESS};
-  std::vector<FieldType> server_types = {NAME_FULL, EMAIL_ADDRESS};
-
-  // Simulate having seen this form on page load.
-  autofill_manager().AddSeenForm(form, heuristic_types, server_types);
-
-  // Simulate form submission.
-  base::HistogramTester histogram_tester;
-  autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
-                                     SubmissionSource::FORM_SUBMISSION);
-
 #if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS)
-  histogram_tester.ExpectBucketCount(
-      "Autofill.ShadowPredictions.ExperimentalToDefault", kNoPrediction, 2);
-#else
+// When default is active, no shadow predictions metrics should be reported.
+TEST(AutofillShadowPredictionMetricsTest, SubmissionWithoutShadowPredictions) {
+  FormStructure form(FormData{});
+  test_api(form).PushField().set_possible_types({NAME_FULL});
+  test_api(form).PushField().set_possible_types({EMAIL_ADDRESS});
+  test_api(form).SetFieldTypes(/*heuristic_types=*/{NAME_FULL, EMAIL_ADDRESS},
+                               /*server_types=*/{NAME_FULL, EMAIL_ADDRESS});
+
+  base::HistogramTester histogram_tester;
+  LogShadowPredictions(form, HeuristicSource::kDefault);
+
   EXPECT_THAT(histogram_tester.GetAllSamples(
                   "Autofill.ShadowPredictions.ExperimentalToDefault"),
               IsEmpty());
-#endif
 }
 
-#if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS)
 // Test that Autofill.ShadowPredictions.* describes the differences between the
 // predictions and the submitted values.
-// TODO(crbug.com/364593932): Shadow predictions only get emitted when
-// `HeuristicSource::kExperimental` is active. Find a way to do so in tests.
-TEST_F(AutofillShadowPredictionMetricsTest,
-       DISABLED_SubmissionWithAgreeingShadowPredictions) {
-  FormData form = GetFormWith2Fields(autofill_client_->form_origin());
-  test_api(form).field(0).set_value(
-      u"Elvis Aaron Presley");  // A known `NAME_FULL`.
-  test_api(form).field(1).set_value(
-      u"buddy@gmail.com");  // A known `EMAIL_ADDRESS`.
+TEST(AutofillShadowPredictionMetricsTest,
+     SubmissionWithAgreeingShadowPredictions) {
+  FormStructure form(FormData{});
+  test_api(form).PushField().set_possible_types({NAME_FULL});
+  test_api(form).PushField().set_possible_types({EMAIL_ADDRESS});
+  test_api(form).SetFieldTypes(/*heuristic_types=*/
+                               {{{HeuristicSource::kDefault, NAME_FULL},
+                                 {HeuristicSource::kExperimental, NAME_FULL}},
+                                {{HeuristicSource::kDefault, SEARCH_TERM},
+                                 {HeuristicSource::kExperimental,
+                                  EMAIL_ADDRESS}}},
+                               {NAME_FULL, EMAIL_ADDRESS});
 
-  std::vector<FieldType> server_types = {NAME_FULL, EMAIL_ADDRESS};
-
-  // Simulate having seen this form on page load.
-  autofill_manager().AddSeenForm(
-      form,
-      {// Field 0
-       {{HeuristicSource::kDefault, NAME_FULL},
-        {HeuristicSource::kExperimental, NAME_FULL}},
-       // Field 1
-       {{HeuristicSource::kDefault, SEARCH_TERM},
-        {HeuristicSource::kExperimental, EMAIL_ADDRESS}}},
-      server_types);
-
-  // Simulate form submission.
   base::HistogramTester histogram_tester;
-  autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
-                                     SubmissionSource::FORM_SUBMISSION);
+  // Shadow predictions between default and experiment are only emitted if
+  // experimental is active.
+  LogShadowPredictions(form, HeuristicSource::kExperimental);
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples(
@@ -205,29 +159,15 @@
 
 // Test that Autofill.ShadowPredictions.DefaultHeuristicToDefaultServer compares
 // heuristics to server predictions.
-TEST_F(AutofillShadowPredictionMetricsTest, CompareHeuristicsAndServer) {
-  constexpr HeuristicSource source = HeuristicSource::kDefault;
+TEST(AutofillShadowPredictionMetricsTest, CompareHeuristicsAndServer) {
+  FormStructure form(FormData{});
+  test_api(form).PushField().set_possible_types({NAME_FULL});
+  test_api(form).PushField().set_possible_types({EMAIL_ADDRESS});
+  test_api(form).SetFieldTypes(/*heuristic_types=*/{NAME_FULL, SEARCH_TERM},
+                               /*server_types=*/{NAME_FULL, EMAIL_ADDRESS});
 
-  FormData form = GetFormWith2Fields(autofill_client_->form_origin());
-  test_api(form).field(0).set_value(
-      u"Elvis Aaron Presley");  // A known `NAME_FULL`.
-  test_api(form).field(1).set_value(
-      u"buddy@gmail.com");  // A known `EMAIL_ADDRESS`.
-
-  std::vector<FieldType> server_types = {NAME_FULL, EMAIL_ADDRESS};
-
-  // Simulate having seen this form on page load.
-  autofill_manager().AddSeenForm(form,
-                                 {// Field 0
-                                  {{source, NAME_FULL}},
-                                  // Field 1
-                                  {{source, SEARCH_TERM}}},
-                                 server_types);
-
-  // Simulate form submission.
   base::HistogramTester histogram_tester;
-  autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
-                                     SubmissionSource::FORM_SUBMISSION);
+  LogShadowPredictions(form, HeuristicSource::kDefault);
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples(
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_test_base.cc b/components/autofill/core/browser/payments/credit_card_access_manager_test_base.cc
new file mode 100644
index 0000000..85c756c
--- /dev/null
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_test_base.cc
@@ -0,0 +1,528 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/payments/credit_card_access_manager_test_base.h"
+
+#include "base/functional/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/payments/card_unmask_challenge_option.h"
+#include "components/autofill/core/browser/payments/credit_card_access_manager_test_api.h"
+#include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
+#include "components/autofill/core/browser/payments/payments_autofill_client.h"
+#include "components/autofill/core/browser/payments/test/mock_payments_window_manager.h"
+#include "components/autofill/core/browser/payments/test/test_credit_card_otp_authenticator.h"
+#include "components/autofill/core/browser/payments/test_payments_autofill_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
+#include "components/autofill/core/browser/payments_data_manager.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_autofill_driver.h"
+#include "components/autofill/core/browser/test_browser_autofill_manager.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/sync/test/test_sync_service.h"
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+#include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h"
+#include "components/autofill/core/browser/payments/test_internal_authenticator.h"
+#include "components/autofill/core/browser/strike_databases/payments/fido_authentication_strike_database.h"
+#endif
+
+namespace autofill {
+namespace {
+using PaymentsRpcCardType =
+    payments::PaymentsAutofillClient::PaymentsRpcCardType;
+using PaymentsRpcResult =
+    payments::TestPaymentsAutofillClient::PaymentsRpcResult;
+}  // namespace
+
+CreditCardAccessManagerTestBase::TestAccessor::TestAccessor() = default;
+CreditCardAccessManagerTestBase::TestAccessor::~TestAccessor() = default;
+
+void CreditCardAccessManagerTestBase::TestAccessor::OnCreditCardFetched(
+    CreditCardFetchResult result,
+    const CreditCard* card) {
+  result_ = result;
+  if (result == CreditCardFetchResult::kSuccess) {
+    DCHECK(card);
+    number_ = card->number();
+    cvc_ = card->cvc();
+    expiry_month_ = card->Expiration2DigitMonthAsString();
+    expiry_year_ = card->Expiration4DigitYearAsString();
+  }
+}
+
+CreditCardAccessManagerTestBase::CreditCardAccessManagerTestBase()
+    : task_environment_(
+          base::test::TaskEnvironment::TimeSource::MOCK_TIME,
+          base::test::TaskEnvironment::MainThreadType::DEFAULT,
+          base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {
+  // Advance the mock clock to 2021-01-01, 00:00:00.000.
+  base::Time year_2021;
+  CHECK(base::Time::FromUTCExploded({.year = 2021,
+                                     .month = 1,
+                                     .day_of_week = 4,
+                                     .day_of_month = 1,
+                                     .hour = 0,
+                                     .minute = 0,
+                                     .second = 0,
+                                     .millisecond = 0},
+                                    &year_2021));
+  task_environment_.AdvanceClock(year_2021 -
+                                 task_environment_.GetMockClock()->Now());
+}
+
+CreditCardAccessManagerTestBase::~CreditCardAccessManagerTestBase() = default;
+
+void CreditCardAccessManagerTestBase::SetUp() {
+  autofill_client_.SetPrefs(test::PrefServiceForTesting());
+  personal_data().SetPrefService(autofill_client_.GetPrefs());
+  personal_data().SetSyncServiceForTest(&sync_service_);
+#if BUILDFLAG(IS_IOS)
+  // On iOS mandatory reauth is by default enabled. Disable it explicitly
+  // to not interfere with tests that do not test reauth functionalities.
+  autofill_client_.GetPrefs()->SetBoolean(
+      prefs::kAutofillPaymentMethodsMandatoryReauth, false);
+#endif
+  accessor_ = std::make_unique<TestAccessor>();
+  autofill_driver_ = std::make_unique<TestAutofillDriver>(&autofill_client_);
+
+  autofill_client_.GetPaymentsAutofillClient()
+      ->set_test_payments_network_interface(
+          std::make_unique<payments::TestPaymentsNetworkInterface>(
+              autofill_client_.GetURLLoaderFactory(),
+              autofill_client_.GetIdentityManager(), &personal_data()));
+  autofill_client_.set_test_strike_database(
+      std::make_unique<TestStrikeDatabase>());
+  autofill_driver_->set_autofill_manager(
+      std::make_unique<TestBrowserAutofillManager>(autofill_driver_.get()));
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  autofill_driver_->SetAuthenticator(new TestInternalAuthenticator());
+  test_api(credit_card_access_manager())
+      .set_fido_authenticator(std::make_unique<TestCreditCardFidoAuthenticator>(
+          autofill_driver_.get(), &autofill_client_));
+#endif
+  auto otp_authenticator =
+      std::make_unique<TestCreditCardOtpAuthenticator>(&autofill_client_);
+  otp_authenticator_ = otp_authenticator.get();
+  autofill_client_.GetPaymentsAutofillClient()->set_otp_authenticator(
+      std::move(otp_authenticator));
+
+  // Force creation of the CreditCardAccessManager.
+  std::ignore = credit_card_access_manager();
+}
+
+bool CreditCardAccessManagerTestBase::IsAuthenticationInProgress() {
+  return test_api(credit_card_access_manager()).is_authentication_in_progress();
+}
+
+void CreditCardAccessManagerTestBase::ResetFetchCreditCard() {
+  test_api(credit_card_access_manager())
+      .set_is_authentication_in_progress(false);
+  test_api(credit_card_access_manager()).set_can_fetch_unmask_details(true);
+  test_api(credit_card_access_manager())
+      .set_unmask_details_request_in_progress(false);
+  test_api(credit_card_access_manager()).set_is_user_verifiable(std::nullopt);
+}
+
+void CreditCardAccessManagerTestBase::ClearCards() {
+  personal_data().test_payments_data_manager().ClearCreditCards();
+}
+
+void CreditCardAccessManagerTestBase::CreateLocalCard(std::string guid,
+                                                      std::string number) {
+  CreditCard local_card = CreditCard();
+  test::SetCreditCardInfo(&local_card, "Elvis Presley", number.c_str(),
+                          test::NextMonth().c_str(), test::NextYear().c_str(),
+                          "1", kTestCvc16);
+  local_card.set_guid(guid);
+  local_card.set_record_type(CreditCard::RecordType::kLocalCard);
+
+  personal_data().payments_data_manager().AddCreditCard(local_card);
+}
+
+CreditCard* CreditCardAccessManagerTestBase::CreateServerCard(
+    std::string guid,
+    std::string number,
+    std::string server_id) {
+  CreditCard server_card = CreditCard();
+  test::SetCreditCardInfo(&server_card, "Elvis Presley", number.c_str(),
+                          test::NextMonth().c_str(), test::NextYear().c_str(),
+                          "1", kTestCvc16);
+  server_card.set_guid(guid);
+  server_card.set_record_type(CreditCard::RecordType::kMaskedServerCard);
+  server_card.set_server_id(server_id);
+  personal_data().test_payments_data_manager().AddServerCreditCard(server_card);
+  return personal_data().payments_data_manager().GetCreditCardByGUID(guid);
+}
+
+CreditCardCvcAuthenticator&
+CreditCardAccessManagerTestBase::GetCvcAuthenticator() {
+  return autofill_client_.GetPaymentsAutofillClient()->GetCvcAuthenticator();
+}
+
+void CreditCardAccessManagerTestBase::MockUserResponseForCvcAuth(
+    std::u16string cvc,
+    bool enable_fido) {
+  payments::FullCardRequest* full_card_request =
+      GetCvcAuthenticator().full_card_request_.get();
+  if (!full_card_request) {
+    return;
+  }
+
+  // Mock user response.
+  payments::FullCardRequest::UserProvidedUnmaskDetails details;
+  details.cvc = cvc;
+#if BUILDFLAG(IS_ANDROID)
+  details.enable_fido_auth = enable_fido;
+#endif
+  full_card_request->OnUnmaskPromptAccepted(details);
+  full_card_request->OnDidGetUnmaskRiskData(/*risk_data=*/"");
+}
+
+bool CreditCardAccessManagerTestBase::GetRealPanForCVCAuth(
+    PaymentsRpcResult result,
+    const std::string& real_pan,
+    TestFidoRequestOptionsType test_fido_request_options_type) {
+  payments::FullCardRequest* full_card_request =
+      GetCvcAuthenticator().full_card_request_.get();
+
+  if (!full_card_request) {
+    return false;
+  }
+
+  MockUserResponseForCvcAuth(kTestCvc16,
+                             /*enable_fido=*/test_fido_request_options_type !=
+                                 TestFidoRequestOptionsType::kNotPresent);
+
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  response.card_authorization_token = "dummy_card_authorization_token";
+  if (test_fido_request_options_type == TestFidoRequestOptionsType::kValid) {
+    response.fido_request_options = GetTestRequestOptions();
+  } else if (test_fido_request_options_type ==
+             TestFidoRequestOptionsType::kInvalid) {
+    response.fido_request_options =
+        GetTestRequestOptions(/*return_invalid_request_options=*/true);
+  }
+#endif
+  response.card_type = PaymentsRpcCardType::kServerCard;
+  full_card_request->OnDidGetRealPan(result, response.with_real_pan(real_pan));
+  return true;
+}
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+void CreditCardAccessManagerTestBase::AddMaxStrikes() {
+  auto* strike_database =
+      GetFIDOAuthenticator()->GetOrCreateFidoAuthenticationStrikeDatabase();
+  CHECK(strike_database);
+  strike_database->AddStrikes(strike_database->GetMaxStrikesLimit());
+}
+
+void CreditCardAccessManagerTestBase::ClearStrikes() {
+  auto* strike_database =
+      GetFIDOAuthenticator()->GetOrCreateFidoAuthenticationStrikeDatabase();
+  CHECK(strike_database);
+  strike_database->ClearAllStrikes();
+}
+
+int CreditCardAccessManagerTestBase::GetStrikes() {
+  auto* strike_database =
+      GetFIDOAuthenticator()->GetOrCreateFidoAuthenticationStrikeDatabase();
+  CHECK(strike_database);
+  return strike_database->GetStrikes();
+}
+
+base::Value::Dict CreditCardAccessManagerTestBase::GetTestRequestOptions(
+    bool return_invalid_request_options) {
+  base::Value::Dict request_options;
+  request_options.Set("challenge", base::Value(kTestChallenge));
+  request_options.Set("relying_party_id", base::Value(kGooglePaymentsRpid));
+
+  // If invalid request options are to be returned, don't set key info or
+  // credential ID.
+  if (return_invalid_request_options) {
+    return request_options;
+  }
+
+  base::Value::Dict key_info;
+  key_info.Set("credential_id", base::Value(kCredentialId));
+  request_options.Set("key_info", base::Value(base::Value::Type::LIST));
+  request_options.FindList("key_info")->Append(std::move(key_info));
+  return request_options;
+}
+
+base::Value::Dict CreditCardAccessManagerTestBase::GetTestCreationOptions() {
+  base::Value::Dict creation_options;
+  creation_options.Set("challenge", base::Value(kTestChallenge));
+  creation_options.Set("relying_party_id", base::Value(kGooglePaymentsRpid));
+  return creation_options;
+}
+
+bool CreditCardAccessManagerTestBase::GetRealPanForFIDOAuth(
+    PaymentsRpcResult result,
+    const std::string& real_pan,
+    const std::string& dcvv,
+    bool is_virtual_card) {
+  payments::FullCardRequest* full_card_request =
+      GetFIDOAuthenticator()->full_card_request_.get();
+
+  if (!full_card_request) {
+    return false;
+  }
+
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
+  response.card_type = is_virtual_card ? PaymentsRpcCardType::kVirtualCard
+                                       : PaymentsRpcCardType::kServerCard;
+  full_card_request->OnDidGetRealPan(
+      result, response.with_real_pan(real_pan).with_dcvv(dcvv));
+  return true;
+}
+
+void CreditCardAccessManagerTestBase::OptChange(PaymentsRpcResult result,
+                                                bool user_is_opted_in,
+                                                bool include_creation_options,
+                                                bool include_request_options) {
+  payments::PaymentsNetworkInterface::OptChangeResponseDetails response;
+  response.user_is_opted_in = user_is_opted_in;
+  if (include_creation_options) {
+    response.fido_creation_options = GetTestCreationOptions();
+  }
+  if (include_request_options) {
+    response.fido_request_options = GetTestRequestOptions();
+  }
+  GetFIDOAuthenticator()->OnDidGetOptChangeResult(result, response);
+}
+
+TestCreditCardFidoAuthenticator*
+CreditCardAccessManagerTestBase::GetFIDOAuthenticator() {
+  return static_cast<TestCreditCardFidoAuthenticator*>(
+      credit_card_access_manager().GetOrCreateFidoAuthenticator());
+}
+#endif
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+void CreditCardAccessManagerTestBase::AcceptWebauthnOfferDialog(
+    bool did_accept) {
+  GetFIDOAuthenticator()->OnWebauthnOfferDialogUserResponse(did_accept);
+}
+#endif
+
+void CreditCardAccessManagerTestBase::InvokeDelayedGetUnmaskDetailsResponse() {
+  test_api(credit_card_access_manager())
+      .OnDidGetUnmaskDetails(PaymentsRpcResult::kSuccess,
+                             *payments_network_interface().unmask_details());
+}
+
+void CreditCardAccessManagerTestBase::InvokeUnmaskDetailsTimeout() {
+  test_api(credit_card_access_manager())
+      .ready_to_start_authentication()
+      .Signal();
+  test_api(credit_card_access_manager()).set_can_fetch_unmask_details(true);
+}
+
+void CreditCardAccessManagerTestBase::WaitForCallbacks() {
+  task_environment_.RunUntilIdle();
+}
+
+void CreditCardAccessManagerTestBase::SetCreditCardFIDOAuthEnabled(
+    bool enabled) {
+  prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), enabled);
+}
+
+bool CreditCardAccessManagerTestBase::IsCreditCardFIDOAuthEnabled() {
+  return prefs::IsCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs());
+}
+
+UnmaskAuthFlowType CreditCardAccessManagerTestBase::GetUnmaskAuthFlowType() {
+  return test_api(credit_card_access_manager()).unmask_auth_flow_type();
+}
+
+void CreditCardAccessManagerTestBase::
+    MockCardUnmaskFlowUpToAuthenticationSelectionDialogAccepted(
+        bool fido_authenticator_is_user_opted_in,
+        bool is_user_verifiable,
+        const std::vector<CardUnmaskChallengeOption>& challenge_options,
+        int selected_index) {
+  CreateServerCard(kTestGUID, kTestNumber, kTestServerId);
+  CreditCard* virtual_card =
+      personal_data().payments_data_manager().GetCreditCardByGUID(kTestGUID);
+  virtual_card->set_record_type(CreditCard::RecordType::kVirtualCard);
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  fido_authenticator().set_is_user_opted_in(
+      fido_authenticator_is_user_opted_in);
+#endif
+
+  // TODO(crbug.com/40197696): Switch to SetUserVerifiable after moving all
+  // |is_user_verifiable_| related logic from CreditCardAccessManager to
+  // CreditCardFidoAuthenticator.
+  test_api(credit_card_access_manager())
+      .set_is_user_verifiable(is_user_verifiable);
+  credit_card_access_manager().FetchCreditCard(
+      virtual_card, base::BindOnce(&TestAccessor::OnCreditCardFetched,
+                                   accessor_->GetWeakPtr()));
+
+  // This checks risk-based authentication flow is successfully invoked,
+  // because it is always the very first authentication flow in a VCN
+  // unmasking flow.
+  EXPECT_TRUE(autofill_client_.GetPaymentsAutofillClient()
+                  ->risk_based_authentication_invoked());
+  // Mock server response with information regarding VCN auth.
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
+  response.context_token = "fake_context_token";
+  response.card_unmask_challenge_options = challenge_options;
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  if (fido_authenticator_is_user_opted_in) {
+    response.fido_request_options = GetTestRequestOptions();
+  }
+#endif
+  credit_card_access_manager()
+      .OnVirtualCardRiskBasedAuthenticationResponseReceived(
+          PaymentsRpcResult::kSuccess, response);
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  // This if-statement ensures that fido-related flows run correctly.
+  if (fido_authenticator_is_user_opted_in) {
+    // Expect the CreditCardAccessManager invokes the FIDO authenticator
+    // first.
+    ASSERT_TRUE(fido_authenticator().authenticate_invoked());
+    EXPECT_EQ(fido_authenticator().card().number(),
+              base::UTF8ToUTF16(std::string(kTestNumber)));
+    EXPECT_EQ(fido_authenticator().card().record_type(),
+              CreditCard::RecordType::kVirtualCard);
+    ASSERT_TRUE(fido_authenticator().context_token().has_value());
+    EXPECT_EQ(fido_authenticator().context_token().value(),
+              "fake_context_token");
+
+    CreditCardFidoAuthenticator::FidoAuthenticationResponse fido_response{
+        .did_succeed = false};
+    test_api(credit_card_access_manager())
+        .OnFIDOAuthenticationComplete(fido_response);
+  }
+#endif
+
+  const CardUnmaskChallengeOption& challenge_option =
+      response.card_unmask_challenge_options[selected_index];
+
+  payments::PaymentsWindowManager::Vcn3dsContext vcn_3ds_context;
+  if (challenge_option.type ==
+      CardUnmaskChallengeOptionType::kThreeDomainSecure) {
+    EXPECT_CALL(*static_cast<payments::MockPaymentsWindowManager*>(
+                    autofill_client_.GetPaymentsAutofillClient()
+                        ->GetPaymentsWindowManager()),
+                InitVcn3dsAuthentication)
+        .Times(1)
+        .WillOnce([&vcn_3ds_context](
+                      payments::PaymentsWindowManager::Vcn3dsContext context) {
+          vcn_3ds_context = std::move(context);
+        });
+  }
+
+  test_api(credit_card_access_manager())
+      .OnUserAcceptedAuthenticationSelectionDialog(challenge_option.id.value());
+
+  // TODO(crbug.com/329523854): Check that the challenge selection acceptance
+  // was handled correctly using mocks instead of test classes.
+  switch (challenge_option.type) {
+    case CardUnmaskChallengeOptionType::kCvc: {
+      CreditCardCvcAuthenticator& cvc_authenticator =
+          autofill_client_.GetPaymentsAutofillClient()->GetCvcAuthenticator();
+      payments::PaymentsNetworkInterface::UnmaskRequestDetails*
+          request_details =
+              cvc_authenticator.GetFullCardRequest()->request_.get();
+      EXPECT_EQ(request_details->card.record_type(),
+                CreditCard::RecordType::kVirtualCard);
+      EXPECT_EQ(request_details->card.number(),
+                base::UTF8ToUTF16(std::string(kTestNumber)));
+      EXPECT_EQ(request_details->context_token, "fake_context_token");
+      EXPECT_EQ(request_details->selected_challenge_option->id.value(), "234");
+      EXPECT_EQ(request_details->selected_challenge_option->type,
+                CardUnmaskChallengeOptionType::kCvc);
+      break;
+    }
+    case CardUnmaskChallengeOptionType::kSmsOtp:
+      VerifyOnSelectChallengeOptionInvoked();
+      EXPECT_EQ(otp_authenticator_->selected_challenge_option().id.value(),
+                "123");
+      EXPECT_EQ(otp_authenticator_->selected_challenge_option().type,
+                CardUnmaskChallengeOptionType::kSmsOtp);
+      EXPECT_EQ(otp_authenticator_->selected_challenge_option().challenge_info,
+                u"xxx-xxx-3547");
+      break;
+    case CardUnmaskChallengeOptionType::kEmailOtp:
+      VerifyOnSelectChallengeOptionInvoked();
+      EXPECT_EQ(otp_authenticator_->selected_challenge_option().id.value(),
+                "345");
+      EXPECT_EQ(otp_authenticator_->selected_challenge_option().type,
+                CardUnmaskChallengeOptionType::kEmailOtp);
+      EXPECT_EQ(otp_authenticator_->selected_challenge_option().challenge_info,
+                u"a******b@google.com");
+      break;
+    case CardUnmaskChallengeOptionType::kThreeDomainSecure:
+      EXPECT_EQ(vcn_3ds_context.context_token, response.context_token);
+      EXPECT_EQ(vcn_3ds_context.card, *virtual_card);
+      EXPECT_EQ(vcn_3ds_context.challenge_option.type,
+                CardUnmaskChallengeOptionType::kThreeDomainSecure);
+      EXPECT_TRUE(vcn_3ds_context.user_consent_already_given);
+      break;
+    case CardUnmaskChallengeOptionType::kUnknownType:
+      NOTREACHED_IN_MIGRATION();
+      break;
+  }
+}
+
+void CreditCardAccessManagerTestBase::VerifyOnSelectChallengeOptionInvoked() {
+  DCHECK(otp_authenticator_);
+  EXPECT_TRUE(otp_authenticator_->on_challenge_option_selected_invoked());
+  EXPECT_EQ(otp_authenticator_->card().number(),
+            base::UTF8ToUTF16(std::string(kTestNumber)));
+  EXPECT_EQ(otp_authenticator_->card().record_type(),
+            CreditCard::RecordType::kVirtualCard);
+  EXPECT_EQ(otp_authenticator_->context_token(), "fake_context_token");
+}
+
+CreditCardAccessManager&
+CreditCardAccessManagerTestBase::credit_card_access_manager() {
+  return static_cast<BrowserAutofillManager&>(
+             autofill_driver_->GetAutofillManager())
+      .GetCreditCardAccessManager();
+}
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+TestCreditCardFidoAuthenticator&
+CreditCardAccessManagerTestBase::fido_authenticator() {
+  return static_cast<TestCreditCardFidoAuthenticator&>(
+      *credit_card_access_manager().GetOrCreateFidoAuthenticator());
+}
+#endif
+
+payments::TestPaymentsNetworkInterface&
+CreditCardAccessManagerTestBase::payments_network_interface() {
+  return *autofill_client_.GetPaymentsAutofillClient()
+              ->GetPaymentsNetworkInterface();
+}
+
+TestPersonalDataManager& CreditCardAccessManagerTestBase::personal_data() {
+  return *autofill_client_.GetPersonalDataManager();
+}
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+void CreditCardAccessManagerTestBase::OptUserInToFido() {
+  std::string other_server_id = "00000000-0000-0000-0000-000000000034";
+  // Add a random FIDO eligible card, it will return RequestOptions in unmask
+  // details.
+  payments_network_interface().AddFidoEligibleCard(
+      other_server_id, kCredentialId, kGooglePaymentsRpid);
+  GetFIDOAuthenticator()->SetUserVerifiable(true);
+  SetCreditCardFIDOAuthEnabled(true);
+}
+#endif
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_test_base.h b/components/autofill/core/browser/payments/credit_card_access_manager_test_base.h
new file mode 100644
index 0000000..bbe7774
--- /dev/null
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_test_base.h
@@ -0,0 +1,199 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_ACCESS_MANAGER_TEST_BASE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_ACCESS_MANAGER_TEST_BASE_H_
+
+#include "base/memory/raw_ptr.h"
+#include "base/test/task_environment.h"
+#include "build/build_config.h"
+#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
+#include "components/autofill/core/browser/payments/payments_autofill_client.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/sync/test/test_sync_service.h"
+#include "components/variations/scoped_variations_ids_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+namespace payments {
+class TestPaymentsNetworkInterface;
+}  // namespace payments
+
+class CreditCard;
+class CreditCardCvcAuthenticator;
+class TestAutofillDriver;
+class TestCreditCardOtpAuthenticator;
+class TestPersonalDataManager;
+
+struct CardUnmaskChallengeOption;
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+class TestCreditCardFidoAuthenticator;
+#endif
+
+// A base class for unittests for CreditCardAccessManager, containing logic and
+// state that is shared across multiple test classes.
+class CreditCardAccessManagerTestBase : public testing::Test {
+ public:
+  static constexpr char kTestGUID[] = "00000000-0000-0000-0000-000000000001";
+  static constexpr char kTestGUID2[] = "00000000-0000-0000-0000-000000000002";
+  static constexpr char kTestNumber[] = "4234567890123456";  // Visa
+  static constexpr char kTestNumber2[] = "5454545454545454";
+  static constexpr char16_t kTestNumber16[] = u"4234567890123456";
+  static constexpr char16_t kTestCvc16[] = u"123";
+  static constexpr char kTestServerId[] = "server_id_1";
+  static constexpr char kTestServerId2[] = "server_id_2";
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  static constexpr char kTestCvc[] = "123";
+  // Base64 encoding of "This is a test challenge".
+  static constexpr char kTestChallenge[] = "VGhpcyBpcyBhIHRlc3QgY2hhbGxlbmdl";
+  // Base64 encoding of "This is a test Credential ID".
+  static constexpr char kCredentialId[] =
+      "VGhpcyBpcyBhIHRlc3QgQ3JlZGVudGlhbCBJRC4=";
+  static constexpr char kGooglePaymentsRpid[] = "google.com";
+#endif
+
+  // Implements an `OnCreditCardFetched()` callback that stores the values it
+  // receives.
+  class TestAccessor {
+   public:
+    TestAccessor();
+    ~TestAccessor();
+
+    void OnCreditCardFetched(CreditCardFetchResult result,
+                             const CreditCard* card);
+
+    base::WeakPtr<TestAccessor> GetWeakPtr() {
+      return weak_ptr_factory_.GetWeakPtr();
+    }
+
+    std::u16string number() { return number_; }
+    std::u16string cvc() { return cvc_; }
+    std::u16string expiry_month() { return expiry_month_; }
+    std::u16string expiry_year() { return expiry_year_; }
+    CreditCardFetchResult result() { return result_; }
+
+   private:
+    // The result of the credit card fetching.
+    CreditCardFetchResult result_ = CreditCardFetchResult::kNone;
+    // The card number returned from OnCreditCardFetched().
+    std::u16string number_;
+    // The returned CVC, if any.
+    std::u16string cvc_;
+    // The two-digit expiration month in string.
+    std::u16string expiry_month_;
+    // The four-digit expiration year in string.
+    std::u16string expiry_year_;
+    base::WeakPtrFactory<TestAccessor> weak_ptr_factory_{this};
+  };
+
+  // The type of request options to be returned with a CVC auth response.
+  enum class TestFidoRequestOptionsType {
+    kValid = 0,
+    kInvalid = 1,
+    kNotPresent = 2
+  };
+
+  CreditCardAccessManagerTestBase();
+  ~CreditCardAccessManagerTestBase() override;
+
+  void SetUp() override;
+
+  bool IsAuthenticationInProgress();
+
+  // Resets all variables related to credit card fetching.
+  void ResetFetchCreditCard();
+
+  void ClearCards();
+
+  void CreateLocalCard(std::string guid, std::string number = std::string());
+
+  CreditCard* CreateServerCard(std::string guid,
+                               std::string number = std::string(),
+                               std::string server_id = std::string());
+
+  CreditCardCvcAuthenticator& GetCvcAuthenticator();
+
+  void MockUserResponseForCvcAuth(std::u16string cvc, bool enable_fido);
+
+  // Returns true if full card request was sent from CVC auth.
+  bool GetRealPanForCVCAuth(
+      payments::PaymentsAutofillClient::PaymentsRpcResult result,
+      const std::string& real_pan,
+      TestFidoRequestOptionsType test_fido_request_options_type =
+          TestFidoRequestOptionsType::kNotPresent);
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  void AddMaxStrikes();
+  void ClearStrikes();
+  int GetStrikes();
+
+  base::Value::Dict GetTestRequestOptions(
+      bool return_invalid_request_options = false);
+  base::Value::Dict GetTestCreationOptions();
+
+  // Returns true if full card request was sent from FIDO auth.
+  bool GetRealPanForFIDOAuth(
+      payments::PaymentsAutofillClient::PaymentsRpcResult result,
+      const std::string& real_pan,
+      const std::string& dcvv = std::string(),
+      bool is_virtual_card = false);
+
+  // Mocks an OptChange response from the PaymentsNetworkInterface.
+  void OptChange(payments::PaymentsAutofillClient::PaymentsRpcResult result,
+                 bool user_is_opted_in,
+                 bool include_creation_options = false,
+                 bool include_request_options = false);
+
+  TestCreditCardFidoAuthenticator* GetFIDOAuthenticator();
+#endif
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+  // Mocks user response for the offer dialog.
+  void AcceptWebauthnOfferDialog(bool did_accept);
+#endif
+
+  void InvokeDelayedGetUnmaskDetailsResponse();
+  void InvokeUnmaskDetailsTimeout();
+  void WaitForCallbacks();
+
+  void SetCreditCardFIDOAuthEnabled(bool enabled);
+  bool IsCreditCardFIDOAuthEnabled();
+
+  UnmaskAuthFlowType GetUnmaskAuthFlowType();
+
+  void MockCardUnmaskFlowUpToAuthenticationSelectionDialogAccepted(
+      bool fido_authenticator_is_user_opted_in,
+      bool is_user_verifiable,
+      const std::vector<CardUnmaskChallengeOption>& challenge_options,
+      int selected_index);
+
+  void VerifyOnSelectChallengeOptionInvoked();
+
+ protected:
+  CreditCardAccessManager& credit_card_access_manager();
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  TestCreditCardFidoAuthenticator& fido_authenticator();
+#endif
+  payments::TestPaymentsNetworkInterface& payments_network_interface();
+  TestPersonalDataManager& personal_data();
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+  void OptUserInToFido();
+#endif
+
+  std::unique_ptr<TestAccessor> accessor_;
+  base::test::TaskEnvironment task_environment_;
+  variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
+      variations::VariationsIdsProvider::Mode::kUseSignedInState};
+  syncer::TestSyncService sync_service_;
+  TestAutofillClient autofill_client_;
+  std::unique_ptr<TestAutofillDriver> autofill_driver_;
+  raw_ptr<TestCreditCardOtpAuthenticator> otp_authenticator_;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_ACCESS_MANAGER_TEST_BASE_H_
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index 1a0b8a3..6e27a631 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -13,14 +13,9 @@
 
 #include "base/base64.h"
 #include "base/functional/bind.h"
-#include "base/memory/raw_ptr.h"
-#include "base/metrics/field_trial.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
@@ -32,35 +27,24 @@
 #include "components/autofill/core/browser/payments/autofill_error_dialog_context.h"
 #include "components/autofill/core/browser/payments/card_unmask_challenge_option.h"
 #include "components/autofill/core/browser/payments/credit_card_access_manager_test_api.h"
+#include "components/autofill/core/browser/payments/credit_card_access_manager_test_base.h"
 #include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
 #include "components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h"
 #include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
 #include "components/autofill/core/browser/payments/payments_autofill_client.h"
 #include "components/autofill/core/browser/payments/test/mock_payments_window_manager.h"
 #include "components/autofill/core/browser/payments/test/test_credit_card_otp_authenticator.h"
-#include "components/autofill/core/browser/payments/test_payments_autofill_client.h"
-#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/payments_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
-#include "components/autofill/core/browser/test_browser_autofill_manager.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
 #include "components/autofill/core/common/autofill_prefs.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/sync/test/test_sync_service.h"
-#include "components/variations/scoped_variations_ids_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/l10n/l10n_util.h"
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
 #include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h"
-#include "components/autofill/core/browser/payments/test_internal_authenticator.h"
 #include "components/autofill/core/browser/strike_databases/payments/fido_authentication_strike_database.h"
-#include "content/public/test/mock_navigation_handle.h"
 #endif
 
 #if BUILDFLAG(IS_ANDROID)
@@ -77,561 +61,25 @@
     payments::PaymentsAutofillClient::PaymentsRpcCardType;
 using PaymentsRpcResult = payments::PaymentsAutofillClient::PaymentsRpcResult;
 
-constexpr char kTestGUID[] = "00000000-0000-0000-0000-000000000001";
-constexpr char kTestGUID2[] = "00000000-0000-0000-0000-000000000002";
-constexpr char kTestNumber[] = "4234567890123456";  // Visa
-constexpr char kTestNumber2[] = "5454545454545454";
-constexpr char16_t kTestNumber16[] = u"4234567890123456";
-constexpr char16_t kTestCvc16[] = u"123";
-constexpr char kTestServerId[] = "server_id_1";
-constexpr char kTestServerId2[] = "server_id_2";
-
 using autofill_metrics::CreditCardFormEventLogger;
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-constexpr char kTestCvc[] = "123";
-// Base64 encoding of "This is a test challenge".
-constexpr char kTestChallenge[] = "VGhpcyBpcyBhIHRlc3QgY2hhbGxlbmdl";
-// Base64 encoding of "This is a test Credential ID".
-constexpr char kCredentialId[] = "VGhpcyBpcyBhIHRlc3QgQ3JlZGVudGlhbCBJRC4=";
-constexpr char kGooglePaymentsRpid[] = "google.com";
-
 std::string BytesToBase64(const std::vector<uint8_t>& bytes) {
   return base::Base64Encode(bytes);
 }
 #endif
 
-// Implements an `OnCreditCardFetched()` callback that stores the values it
-// receives.
-class TestAccessor {
- public:
-  TestAccessor() = default;
-
-  base::WeakPtr<TestAccessor> GetWeakPtr() {
-    return weak_ptr_factory_.GetWeakPtr();
-  }
-
-  void OnCreditCardFetched(CreditCardFetchResult result,
-                           const CreditCard* card) {
-    result_ = result;
-    if (result == CreditCardFetchResult::kSuccess) {
-      DCHECK(card);
-      number_ = card->number();
-      cvc_ = card->cvc();
-      expiry_month_ = card->Expiration2DigitMonthAsString();
-      expiry_year_ = card->Expiration4DigitYearAsString();
-    }
-  }
-
-  std::u16string number() { return number_; }
-  std::u16string cvc() { return cvc_; }
-  std::u16string expiry_month() { return expiry_month_; }
-  std::u16string expiry_year() { return expiry_year_; }
-  CreditCardFetchResult result() { return result_; }
-
- private:
-  // The result of the credit card fetching.
-  CreditCardFetchResult result_ = CreditCardFetchResult::kNone;
-  // The card number returned from OnCreditCardFetched().
-  std::u16string number_;
-  // The returned CVC, if any.
-  std::u16string cvc_;
-  // The two-digit expiration month in string.
-  std::u16string expiry_month_;
-  // The four-digit expiration year in string.
-  std::u16string expiry_year_;
-  base::WeakPtrFactory<TestAccessor> weak_ptr_factory_{this};
-};
-
 }  // namespace
 // The anonymous namespace needs to end here because of `friend`ships between
 // the tests and the production code.
 
-class CreditCardAccessManagerTest : public testing::Test {
- public:
-  // The type of request options to be returned with a CVC auth response.
-  enum class TestFidoRequestOptionsType {
-    kValid = 0,
-    kInvalid = 1,
-    kNotPresent = 2
-  };
-
-  CreditCardAccessManagerTest()
-      : task_environment_(
-            base::test::TaskEnvironment::TimeSource::MOCK_TIME,
-            base::test::TaskEnvironment::MainThreadType::DEFAULT,
-            base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {
-    // Advance the mock clock to 2021-01-01, 00:00:00.000.
-    base::Time year_2021;
-    CHECK(base::Time::FromUTCExploded({.year = 2021,
-                                       .month = 1,
-                                       .day_of_week = 4,
-                                       .day_of_month = 1,
-                                       .hour = 0,
-                                       .minute = 0,
-                                       .second = 0,
-                                       .millisecond = 0},
-                                      &year_2021));
-    task_environment_.AdvanceClock(year_2021 -
-                                   task_environment_.GetMockClock()->Now());
-  }
-
-  void SetUp() override {
-    autofill_client_.SetPrefs(test::PrefServiceForTesting());
-    personal_data().SetPrefService(autofill_client_.GetPrefs());
-    personal_data().SetSyncServiceForTest(&sync_service_);
-#if BUILDFLAG(IS_IOS)
-    // On iOS mandatory reauth is by default enabled. Disable it explicitly
-    // to not interfere with tests that do not test reauth functionalities.
-    autofill_client_.GetPrefs()->SetBoolean(
-        prefs::kAutofillPaymentMethodsMandatoryReauth, false);
-#endif
-    accessor_ = std::make_unique<TestAccessor>();
-    autofill_driver_ = std::make_unique<TestAutofillDriver>(&autofill_client_);
-
-    autofill_client_.GetPaymentsAutofillClient()
-        ->set_test_payments_network_interface(
-            std::make_unique<payments::TestPaymentsNetworkInterface>(
-                autofill_client_.GetURLLoaderFactory(),
-                autofill_client_.GetIdentityManager(), &personal_data()));
-    autofill_client_.set_test_strike_database(
-        std::make_unique<TestStrikeDatabase>());
-    autofill_driver_->set_autofill_manager(
-        std::make_unique<TestBrowserAutofillManager>(autofill_driver_.get()));
-
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-    autofill_driver_->SetAuthenticator(new TestInternalAuthenticator());
-    test_api(credit_card_access_manager())
-        .set_fido_authenticator(
-            std::make_unique<TestCreditCardFidoAuthenticator>(
-                autofill_driver_.get(), &autofill_client_));
-#endif
-    auto otp_authenticator =
-        std::make_unique<TestCreditCardOtpAuthenticator>(&autofill_client_);
-    otp_authenticator_ = otp_authenticator.get();
-    autofill_client_.GetPaymentsAutofillClient()->set_otp_authenticator(
-        std::move(otp_authenticator));
-
-    // Force creation of the CreditCardAccessManager.
-    std::ignore = credit_card_access_manager();
-  }
-
-  bool IsAuthenticationInProgress() {
-    return test_api(credit_card_access_manager())
-        .is_authentication_in_progress();
-  }
-
-  void ResetFetchCreditCard() {
-    // Resets all variables related to credit card fetching.
-    test_api(credit_card_access_manager())
-        .set_is_authentication_in_progress(false);
-    test_api(credit_card_access_manager()).set_can_fetch_unmask_details(true);
-    test_api(credit_card_access_manager())
-        .set_unmask_details_request_in_progress(false);
-    test_api(credit_card_access_manager()).set_is_user_verifiable(std::nullopt);
-  }
-
-  void ClearCards() {
-    personal_data().test_payments_data_manager().ClearCreditCards();
-  }
-
-  void CreateLocalCard(std::string guid, std::string number = std::string()) {
-    CreditCard local_card = CreditCard();
-    test::SetCreditCardInfo(&local_card, "Elvis Presley", number.c_str(),
-                            test::NextMonth().c_str(), test::NextYear().c_str(),
-                            "1", kTestCvc16);
-    local_card.set_guid(guid);
-    local_card.set_record_type(CreditCard::RecordType::kLocalCard);
-
-    personal_data().payments_data_manager().AddCreditCard(local_card);
-  }
-
-  CreditCard* CreateServerCard(std::string guid,
-                               std::string number = std::string(),
-                               std::string server_id = std::string()) {
-    CreditCard server_card = CreditCard();
-    test::SetCreditCardInfo(&server_card, "Elvis Presley", number.c_str(),
-                            test::NextMonth().c_str(), test::NextYear().c_str(),
-                            "1", kTestCvc16);
-    server_card.set_guid(guid);
-    server_card.set_record_type(CreditCard::RecordType::kMaskedServerCard);
-    server_card.set_server_id(server_id);
-    personal_data().test_payments_data_manager().AddServerCreditCard(
-        server_card);
-    return personal_data().payments_data_manager().GetCreditCardByGUID(guid);
-  }
-
-  CreditCardCvcAuthenticator& GetCvcAuthenticator() {
-    return autofill_client_.GetPaymentsAutofillClient()->GetCvcAuthenticator();
-  }
-
-  void MockUserResponseForCvcAuth(std::u16string cvc, bool enable_fido) {
-    payments::FullCardRequest* full_card_request =
-        GetCvcAuthenticator().full_card_request_.get();
-    if (!full_card_request)
-      return;
-
-    // Mock user response.
-    payments::FullCardRequest::UserProvidedUnmaskDetails details;
-    details.cvc = cvc;
-#if BUILDFLAG(IS_ANDROID)
-    details.enable_fido_auth = enable_fido;
-#endif
-    full_card_request->OnUnmaskPromptAccepted(details);
-    full_card_request->OnDidGetUnmaskRiskData(/*risk_data=*/"");
-  }
-
-  // Returns true if full card request was sent from CVC auth.
-  bool GetRealPanForCVCAuth(
-      PaymentsRpcResult result,
-      const std::string& real_pan,
-      TestFidoRequestOptionsType test_fido_request_options_type =
-          TestFidoRequestOptionsType::kNotPresent) {
-    payments::FullCardRequest* full_card_request =
-        GetCvcAuthenticator().full_card_request_.get();
-
-    if (!full_card_request)
-      return false;
-
-    MockUserResponseForCvcAuth(kTestCvc16,
-                               /*enable_fido=*/test_fido_request_options_type !=
-                                   TestFidoRequestOptionsType::kNotPresent);
-
-    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-    response.card_authorization_token = "dummy_card_authorization_token";
-    if (test_fido_request_options_type == TestFidoRequestOptionsType::kValid) {
-      response.fido_request_options = GetTestRequestOptions();
-    } else if (test_fido_request_options_type ==
-               TestFidoRequestOptionsType::kInvalid) {
-      response.fido_request_options =
-          GetTestRequestOptions(/*return_invalid_request_options=*/true);
-    }
-#endif
-    response.card_type = PaymentsRpcCardType::kServerCard;
-    full_card_request->OnDidGetRealPan(result,
-                                       response.with_real_pan(real_pan));
-    return true;
-  }
-
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-  void AddMaxStrikes() {
-    auto* strike_database =
-        GetFIDOAuthenticator()->GetOrCreateFidoAuthenticationStrikeDatabase();
-    CHECK(strike_database);
-    strike_database->AddStrikes(strike_database->GetMaxStrikesLimit());
-  }
-
-  void ClearStrikes() {
-    auto* strike_database =
-        GetFIDOAuthenticator()->GetOrCreateFidoAuthenticationStrikeDatabase();
-    CHECK(strike_database);
-    strike_database->ClearAllStrikes();
-  }
-
-  int GetStrikes() {
-    auto* strike_database =
-        GetFIDOAuthenticator()->GetOrCreateFidoAuthenticationStrikeDatabase();
-    CHECK(strike_database);
-    return strike_database->GetStrikes();
-  }
-
-  base::Value::Dict GetTestRequestOptions(
-      bool return_invalid_request_options = false) {
-    base::Value::Dict request_options;
-    request_options.Set("challenge", base::Value(kTestChallenge));
-    request_options.Set("relying_party_id", base::Value(kGooglePaymentsRpid));
-
-    // If invalid request options are to be returned, don't set key info or
-    // credential ID.
-    if (return_invalid_request_options) {
-      return request_options;
-    }
-
-    base::Value::Dict key_info;
-    key_info.Set("credential_id", base::Value(kCredentialId));
-    request_options.Set("key_info", base::Value(base::Value::Type::LIST));
-    request_options.FindList("key_info")->Append(std::move(key_info));
-    return request_options;
-  }
-
-  base::Value::Dict GetTestCreationOptions() {
-    base::Value::Dict creation_options;
-    creation_options.Set("challenge", base::Value(kTestChallenge));
-    creation_options.Set("relying_party_id", base::Value(kGooglePaymentsRpid));
-    return creation_options;
-  }
-
-  // Returns true if full card request was sent from FIDO auth.
-  bool GetRealPanForFIDOAuth(PaymentsRpcResult result,
-                             const std::string& real_pan,
-                             const std::string& dcvv = std::string(),
-                             bool is_virtual_card = false) {
-    payments::FullCardRequest* full_card_request =
-        GetFIDOAuthenticator()->full_card_request_.get();
-
-    if (!full_card_request)
-      return false;
-
-    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
-    response.card_type = is_virtual_card ? PaymentsRpcCardType::kVirtualCard
-                                         : PaymentsRpcCardType::kServerCard;
-    full_card_request->OnDidGetRealPan(
-        result, response.with_real_pan(real_pan).with_dcvv(dcvv));
-    return true;
-  }
-
-  // Mocks an OptChange response from the PaymentsNetworkInterface.
-  void OptChange(PaymentsRpcResult result,
-                 bool user_is_opted_in,
-                 bool include_creation_options = false,
-                 bool include_request_options = false) {
-    payments::PaymentsNetworkInterface::OptChangeResponseDetails response;
-    response.user_is_opted_in = user_is_opted_in;
-    if (include_creation_options) {
-      response.fido_creation_options = GetTestCreationOptions();
-    }
-    if (include_request_options) {
-      response.fido_request_options = GetTestRequestOptions();
-    }
-    GetFIDOAuthenticator()->OnDidGetOptChangeResult(result, response);
-  }
-
-  TestCreditCardFidoAuthenticator* GetFIDOAuthenticator() {
-    return static_cast<TestCreditCardFidoAuthenticator*>(
-        credit_card_access_manager().GetOrCreateFidoAuthenticator());
-  }
-#endif
-
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-  // Mocks user response for the offer dialog.
-  void AcceptWebauthnOfferDialog(bool did_accept) {
-    GetFIDOAuthenticator()->OnWebauthnOfferDialogUserResponse(did_accept);
-  }
-#endif
-
-  void InvokeDelayedGetUnmaskDetailsResponse() {
-    test_api(credit_card_access_manager())
-        .OnDidGetUnmaskDetails(PaymentsRpcResult::kSuccess,
-                               *payments_network_interface().unmask_details());
-  }
-
-  void InvokeUnmaskDetailsTimeout() {
-    test_api(credit_card_access_manager())
-        .ready_to_start_authentication()
-        .Signal();
-    test_api(credit_card_access_manager()).set_can_fetch_unmask_details(true);
-  }
-
-  void WaitForCallbacks() { task_environment_.RunUntilIdle(); }
-
-  void SetCreditCardFIDOAuthEnabled(bool enabled) {
-    prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), enabled);
-  }
-
-  bool IsCreditCardFIDOAuthEnabled() {
-    return prefs::IsCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs());
-  }
-
-  UnmaskAuthFlowType GetUnmaskAuthFlowType() {
-    return test_api(credit_card_access_manager()).unmask_auth_flow_type();
-  }
-
-  void MockCardUnmaskFlowUpToAuthenticationSelectionDialogAccepted(
-      bool fido_authenticator_is_user_opted_in,
-      bool is_user_verifiable,
-      const std::vector<CardUnmaskChallengeOption>& challenge_options,
-      int selected_index) {
-    CreateServerCard(kTestGUID, kTestNumber, kTestServerId);
-    CreditCard* virtual_card =
-        personal_data().payments_data_manager().GetCreditCardByGUID(kTestGUID);
-    virtual_card->set_record_type(CreditCard::RecordType::kVirtualCard);
-
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-    fido_authenticator().set_is_user_opted_in(
-        fido_authenticator_is_user_opted_in);
-#endif
-
-    // TODO(crbug.com/40197696): Switch to SetUserVerifiable after moving all
-    // |is_user_verifiable_| related logic from CreditCardAccessManager to
-    // CreditCardFidoAuthenticator.
-    test_api(credit_card_access_manager())
-        .set_is_user_verifiable(is_user_verifiable);
-    credit_card_access_manager().FetchCreditCard(
-        virtual_card, base::BindOnce(&TestAccessor::OnCreditCardFetched,
-                                     accessor_->GetWeakPtr()));
-
-    // This checks risk-based authentication flow is successfully invoked,
-    // because it is always the very first authentication flow in a VCN
-    // unmasking flow.
-    EXPECT_TRUE(autofill_client_.GetPaymentsAutofillClient()
-                    ->risk_based_authentication_invoked());
-    // Mock server response with information regarding VCN auth.
-    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
-    response.context_token = "fake_context_token";
-    response.card_unmask_challenge_options = challenge_options;
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-    if (fido_authenticator_is_user_opted_in)
-      response.fido_request_options = GetTestRequestOptions();
-#endif
-    credit_card_access_manager()
-        .OnVirtualCardRiskBasedAuthenticationResponseReceived(
-            PaymentsRpcResult::kSuccess, response);
-
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-    // This if-statement ensures that fido-related flows run correctly.
-    if (fido_authenticator_is_user_opted_in) {
-      // Expect the CreditCardAccessManager invokes the FIDO authenticator
-      // first.
-      ASSERT_TRUE(fido_authenticator().authenticate_invoked());
-      EXPECT_EQ(fido_authenticator().card().number(),
-                base::UTF8ToUTF16(std::string(kTestNumber)));
-      EXPECT_EQ(fido_authenticator().card().record_type(),
-                CreditCard::RecordType::kVirtualCard);
-      ASSERT_TRUE(fido_authenticator().context_token().has_value());
-      EXPECT_EQ(fido_authenticator().context_token().value(),
-                "fake_context_token");
-
-      CreditCardFidoAuthenticator::FidoAuthenticationResponse fido_response{
-          .did_succeed = false};
-      test_api(credit_card_access_manager())
-          .OnFIDOAuthenticationComplete(fido_response);
-    }
-#endif
-
-    const CardUnmaskChallengeOption& challenge_option =
-        response.card_unmask_challenge_options[selected_index];
-
-    payments::PaymentsWindowManager::Vcn3dsContext vcn_3ds_context;
-    if (challenge_option.type ==
-        CardUnmaskChallengeOptionType::kThreeDomainSecure) {
-      EXPECT_CALL(*static_cast<payments::MockPaymentsWindowManager*>(
-                      autofill_client_.GetPaymentsAutofillClient()
-                          ->GetPaymentsWindowManager()),
-                  InitVcn3dsAuthentication)
-          .Times(1)
-          .WillOnce(
-              [&vcn_3ds_context](
-                  payments::PaymentsWindowManager::Vcn3dsContext context) {
-                vcn_3ds_context = std::move(context);
-              });
-    }
-
-    test_api(credit_card_access_manager())
-        .OnUserAcceptedAuthenticationSelectionDialog(
-            challenge_option.id.value());
-
-    // TODO(crbug.com/329523854): Check that the challenge selection acceptance
-    // was handled correctly using mocks instead of test classes.
-    switch (challenge_option.type) {
-      case CardUnmaskChallengeOptionType::kCvc: {
-        CreditCardCvcAuthenticator& cvc_authenticator =
-            autofill_client_.GetPaymentsAutofillClient()->GetCvcAuthenticator();
-        payments::PaymentsNetworkInterface::UnmaskRequestDetails*
-            request_details =
-                cvc_authenticator.GetFullCardRequest()->request_.get();
-        EXPECT_EQ(request_details->card.record_type(),
-                  CreditCard::RecordType::kVirtualCard);
-        EXPECT_EQ(request_details->card.number(),
-                  base::UTF8ToUTF16(std::string(kTestNumber)));
-        EXPECT_EQ(request_details->context_token, "fake_context_token");
-        EXPECT_EQ(request_details->selected_challenge_option->id.value(),
-                  "234");
-        EXPECT_EQ(request_details->selected_challenge_option->type,
-                  CardUnmaskChallengeOptionType::kCvc);
-        break;
-      }
-      case CardUnmaskChallengeOptionType::kSmsOtp:
-        VerifyOnSelectChallengeOptionInvoked();
-        EXPECT_EQ(otp_authenticator_->selected_challenge_option().id.value(),
-                  "123");
-        EXPECT_EQ(otp_authenticator_->selected_challenge_option().type,
-                  CardUnmaskChallengeOptionType::kSmsOtp);
-        EXPECT_EQ(
-            otp_authenticator_->selected_challenge_option().challenge_info,
-            u"xxx-xxx-3547");
-        break;
-      case CardUnmaskChallengeOptionType::kEmailOtp:
-        VerifyOnSelectChallengeOptionInvoked();
-        EXPECT_EQ(otp_authenticator_->selected_challenge_option().id.value(),
-                  "345");
-        EXPECT_EQ(otp_authenticator_->selected_challenge_option().type,
-                  CardUnmaskChallengeOptionType::kEmailOtp);
-        EXPECT_EQ(
-            otp_authenticator_->selected_challenge_option().challenge_info,
-            u"a******b@google.com");
-        break;
-      case CardUnmaskChallengeOptionType::kThreeDomainSecure:
-        EXPECT_EQ(vcn_3ds_context.context_token, response.context_token);
-        EXPECT_EQ(vcn_3ds_context.card, *virtual_card);
-        EXPECT_EQ(vcn_3ds_context.challenge_option.type,
-                  CardUnmaskChallengeOptionType::kThreeDomainSecure);
-        EXPECT_TRUE(vcn_3ds_context.user_consent_already_given);
-        break;
-      case CardUnmaskChallengeOptionType::kUnknownType:
-        NOTREACHED_IN_MIGRATION();
-        break;
-    }
-  }
-
-  void VerifyOnSelectChallengeOptionInvoked() {
-    DCHECK(otp_authenticator_);
-    EXPECT_TRUE(otp_authenticator_->on_challenge_option_selected_invoked());
-    EXPECT_EQ(otp_authenticator_->card().number(),
-              base::UTF8ToUTF16(std::string(kTestNumber)));
-    EXPECT_EQ(otp_authenticator_->card().record_type(),
-              CreditCard::RecordType::kVirtualCard);
-    EXPECT_EQ(otp_authenticator_->context_token(), "fake_context_token");
-  }
-
- protected:
-  CreditCardAccessManager& credit_card_access_manager() {
-    return static_cast<BrowserAutofillManager&>(
-               autofill_driver_->GetAutofillManager())
-        .GetCreditCardAccessManager();
-  }
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-  TestCreditCardFidoAuthenticator& fido_authenticator() {
-    return static_cast<TestCreditCardFidoAuthenticator&>(
-        *credit_card_access_manager().GetOrCreateFidoAuthenticator());
-  }
-#endif
-  payments::TestPaymentsNetworkInterface& payments_network_interface() {
-    return *autofill_client_.GetPaymentsAutofillClient()
-                ->GetPaymentsNetworkInterface();
-  }
-  TestPersonalDataManager& personal_data() {
-    return *autofill_client_.GetPersonalDataManager();
-  }
-
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
-  void OptUserInToFido() {
-    std::string other_server_id = "00000000-0000-0000-0000-000000000034";
-    // Add a random FIDO eligible card, it will return RequestOptions in unmask
-    // details.
-    payments_network_interface().AddFidoEligibleCard(
-        other_server_id, kCredentialId, kGooglePaymentsRpid);
-    GetFIDOAuthenticator()->SetUserVerifiable(true);
-    SetCreditCardFIDOAuthEnabled(true);
-  }
-#endif
-
-  std::unique_ptr<TestAccessor> accessor_;
-  base::test::TaskEnvironment task_environment_;
-  variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
-      variations::VariationsIdsProvider::Mode::kUseSignedInState};
-  syncer::TestSyncService sync_service_;
-  TestAutofillClient autofill_client_;
-  std::unique_ptr<TestAutofillDriver> autofill_driver_;
-  scoped_refptr<AutofillWebDataService> database_;
-  raw_ptr<TestCreditCardOtpAuthenticator> otp_authenticator_;
-};
+using CreditCardAccessManagerTest = CreditCardAccessManagerTestBase;
 
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || \
     BUILDFLAG(IS_IOS)
 
 class CreditCardAccessManagerMandatoryReauthTest
-    : public CreditCardAccessManagerTest {
+    : public CreditCardAccessManagerTestBase {
  public:
   CreditCardAccessManagerMandatoryReauthTest() = default;
   ~CreditCardAccessManagerMandatoryReauthTest() override = default;
@@ -1313,7 +761,7 @@
 // -- bool has_server_card;
 // -- bool is_user_opted_in;
 class CreditCardAccessManagerBetterAuthLogTest
-    : public CreditCardAccessManagerTest,
+    : public CreditCardAccessManagerTestBase,
       public testing::WithParamInterface<std::tuple<bool, bool>> {
  public:
   CreditCardAccessManagerBetterAuthLogTest() = default;
@@ -2629,7 +2077,7 @@
 // -- bool has_opted_in_from_android_settings;
 // -- bool is_opted_in_for_fido;
 class CreditCardAccessManagerBetterAuthOptInLogTest
-    : public CreditCardAccessManagerTest,
+    : public CreditCardAccessManagerTestBase,
       public testing::WithParamInterface<
           std::tuple<bool, bool, bool, bool, bool, bool>> {
  public:
@@ -3147,7 +2595,7 @@
 }
 
 class CreditCardAccessManagerRiskBasedMaskedServerCardUnmaskingTest
-    : public CreditCardAccessManagerTest {
+    : public CreditCardAccessManagerTestBase {
  public:
   CreditCardAccessManagerRiskBasedMaskedServerCardUnmaskingTest() = default;
   ~CreditCardAccessManagerRiskBasedMaskedServerCardUnmaskingTest() override =
diff --git a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
index c0ab259..f5d7c56 100644
--- a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
+++ b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
@@ -129,7 +129,7 @@
   friend class BrowserAutofillManagerTest;
   friend class AutofillMetricsTest;
   friend class autofill_metrics::AutofillMetricsBaseTest;
-  friend class CreditCardAccessManagerTest;
+  friend class CreditCardAccessManagerTestBase;
   friend class CreditCardCvcAuthenticatorTest;
   friend class FormFillerTest;
 
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator.h b/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
index 0b23bd4..be55dd03 100644
--- a/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
+++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
@@ -158,7 +158,7 @@
 
  private:
   friend class BrowserAutofillManagerTest;
-  friend class CreditCardAccessManagerTest;
+  friend class CreditCardAccessManagerTestBase;
   friend class CreditCardFidoAuthenticatorTest;
   friend class TestCreditCardFidoAuthenticator;
   FRIEND_TEST_ALL_PREFIXES(CreditCardFidoAuthenticatorTest,
diff --git a/components/autofill/core/browser/payments/full_card_request.h b/components/autofill/core/browser/payments/full_card_request.h
index bf788ea..b5ae0c5 100644
--- a/components/autofill/core/browser/payments/full_card_request.h
+++ b/components/autofill/core/browser/payments/full_card_request.h
@@ -25,7 +25,7 @@
 class AutofillMetricsTest;
 class BrowserAutofillManagerTest;
 class CreditCard;
-class CreditCardAccessManagerTest;
+class CreditCardAccessManagerTestBase;
 class CreditCardCvcAuthenticatorTest;
 class FormFillerTest;
 class PersonalDataManager;
@@ -197,7 +197,7 @@
   friend class autofill::BrowserAutofillManagerTest;
   friend class autofill::AutofillMetricsTest;
   friend class autofill::autofill_metrics::AutofillMetricsBaseTest;
-  friend class autofill::CreditCardAccessManagerTest;
+  friend class autofill::CreditCardAccessManagerTestBase;
   friend class autofill::CreditCardCvcAuthenticatorTest;
   friend class autofill::FormFillerTest;
 
diff --git a/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h b/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h
index 5e6e29c2..35423986 100644
--- a/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h
+++ b/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h
@@ -74,7 +74,7 @@
 
  private:
   friend class BrowserAutofillManagerTest;
-  friend class CreditCardAccessManagerTest;
+  friend class CreditCardAccessManagerTestBase;
 
   blink::mojom::PublicKeyCredentialRequestOptionsPtr request_options_;
   blink::mojom::PublicKeyCredentialCreationOptionsPtr creation_options_;
diff --git a/components/autofill/core/browser/payments_suggestion_generator.cc b/components/autofill/core/browser/payments_suggestion_generator.cc
index 627f0e8..f4b7191 100644
--- a/components/autofill/core/browser/payments_suggestion_generator.cc
+++ b/components/autofill/core/browser/payments_suggestion_generator.cc
@@ -404,7 +404,6 @@
       client.GetPersonalDataManager()->payments_data_manager().app_locale()));
 }
 
-#if !BUILDFLAG(IS_ANDROID)
 Suggestion::Text GetBenefitTextWithTermsAppended(
     const std::u16string& benefit_text) {
   return Suggestion::Text(l10n_util::GetStringFUTF16(
@@ -427,7 +426,6 @@
              : std::optional<Suggestion::Text>(
                    GetBenefitTextWithTermsAppended(benefit_description));
 }
-#endif  // !BUILDFLAG(IS_ANDROID)
 
 // Set the labels to be shown in the suggestion. Note that this does not
 // account for virtual cards or card-linked offers.
@@ -1136,6 +1134,15 @@
         credit_card.CardNameForAutofillDisplay(nickname);
     suggestion.minor_text.value =
         credit_card.ObfuscatedNumberWithVisibleLastFourDigits();
+    std::optional<Suggestion::Text> benefit_label =
+        GetCreditCardBenefitSuggestionLabel(credit_card, client);
+    // TODO(b/364660068): Check if card benefits eligibility can be added while
+    // retrieving the benefits label.
+    if (benefit_label && client.GetPersonalDataManager()
+                             ->payments_data_manager()
+                             .IsCardEligibleForBenefits(credit_card)) {
+      suggestion.labels.push_back({*benefit_label});
+    }
     if (credit_card.record_type() == CreditCard::RecordType::kVirtualCard) {
       suggestion.apply_deactivated_style = !IsCardSuggestionAcceptable(
           credit_card, client, /*is_manual_fallback= */ false);
diff --git a/components/autofill/core/browser/payments_suggestion_generator_unittest.cc b/components/autofill/core/browser/payments_suggestion_generator_unittest.cc
index 1e14e84..5b55f78 100644
--- a/components/autofill/core/browser/payments_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/payments_suggestion_generator_unittest.cc
@@ -541,6 +541,105 @@
               CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, /*app_locale=*/"en-US"))}));
 }
 
+TEST_P(AutofillCreditCardBenefitsLabelTest,
+       GetCreditCardSuggestionsForTouchToFill_BenefitsAdded_RealCard) {
+  std::vector<CreditCard> cards = {card()};
+  base::span<const CreditCard> credit_cards_span(cards);
+
+  std::vector<Suggestion> suggestions = GetCreditCardSuggestionsForTouchToFill(
+      credit_cards_span, *autofill_client());
+
+  EXPECT_THAT(suggestions[0],
+              EqualLabels({{expected_benefit_text()},
+                           {card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+                                           app_locale())}}));
+}
+
+TEST_P(AutofillCreditCardBenefitsLabelTest,
+       GetCreditCardSuggestionsForTouchToFill_BenefitsAdded_VirtualCard) {
+  CreditCard virtual_card = CreditCard::CreateVirtualCard(card());
+  std::vector<CreditCard> cards = {virtual_card};
+  base::span<const CreditCard> credit_cards_span(cards);
+
+  std::vector<Suggestion> suggestions = GetCreditCardSuggestionsForTouchToFill(
+      credit_cards_span, *autofill_client());
+
+  EXPECT_THAT(
+      suggestions[0],
+      EqualLabels({{expected_benefit_text()},
+                   {l10n_util::GetStringUTF16(
+                       IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE)}}));
+}
+
+// Checks that the merchant benefit description is not displayed for suggestions
+// where the webpage's URL is different from the benefit's applicable URL.
+TEST_P(
+    AutofillCreditCardBenefitsLabelTest,
+    GetCreditCardSuggestionsForTouchToFill_BenefitsNotAdded_NonApplicableUrl) {
+  if (!absl::holds_alternative<CreditCardMerchantBenefit>(GetBenefit())) {
+    GTEST_SKIP() << "This test should not run for non-merchant benefits.";
+  }
+  autofill_client()->set_last_committed_primary_main_frame_url(
+      GURL("https://random-url.com"));
+  std::vector<CreditCard> cards = {card()};
+  base::span<const CreditCard> credit_cards_span(cards);
+
+  std::vector<Suggestion> suggestions = GetCreditCardSuggestionsForTouchToFill(
+      credit_cards_span, *autofill_client());
+
+  // Merchant benefit description is not returned.
+  EXPECT_THAT(suggestions[0],
+              EqualLabels({{card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+                                           app_locale())}}));
+}
+
+// Checks that the category benefit description is not displayed for suggestions
+// where the webpage's category in the optimization guide is different from the
+// benefit's applicable category.
+TEST_P(
+    AutofillCreditCardBenefitsLabelTest,
+    GetCreditCardSuggestionsForTouchToFill_BenefitsNotAdded_DifferentCategory) {
+  if (!absl::holds_alternative<CreditCardCategoryBenefit>(GetBenefit())) {
+    GTEST_SKIP() << "This test should not run for non-category benefits.";
+  }
+
+  ON_CALL(*static_cast<MockAutofillOptimizationGuide*>(
+              autofill_client()->GetAutofillOptimizationGuide()),
+          AttemptToGetEligibleCreditCardBenefitCategory)
+      .WillByDefault(testing::Return(
+          CreditCardCategoryBenefit::BenefitCategory::kUnknownBenefitCategory));
+  std::vector<CreditCard> cards = {card()};
+  base::span<const CreditCard> credit_cards_span(cards);
+
+  std::vector<Suggestion> suggestions = GetCreditCardSuggestionsForTouchToFill(
+      credit_cards_span, *autofill_client());
+
+  // Category benefit description is not returned.
+  EXPECT_THAT(suggestions[0],
+              EqualLabels({{card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+                                           app_locale())}}));
+}
+
+// Checks that the benefit description is not displayed when benefit suggestions
+// are disabled for the given card and url.
+TEST_P(AutofillCreditCardBenefitsLabelTest,
+       GetCreditCardSuggestionsForTouchToFill_BenefitsNotAdded_BlockedUrl) {
+  ON_CALL(*static_cast<MockAutofillOptimizationGuide*>(
+              autofill_client()->GetAutofillOptimizationGuide()),
+          ShouldBlockBenefitSuggestionLabelsForCardAndUrl)
+      .WillByDefault(testing::Return(true));
+  std::vector<CreditCard> cards = {card()};
+  base::span<const CreditCard> credit_cards_span(cards);
+
+  std::vector<Suggestion> suggestions = GetCreditCardSuggestionsForTouchToFill(
+      credit_cards_span, *autofill_client());
+
+  // Benefit description is not returned.
+  EXPECT_THAT(suggestions[0],
+              EqualLabels({{card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+                                           app_locale())}}));
+}
+
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 
 // Tests the scenario when:
diff --git a/components/browser_sync/BUILD.gn b/components/browser_sync/BUILD.gn
index 7e4e5fb..53b694f 100644
--- a/components/browser_sync/BUILD.gn
+++ b/components/browser_sync/BUILD.gn
@@ -51,6 +51,8 @@
     "//components/prefs",
     "//components/reading_list/core",
     "//components/reading_list/features:flags",
+    "//components/saved_tab_groups:core",
+    "//components/saved_tab_groups:model",
     "//components/search_engines",
     "//components/send_tab_to_self",
     "//components/sharing_message",
diff --git a/components/browser_sync/DEPS b/components/browser_sync/DEPS
index 11c5892a..f2222773 100644
--- a/components/browser_sync/DEPS
+++ b/components/browser_sync/DEPS
@@ -17,6 +17,7 @@
   "+components/prefs",
   "+components/reading_list/core",
   "+components/reading_list/features",
+  "+components/saved_tab_groups",
   "+components/search_engines",
   "+components/send_tab_to_self",
   "+components/sharing_message",
diff --git a/components/browser_sync/common_controller_builder.cc b/components/browser_sync/common_controller_builder.cc
index ee92ae4..4bece94 100644
--- a/components/browser_sync/common_controller_builder.cc
+++ b/components/browser_sync/common_controller_builder.cc
@@ -47,6 +47,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/reading_list/core/dual_reading_list_model.h"
 #include "components/reading_list/core/reading_list_local_data_batch_uploader.h"
+#include "components/saved_tab_groups/tab_group_sync_service.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/send_tab_to_self/send_tab_to_self_data_type_controller.h"
 #include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
@@ -313,6 +314,11 @@
 }
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
+void CommonControllerBuilder::SetTabGroupSyncService(
+    tab_groups::TabGroupSyncService* tab_group_sync_service) {
+  tab_group_sync_service_.Set(tab_group_sync_service);
+}
+
 void CommonControllerBuilder::SetTemplateURLService(
     TemplateURLService* template_url_service) {
   template_url_service_.Set(template_url_service);
@@ -633,6 +639,42 @@
                       kLegacyFullSyncModeOnly));
   }
 
+  if (!disabled_types.Has(syncer::SAVED_TAB_GROUP) &&
+      tab_group_sync_service_.value()) {
+    syncer::DataTypeControllerDelegate* delegate =
+        tab_group_sync_service_.value()
+            ->GetSavedTabGroupControllerDelegate()
+            .get();
+
+    controllers.push_back(std::make_unique<syncer::DataTypeController>(
+        syncer::SAVED_TAB_GROUP,
+        /*delegate_for_full_sync_mode=*/
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            delegate),
+        /*delegate_for_transport_mode=*/
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            delegate)));
+  }
+
+  if (!disabled_types.Has(syncer::SHARED_TAB_GROUP_DATA) &&
+      tab_group_sync_service_.value() &&
+      base::FeatureList::IsEnabled(
+          data_sharing::features::kDataSharingFeature)) {
+    syncer::DataTypeControllerDelegate* delegate =
+        tab_group_sync_service_.value()
+            ->GetSharedTabGroupControllerDelegate()
+            .get();
+
+    controllers.push_back(std::make_unique<syncer::DataTypeController>(
+        syncer::SHARED_TAB_GROUP_DATA,
+        /*delegate_for_full_sync_mode=*/
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            delegate),
+        /*delegate_for_transport_mode=*/
+        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
+            delegate)));
+  }
+
   if (!disabled_types.Has(syncer::SHARING_MESSAGE) &&
       sharing_message_bridge_.value()) {
     syncer::DataTypeControllerDelegate* sharing_message_delegate =
diff --git a/components/browser_sync/common_controller_builder.h b/components/browser_sync/common_controller_builder.h
index 52a2835..3c9090d 100644
--- a/components/browser_sync/common_controller_builder.h
+++ b/components/browser_sync/common_controller_builder.h
@@ -103,6 +103,10 @@
 class UserEventService;
 }  // namespace syncer
 
+namespace tab_groups {
+class TabGroupSyncService;
+}  // namespace tab_groups
+
 namespace version_info {
 enum class Channel;
 }  // namespace version_info
@@ -186,6 +190,8 @@
           supervised_user_settings_service);
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
+  void SetTabGroupSyncService(
+      tab_groups::TabGroupSyncService* tab_group_sync_service);
   void SetTemplateURLService(TemplateURLService* template_url_service);
   void SetUserEventService(syncer::UserEventService* user_event_service);
 
@@ -286,6 +292,8 @@
       product_specifications_service_;
   SafeOptional<raw_ptr<data_sharing::DataSharingService>> data_sharing_service_;
   SafeOptional<raw_ptr<SharingMessageBridge>> sharing_message_bridge_;
+  SafeOptional<raw_ptr<tab_groups::TabGroupSyncService>>
+      tab_group_sync_service_;
   SafeOptional<raw_ptr<TemplateURLService>> template_url_service_;
 };
 
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd
index e50d238..15600e82 100644
--- a/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -1164,6 +1164,12 @@
       <message name="IDS_EDUCATIONAL_TIP_TAB_GROUP_DESCRIPTION" desc="Description of the Tab group promo in the educational tip module on NTP.">
         You can group related pages, and your groups save and update across all your devices
       </message>
+      <message name="IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_TITLE" desc="Title of the tab group sync promo in the educational tip module on NTP.">
+        Your tab groups are saved
+      </message>
+      <message name="IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_DESCRIPTION" desc="Description of the Tab group promo in the educational tip module on NTP.">
+        The groups you've created are saved in tab group section and update across your devices
+      </message>
 
       <message name="IDS_GO_TO_OS_SETTINGS" desc="When the user clicks on this text button, Chrome sends them to the device OS Settings. One use is the text button shown below the text 'Get alerts for price drops?', which takes the user to the Android notification settings. Another use is in the primary button of the dialog prompting the user to create a device lock, which takes the user to the Android security settings.">
         Go to Settings
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_DESCRIPTION.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..b7c28c83
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+a1327e1a318c66f83ab989914d3063b0ab9a1f74
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_TITLE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_TITLE.png.sha1
new file mode 100644
index 0000000..b7c28c83
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TAB_GROUP_SYNC_TITLE.png.sha1
@@ -0,0 +1 @@
+a1327e1a318c66f83ab989914d3063b0ab9a1f74
\ No newline at end of file
diff --git a/components/content_relationship_verification/digital_asset_links_handler.cc b/components/content_relationship_verification/digital_asset_links_handler.cc
index 1a7d86b..6a13a59 100644
--- a/components/content_relationship_verification/digital_asset_links_handler.cc
+++ b/components/content_relationship_verification/digital_asset_links_handler.cc
@@ -29,6 +29,39 @@
 // In some cases we get a network change while fetching the digital asset
 // links file. See https://crbug.com/987329.
 const int kNumNetworkRetries = 1;
+// Traffic annotation for requests made by the DigitalAssetLinksHandler
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("digital_asset_links", R"(
+      semantics {
+        sender: "Digital Asset Links Handler"
+        description:
+          "Digital Asset Links APIs allows any caller to check pre declared "
+          "relationships between two assets which can be either web domains "
+          "or native applications. This requests checks for a specific "
+          "relationship declared by a web site with an Android application"
+        trigger:
+          "When the related application makes a claim to have the queried "
+          "relationship with the web domain"
+        data: "None"
+        destination: WEBSITE
+        internal {
+          contacts {
+            owners: "//components/content_relationship_verification/OWNERS"
+          }
+        }
+        user_data {
+          type: NONE
+        }
+        last_reviewed: "2024-09-03"
+      }
+      policy {
+        cookies_allowed: NO
+        setting: "Not user controlled. But the verification is a trusted API "
+                 "that doesn't use user data"
+        policy_exception_justification:
+          "Not implemented, considered not useful as no content is being "
+          "uploaded; this request merely downloads the resources on the web."
+      })");
 
 // Location on a website where the asset links file can be found, see
 // https://developers.google.com/digital-asset-links/v1/getting-started.
@@ -153,22 +186,24 @@
 DigitalAssetLinksHandler::~DigitalAssetLinksHandler() = default;
 
 void DigitalAssetLinksHandler::OnURLLoadComplete(
+    std::unique_ptr<network::SimpleURLLoader> url_loader,
     std::string relationship,
     std::optional<std::vector<std::string>> fingerprints,
     std::map<std::string, std::set<std::string>> target_values,
+    RelationshipCheckResultCallback callback,
     std::unique_ptr<std::string> response_body) {
   int response_code = -1;
-  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
-    response_code = url_loader_->ResponseInfo()->headers->response_code();
+  if (url_loader->ResponseInfo() && url_loader->ResponseInfo()->headers) {
+    response_code = url_loader->ResponseInfo()->headers->response_code();
   }
 
   if (!response_body || response_code != net::HTTP_OK) {
-    int net_error = url_loader_->NetError();
+    int net_error = url_loader->NetError();
     if (net_error == net::ERR_INTERNET_DISCONNECTED ||
         net_error == net::ERR_NAME_NOT_RESOLVED) {
       AddMessageToConsole(web_contents_.get(),
                           "Digital Asset Links connection failed.");
-      std::move(callback_).Run(RelationshipCheckResult::kNoConnection);
+      std::move(callback).Run(RelationshipCheckResult::kNoConnection);
       return;
     }
 
@@ -177,7 +212,7 @@
         base::StringPrintf(
             "Digital Asset Links endpoint responded with code %d.",
             response_code));
-    std::move(callback_).Run(RelationshipCheckResult::kFailure);
+    std::move(callback).Run(RelationshipCheckResult::kFailure);
     return;
   }
 
@@ -185,29 +220,29 @@
       *response_body,
       base::BindOnce(&DigitalAssetLinksHandler::OnJSONParseResult,
                      weak_ptr_factory_.GetWeakPtr(), std::move(relationship),
-                     std::move(fingerprints), std::move(target_values)));
-
-  url_loader_.reset(nullptr);
+                     std::move(fingerprints), std::move(target_values),
+                     std::move(callback)));
 }
 
 void DigitalAssetLinksHandler::OnJSONParseResult(
     std::string relationship,
     std::optional<std::vector<std::string>> fingerprints,
     std::map<std::string, std::set<std::string>> target_values,
+    RelationshipCheckResultCallback callback,
     data_decoder::DataDecoder::ValueOrError result) {
   if (!result.has_value()) {
     AddMessageToConsole(
         web_contents_.get(),
         "Digital Asset Links response parsing failed with message: " +
             result.error());
-    std::move(callback_).Run(RelationshipCheckResult::kFailure);
+    std::move(callback).Run(RelationshipCheckResult::kFailure);
     return;
   }
 
   base::Value::List* statement_list = result->GetIfList();
   if (!statement_list) {
     AddMessageToConsole(web_contents_.get(), "Statement List is not a list.");
-    std::move(callback_).Run(RelationshipCheckResult::kFailure);
+    std::move(callback).Run(RelationshipCheckResult::kFailure);
     return;
   }
 
@@ -246,7 +281,7 @@
       continue;
     }
 
-    std::move(callback_).Run(RelationshipCheckResult::kSuccess);
+    std::move(callback).Run(RelationshipCheckResult::kSuccess);
     return;
   }
 
@@ -254,7 +289,7 @@
     AddMessageToConsole(web_contents_.get(), failure_reason);
   }
 
-  std::move(callback_).Run(RelationshipCheckResult::kFailure);
+  std::move(callback).Run(RelationshipCheckResult::kFailure);
 }
 
 bool DigitalAssetLinksHandler::CheckDigitalAssetLinkRelationshipForAndroidApp(
@@ -290,54 +325,27 @@
     return false;
   }
 
-  // Resetting both the callback and SimpleURLLoader here to ensure
-  // that any previous requests will never get a
-  // OnURLLoadComplete. This effectively cancels any checks that was
-  // done over this handler.
-  callback_ = std::move(callback);
-
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("digital_asset_links", R"(
-        semantics {
-          sender: "Digital Asset Links Handler"
-          description:
-            "Digital Asset Links APIs allows any caller to check pre declared"
-            "relationships between two assets which can be either web domains"
-            "or native applications. This requests checks for a specific "
-            "relationship declared by a web site with an Android application"
-          trigger:
-            "When the related application makes a claim to have the queried"
-            "relationship with the web domain"
-          data: "None"
-          destination: WEBSITE
-        }
-        policy {
-          cookies_allowed: YES
-          cookies_store: "user"
-          setting: "Not user controlled. But the verification is a trusted API"
-                   "that doesn't use user data"
-          policy_exception_justification:
-            "Not implemented, considered not useful as no content is being "
-            "uploaded; this request merely downloads the resources on the web."
-        })");
-
   auto request = std::make_unique<network::ResourceRequest>();
   request->url = request_url;
 
-  // Exclude credentials (specifically client certs) from the request.
+  // Exclude credentials (cookies and client certs) from the request.
   request->credentials_mode =
       network::mojom::CredentialsMode::kOmitBug_775438_Workaround;
 
-  url_loader_ =
-      network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
-  url_loader_->SetRetryOptions(
+  std::unique_ptr<network::SimpleURLLoader> url_loader =
+      network::SimpleURLLoader::Create(std::move(request), kTrafficAnnotation);
+  url_loader->SetRetryOptions(
       kNumNetworkRetries,
       network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
-  url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+
+  // Grab a raw pointer before moving the unique_ptr into the bound callback.
+  network::SimpleURLLoader* raw_url_loader = url_loader.get();
+  raw_url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
       shared_url_loader_factory_.get(),
       base::BindOnce(&DigitalAssetLinksHandler::OnURLLoadComplete,
-                     weak_ptr_factory_.GetWeakPtr(), relationship,
-                     std::move(fingerprints), target_values));
+                     weak_ptr_factory_.GetWeakPtr(), std::move(url_loader),
+                     relationship, std::move(fingerprints), target_values,
+                     std::move(callback)));
 
   return true;
 }
diff --git a/components/content_relationship_verification/digital_asset_links_handler.h b/components/content_relationship_verification/digital_asset_links_handler.h
index fe0e16cb..cf5a825b 100644
--- a/components/content_relationship_verification/digital_asset_links_handler.h
+++ b/components/content_relationship_verification/digital_asset_links_handler.h
@@ -67,8 +67,7 @@
   // between) given. Any error in the string params here will result in a bad
   // request and a nullptr response to the callback.
   //
-  // Calling this multiple times on the same handler will cancel the previous
-  // checks. See
+  // See
   // https://developers.google.com/digital-asset-links/reference/rest/v1/assetlinks/check
   // for details.
   bool CheckDigitalAssetLinkRelationshipForAndroidApp(
@@ -103,9 +102,11 @@
       RelationshipCheckResultCallback callback);
 
   void OnURLLoadComplete(
+      std::unique_ptr<network::SimpleURLLoader> url_loader,
       std::string relationship,
       std::optional<std::vector<std::string>> fingerprints,
       std::map<std::string, std::set<std::string>> target_values,
+      RelationshipCheckResultCallback callback,
       std::unique_ptr<std::string> response_body);
 
   // Callback for the DataDecoder.
@@ -113,15 +114,11 @@
       std::string relationship,
       std::optional<std::vector<std::string>> fingerprints,
       std::map<std::string, std::set<std::string>> target_values,
+      RelationshipCheckResultCallback callback,
       data_decoder::DataDecoder::ValueOrError result);
 
   scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
 
-  std::unique_ptr<network::SimpleURLLoader> url_loader_;
-
-  // The per request callback for receiving a URLFetcher result. This gets
-  // reset every time we get a new CheckDigitalAssetLinkRelationship call.
-  RelationshipCheckResultCallback callback_;
 
   base::WeakPtr<content::WebContents> web_contents_;
 
diff --git a/components/download/internal/common/DEPS b/components/download/internal/common/DEPS
index ae3d18d..5ecffaa 100644
--- a/components/download/internal/common/DEPS
+++ b/components/download/internal/common/DEPS
@@ -8,6 +8,7 @@
   "+components/safe_browsing/buildflags.h",
   "+components/safe_browsing/content/common",
   "+components/services/quarantine/quarantine.h",
+  "+components/services/quarantine/public",
   "+components/ukm/test_ukm_recorder.h",
   "+crypto",
   "+mojo/public/c/system",
diff --git a/components/download/internal/common/base_file.cc b/components/download/internal/common/base_file.cc
index 931b6de0e..cafcdc6 100644
--- a/components/download/internal/common/base_file.cc
+++ b/components/download/internal/common/base_file.cc
@@ -625,6 +625,7 @@
     const std::string& client_guid,
     const GURL& source_url,
     const GURL& referrer_url,
+    const std::optional<url::Origin>& request_initiator,
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
     OnAnnotationDoneCallback on_annotation_done_callback) {
   GURL authority_url = GetEffectiveAuthorityURL(source_url, referrer_url);
@@ -649,7 +650,7 @@
         authority_url, referrer_url));
 
     quarantine_service_->QuarantineFile(
-        full_path_, authority_url, referrer_url, client_guid,
+        full_path_, authority_url, referrer_url, request_initiator, client_guid,
         base::BindOnce(&BaseFile::OnFileQuarantined,
                        weak_factory_.GetWeakPtr()));
   }
diff --git a/components/download/internal/common/download_file_impl.cc b/components/download/internal/common/download_file_impl.cc
index 482ea3f..24065eb 100644
--- a/components/download/internal/common/download_file_impl.cc
+++ b/components/download/internal/common/download_file_impl.cc
@@ -382,6 +382,7 @@
     const std::string& client_guid,
     const GURL& source_url,
     const GURL& referrer_url,
+    const std::optional<url::Origin>& request_initiator,
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
     RenameCompletionCallback callback) {
   std::unique_ptr<RenameParameters> parameters(new RenameParameters(
@@ -389,6 +390,7 @@
   parameters->client_guid = client_guid;
   parameters->source_url = source_url;
   parameters->referrer_url = referrer_url;
+  parameters->request_initiator = request_initiator;
   parameters->remote_quarantine = std::move(remote_quarantine);
   RenameWithRetryInternal(std::move(parameters));
 }
@@ -476,7 +478,8 @@
     // QuarantineFile when kPreventDownloadsWithSamePath is disabled.
     file_.AnnotateWithSourceInformation(
         parameters->client_guid, parameters->source_url,
-        parameters->referrer_url, std::move(parameters->remote_quarantine),
+        parameters->referrer_url, parameters->request_initiator,
+        std::move(parameters->remote_quarantine),
         base::BindOnce(&DownloadFileImpl::OnRenameComplete,
                        weak_factory_.GetWeakPtr(), new_path,
                        std::move(parameters->completion_callback)));
diff --git a/components/download/internal/common/download_file_unittest.cc b/components/download/internal/common/download_file_unittest.cc
index 842dc88..42ea52b 100644
--- a/components/download/internal/common/download_file_unittest.cc
+++ b/components/download/internal/common/download_file_unittest.cc
@@ -33,6 +33,8 @@
 #include "components/download/public/common/download_file_impl.h"
 #include "components/download/public/common/download_interrupt_reasons.h"
 #include "components/download/public/common/mock_input_stream.h"
+#include "components/services/quarantine/public/mojom/quarantine.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "net/base/net_errors.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -44,11 +46,13 @@
 using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::DoAll;
+using ::testing::Eq;
 using ::testing::InSequence;
 using ::testing::Return;
 using ::testing::Sequence;
 using ::testing::SetArgPointee;
 using ::testing::StrictMock;
+using ::testing::WithArg;
 
 namespace download {
 namespace {
@@ -139,6 +143,18 @@
 #endif
 };
 
+class MockQuarantine : public quarantine::mojom::Quarantine {
+ public:
+  MOCK_METHOD(void,
+              QuarantineFile,
+              (const base::FilePath& full_path,
+               const GURL& source_url,
+               const GURL& referrer_url,
+               const std::optional<url::Origin>& request_initiator,
+               const std::string& client_guid,
+               quarantine::mojom::Quarantine::QuarantineFileCallback callback));
+};
+
 }  // namespace
 
 class DownloadFileTest : public testing::Test {
@@ -164,7 +180,8 @@
         additional_streams_(std::vector<raw_ptr<StrictMock<MockInputStream>>>{
             nullptr, nullptr}),
         bytes_(-1),
-        bytes_per_sec_(-1) {}
+        bytes_per_sec_(-1),
+        quarantine_remote_(&quarantine_) {}
 
   ~DownloadFileTest() override {}
 
@@ -187,6 +204,12 @@
     EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
         .Times(AnyNumber())
         .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
+    ON_CALL(quarantine_, QuarantineFile(_, _, _, _, _, _))
+        .WillByDefault(WithArg<5>(
+            [](quarantine::mojom::Quarantine::QuarantineFileCallback callback) {
+              std::move(callback).Run(
+                  quarantine::mojom::QuarantineFileResult::OK);
+            }));
     bool result = download_dir_.CreateUniqueTempDir();
     CHECK(result);
   }
@@ -425,9 +448,19 @@
         break;
 
       case RENAME_AND_ANNOTATE:
+        // We cannot rebind a mojo::Remote without resetting it. The
+        // real implementation binds a new Remote on every call to
+        // RenameAndAnnotate, but it's simpler to reuse
+        // `quarantine_remote_` in tests.
+        quarantine_remote_.reset();
         download_file_->RenameAndAnnotate(
-            full_path, "12345678-ABCD-1234-DCBA-123456789ABC", GURL(), GURL(),
-            mojo::NullRemote(), std::move(completion_callback));
+            full_path, "12345678-ABCD-1234-DCBA-123456789ABC",
+            GURL("https://source.example.com/"),
+            GURL("https://referrer.example.com/"),
+            /*request_initiator=*/
+            url::Origin::Create(GURL("https://initiator.example.com/")),
+            quarantine_remote_.BindNewPipeAndPassRemote(),
+            std::move(completion_callback));
         break;
     }
   }
@@ -526,6 +559,8 @@
   // Keep track of what data should be saved to the disk file.
   std::string expected_data_;
 
+  MockQuarantine quarantine_;
+
  private:
   void SetRenameResult(base::OnceClosure closure,
                        DownloadInterruptReason* reason_p,
@@ -539,6 +574,8 @@
     std::move(closure).Run();
   }
 
+  mojo::Receiver<quarantine::mojom::Quarantine> quarantine_remote_;
+
   base::test::TaskEnvironment task_environment_;
 };
 
@@ -1273,4 +1310,31 @@
   DestroyDownloadFile(0, false);
 }
 
+TEST_F(DownloadFileTest, PropagatesUrlAndInitiatorToQuarantine) {
+  ASSERT_TRUE(CreateDownloadFile(true));
+  base::FilePath initial_path(download_file_->FullPath());
+  base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
+
+  EXPECT_CALL(
+      quarantine_,
+      QuarantineFile(
+          _, GURL("https://source.example.com/"),
+          GURL("https://referrer.example.com"),
+          Eq(url::Origin::Create(GURL("https://initiator.example.com/"))), _,
+          _))
+      .WillOnce(WithArg<5>(
+          [](quarantine::mojom::Quarantine::QuarantineFileCallback callback) {
+            std::move(callback).Run(
+                quarantine::mojom::QuarantineFileResult::OK);
+          }));
+  base::FilePath new_path;
+  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+            RenameAndAnnotate(path_1, &new_path));
+  EXPECT_EQ(path_1.value(), new_path.value());
+
+  FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
+  base::RunLoop().RunUntilIdle();
+  DestroyDownloadFile(0);
+}
+
 }  // namespace download
diff --git a/components/download/internal/common/download_file_with_copy.cc b/components/download/internal/common/download_file_with_copy.cc
index b614965d..dfa00a1 100644
--- a/components/download/internal/common/download_file_with_copy.cc
+++ b/components/download/internal/common/download_file_with_copy.cc
@@ -68,6 +68,7 @@
     const std::string& client_guid,
     const GURL& source_url,
     const GURL& referrer_url,
+    const std::optional<url::Origin>& request_initiator,
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
     RenameCompletionCallback callback) {
   if (full_path != file_path_to_copy_) {
diff --git a/components/download/internal/common/download_file_with_copy.h b/components/download/internal/common/download_file_with_copy.h
index e8931eb..b601b553 100644
--- a/components/download/internal/common/download_file_with_copy.h
+++ b/components/download/internal/common/download_file_with_copy.h
@@ -36,6 +36,7 @@
       const std::string& client_guid,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
       RenameCompletionCallback callback) override;
   void Detach() override;
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index 4689353..dce8875 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -1979,13 +1979,14 @@
 
   GetDownloadTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&DownloadFile::RenameAndAnnotate,
-                     base::Unretained(download_file_.get()),
-                     GetTargetFilePath(),
-                     delegate_->GetApplicationClientIdForFileScanning(),
-                     delegate_->IsOffTheRecord() ? GURL() : GetURL(),
-                     delegate_->IsOffTheRecord() ? GURL() : GetReferrerUrl(),
-                     std::move(quarantine), std::move(rename_callback)));
+      base::BindOnce(
+          &DownloadFile::RenameAndAnnotate,
+          base::Unretained(download_file_.get()), GetTargetFilePath(),
+          delegate_->GetApplicationClientIdForFileScanning(),
+          delegate_->IsOffTheRecord() ? GURL() : GetURL(),
+          delegate_->IsOffTheRecord() ? GURL() : GetReferrerUrl(),
+          delegate_->IsOffTheRecord() ? std::nullopt : GetRequestInitiator(),
+          std::move(quarantine), std::move(rename_callback)));
 }
 
 void DownloadItemImpl::OnRenameAndAnnotateDone(
diff --git a/components/download/internal/common/download_item_impl_unittest.cc b/components/download/internal/common/download_item_impl_unittest.cc
index a2efee7..deaf0b4 100644
--- a/components/download/internal/common/download_item_impl_unittest.cc
+++ b/components/download/internal/common/download_item_impl_unittest.cc
@@ -238,6 +238,8 @@
     create_info_->save_info->prompt_for_save_location = false;
     create_info_->url_chain.push_back(GURL("http://example.com/download"));
     create_info_->etag = "SomethingToSatisfyResumption";
+    create_info_->request_initiator =
+        url::Origin::Create(GURL("http://example.com"));
   }
 
   DownloadItemImpl* CreateDownloadItemWithCreateInfo(
@@ -352,8 +354,8 @@
         .WillOnce(Return(true));
     base::FilePath final_path(kDummyTargetPath);
     auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
-    EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _))
-        .WillOnce(WithArg<5>([&task_runner, &final_path](
+    EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _, _))
+        .WillOnce(WithArg<6>([&task_runner, &final_path](
                                  DownloadFile::RenameCompletionCallback cb) {
           task_runner->PostTask(
               FROM_HERE,
@@ -536,7 +538,7 @@
 
   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload_(_, _))
       .WillOnce(Return(true));
-  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _));
+  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _, _));
   unsafeurl_item->ValidateDangerousDownload();
   EXPECT_TRUE(unsafeurl_observer.CheckAndResetDownloadUpdated());
   CleanupItem(unsafeurl_item, download_file, DownloadItem::IN_PROGRESS);
@@ -554,7 +556,7 @@
 
   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload_(_, _))
       .WillOnce(Return(true));
-  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _));
+  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _, _));
   unsafefile_item->ValidateDangerousDownload();
   EXPECT_TRUE(unsafefile_observer.CheckAndResetDownloadUpdated());
   CleanupItem(unsafefile_item, download_file, DownloadItem::IN_PROGRESS);
@@ -791,8 +793,8 @@
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
   EXPECT_CALL(
       *download_file,
-      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _))
-      .WillOnce(WithArg<5>([&task_runner](
+      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _, _))
+      .WillOnce(WithArg<6>([&task_runner](
                                DownloadFile::RenameCompletionCallback cb) {
         task_runner->PostTask(
             FROM_HERE, base::BindOnce(std::move(cb),
@@ -1296,8 +1298,8 @@
 
   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload_(item, _))
       .WillOnce(Return(true));
-  EXPECT_CALL(*download_file, RenameAndAnnotate(final_path, _, _, _, _, _))
-      .WillOnce(WithArg<5>([&task_runner, &final_path](
+  EXPECT_CALL(*download_file, RenameAndAnnotate(final_path, _, _, _, _, _, _))
+      .WillOnce(WithArg<6>([&task_runner, &final_path](
                                DownloadFile::RenameCompletionCallback cb) {
         task_runner->PostTask(
             FROM_HERE,
@@ -1742,9 +1744,9 @@
 
   // Complete
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
-  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _))
+  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -1784,9 +1786,9 @@
   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload_(item, _))
       .WillOnce(Return(true));
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
-  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _))
+  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -1857,9 +1859,9 @@
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
   EXPECT_CALL(
       *download_file,
-      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _))
+      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -1900,9 +1902,9 @@
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
   EXPECT_CALL(
       *download_file,
-      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _))
+      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -1946,9 +1948,9 @@
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
   EXPECT_CALL(
       *download_file,
-      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _))
+      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -1999,9 +2001,9 @@
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
   EXPECT_CALL(
       *download_file,
-      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _))
+      RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -2115,9 +2117,9 @@
   // Target file should be annotated with the source URL.
   auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
   EXPECT_CALL(*download_file,
-              RenameAndAnnotate(_, _, create_info()->url(), _, _, _))
+              RenameAndAnnotate(_, _, create_info()->url(), _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -2137,9 +2139,9 @@
   download_file =
       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
   // Target file should be annotated with an empty URL.
-  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, GURL(), _, _, _))
+  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, GURL(), _, _, _, _))
       .WillOnce(
-          WithArg<5>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
             task_runner->PostTask(
                 FROM_HERE,
                 base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -2157,6 +2159,31 @@
   task_environment_.RunUntilIdle();
 }
 
+TEST_F(DownloadItemTest, AnnotationWithRequestInitiator) {
+  DownloadItemImpl* item = CreateDownloadItem();
+  MockDownloadFile* download_file =
+      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
+  auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
+  EXPECT_CALL(
+      *download_file,
+      RenameAndAnnotate(_, _, _, _, create_info()->request_initiator, _, _))
+      .WillOnce(
+          WithArg<6>([&task_runner](DownloadFile::RenameCompletionCallback cb) {
+            task_runner->PostTask(
+                FROM_HERE,
+                base::BindOnce(std::move(cb), DOWNLOAD_INTERRUPT_REASON_NONE,
+                               base::FilePath(kDummyTargetPath)));
+          }));
+  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload_(item, _))
+      .WillOnce(Return(true));
+  EXPECT_CALL(*download_file, FullPath())
+      .WillOnce(ReturnRefOfCopy(base::FilePath()));
+  EXPECT_CALL(*download_file, Detach());
+  item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+      0, std::unique_ptr<crypto::SecureHash>());
+  task_environment_.RunUntilIdle();
+}
+
 // The DownloadItemDestinationUpdateRaceTest fixture (defined below) is used to
 // test for race conditions between download destination events received via the
 // DownloadDestinationObserver interface, and the target determination logic.
diff --git a/components/download/internal/common/in_memory_download_file.cc b/components/download/internal/common/in_memory_download_file.cc
index d6ffce4..e3c3a65 100644
--- a/components/download/internal/common/in_memory_download_file.cc
+++ b/components/download/internal/common/in_memory_download_file.cc
@@ -96,6 +96,7 @@
     const std::string& client_guid,
     const GURL& source_url,
     const GURL& referrer_url,
+    const std::optional<url::Origin>& request_initiator,
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
     RenameCompletionCallback callback) {
   OnRenameComplete(memory_file_path_, main_task_runner_, std::move(callback));
diff --git a/components/download/internal/common/in_memory_download_file.h b/components/download/internal/common/in_memory_download_file.h
index d137a62a..54c6366 100644
--- a/components/download/internal/common/in_memory_download_file.h
+++ b/components/download/internal/common/in_memory_download_file.h
@@ -38,6 +38,7 @@
       const std::string& client_guid,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
       RenameCompletionCallback callback) override;
   void Detach() override;
diff --git a/components/download/public/common/base_file.h b/components/download/public/common/base_file.h
index e6d2c85..2818f0b 100644
--- a/components/download/public/common/base_file.h
+++ b/components/download/public/common/base_file.h
@@ -29,6 +29,7 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/net_errors.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace download {
 
@@ -172,10 +173,15 @@
   //     that originated this download. Will be used to annotate source
   //     information and also to determine the relative danger level of the
   //     file.
+  //
+  // `request_initiator`: Initiating origin for the request. This will
+  //     be used in place of the `source_url` when the `source_url` is not
+  //     suitable for reporting to the OS.
   void AnnotateWithSourceInformation(
       const std::string& client_guid,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
       OnAnnotationDoneCallback on_annotation_done_callback);
 
diff --git a/components/download/public/common/download_file.h b/components/download/public/common/download_file.h
index c78d88a..097bec5 100644
--- a/components/download/public/common/download_file.h
+++ b/components/download/public/common/download_file.h
@@ -91,6 +91,7 @@
       const std::string& client_guid,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
       RenameCompletionCallback callback) = 0;
 
diff --git a/components/download/public/common/download_file_impl.h b/components/download/public/common/download_file_impl.h
index f7222158..3d61c398 100644
--- a/components/download/public/common/download_file_impl.h
+++ b/components/download/public/common/download_file_impl.h
@@ -71,6 +71,7 @@
       const std::string& client_guid,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
       RenameCompletionCallback callback) override;
   void Detach() override;
@@ -237,6 +238,8 @@
     std::string client_guid;  // See BaseFile::AnnotateWithSourceInformation()
     GURL source_url;          // See BaseFile::AnnotateWithSourceInformation()
     GURL referrer_url;        // See BaseFile::AnnotateWithSourceInformation()
+    std::optional<url::Origin>
+        request_initiator;  // See BaseFile::AnnotateWithSourceInformation()
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine;
     int retries_left;         // RenameWithRetryInternal() will
                               // automatically retry until this
diff --git a/components/download/public/common/mock_download_file.h b/components/download/public/common/mock_download_file.h
index 413e9e7..e957ebe 100644
--- a/components/download/public/common/mock_download_file.h
+++ b/components/download/public/common/mock_download_file.h
@@ -46,14 +46,16 @@
   MOCK_METHOD2(RenameAndUniquify,
                void(const base::FilePath& full_path,
                     RenameCompletionCallback callback));
-  MOCK_METHOD6(
+  MOCK_METHOD(
+      void,
       RenameAndAnnotate,
-      void(const base::FilePath& full_path,
-           const std::string& client_guid,
-           const GURL& source_url,
-           const GURL& referrer_url,
-           mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
-           RenameCompletionCallback callback));
+      (const base::FilePath& full_path,
+       const std::string& client_guid,
+       const GURL& source_url,
+       const GURL& referrer_url,
+       const std::optional<url::Origin>& request_initiator,
+       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
+       RenameCompletionCallback callback));
   MOCK_METHOD0(Detach, void());
   MOCK_METHOD0(Cancel, void());
   MOCK_METHOD1(SetPotentialFileLength, void(int64_t length));
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
index a93fb7d..2d7951e 100644
--- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
+++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
@@ -59,7 +59,6 @@
     FeatureConstants.SHOPPING_LIST_SAVE_FLOW_FEATURE,
     FeatureConstants.TAB_GROUPS_QUICKLY_COMPARE_PAGES_FEATURE,
     FeatureConstants.TAB_GROUPS_TAP_TO_SEE_ANOTHER_TAB_FEATURE,
-    FeatureConstants.TAB_GROUPS_YOUR_TABS_ARE_TOGETHER_FEATURE,
     FeatureConstants.TAB_SWITCHER_BUTTON_FEATURE,
     FeatureConstants.TAB_SWITCHER_BUTTON_SWITCH_INCOGNITO,
     FeatureConstants.TAB_SWITCHER_FLOATING_ACTION_BUTTON,
@@ -219,9 +218,6 @@
     /** An IPH feature to show when tab group is synced across devices. */
     String TAB_GROUP_SYNC_ON_STRIP_FEATURE = "IPH_TabGroupSyncOnStrip";
 
-    /** An IPH feature to show on tab switcher cards with multiple tab thumbnails. */
-    String TAB_GROUPS_YOUR_TABS_ARE_TOGETHER_FEATURE = "IPH_TabGroupsYourTabsTogether";
-
     /** An IPH feature to prompt users to open the tab switcher after a navigation. */
     String TAB_SWITCHER_BUTTON_FEATURE = "IPH_TabSwitcherButton";
 
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 417ab0f..e3fdf7e0 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -384,9 +384,6 @@
 BASE_FEATURE(kIPHTabGroupSyncOnStripFeature,
              "IPH_TabGroupSyncOnStrip",
              base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kIPHTabGroupsYourTabsAreTogetherFeature,
-             "IPH_TabGroupsYourTabsTogether",
-             base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHTabGroupsDragAndDropFeature,
              "IPH_TabGroupsDragAndDrop",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index f9a6bdf..4e47b5f 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -156,7 +156,6 @@
 BASE_DECLARE_FEATURE(kIPHTabGroupsTapToSeeAnotherTabFeature);
 BASE_DECLARE_FEATURE(kIPHTabGroupCreationDialogSyncTextFeature);
 BASE_DECLARE_FEATURE(kIPHTabGroupSyncOnStripFeature);
-BASE_DECLARE_FEATURE(kIPHTabGroupsYourTabsAreTogetherFeature);
 BASE_DECLARE_FEATURE(kIPHTabGroupsDragAndDropFeature);
 BASE_DECLARE_FEATURE(kIPHTabGroupsRemoteGroupFeature);
 BASE_DECLARE_FEATURE(kIPHTabGroupsSurfaceFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index 1ec1cc1..92e42bb2 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -84,7 +84,6 @@
     &kIPHTabGroupsTapToSeeAnotherTabFeature,
     &kIPHTabGroupCreationDialogSyncTextFeature,
     &kIPHTabGroupSyncOnStripFeature,
-    &kIPHTabGroupsYourTabsAreTogetherFeature,
     &kIPHTabGroupsDragAndDropFeature,
     &kIPHTabGroupsRemoteGroupFeature,
     &kIPHTabGroupsSurfaceFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index 6186694..e9f4ed80 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -155,8 +155,6 @@
                        "IPH_TabGroupCreationDialogSyncText");
 DEFINE_VARIATION_PARAM(kIPHTabGroupSyncOnStripFeature,
                        "IPH_TabGroupSyncOnStrip");
-DEFINE_VARIATION_PARAM(kIPHTabGroupsYourTabsAreTogetherFeature,
-                       "IPH_TabGroupsYourTabsTogether");
 DEFINE_VARIATION_PARAM(kIPHTabGroupsDragAndDropFeature,
                        "IPH_TabGroupsDragAndDrop");
 DEFINE_VARIATION_PARAM(kIPHTabGroupsRemoteGroupFeature,
@@ -567,7 +565,6 @@
         VARIATION_ENTRY(kIPHTabGroupCreationDialogSyncTextFeature),
         VARIATION_ENTRY(kIPHTabGroupsQuicklyComparePagesFeature),
         VARIATION_ENTRY(kIPHTabGroupsTapToSeeAnotherTabFeature),
-        VARIATION_ENTRY(kIPHTabGroupsYourTabsAreTogetherFeature),
         VARIATION_ENTRY(kIPHTabGroupsDragAndDropFeature),
         VARIATION_ENTRY(kIPHTabGroupsRemoteGroupFeature),
         VARIATION_ENTRY(kIPHTabGroupsSurfaceFeature),
diff --git a/components/input/input_router_impl.cc b/components/input/input_router_impl.cc
index 7a418d1..4b3d5d0 100644
--- a/components/input/input_router_impl.cc
+++ b/components/input/input_router_impl.cc
@@ -40,6 +40,7 @@
 using blink::WebMouseWheelEvent;
 using blink::WebTouchEvent;
 using perfetto::protos::pbzero::ChromeLatencyInfo;
+using perfetto::protos::pbzero::ChromeLatencyInfo2;
 using perfetto::protos::pbzero::TrackEvent;
 using ui::WebInputEventTraits;
 
@@ -68,23 +69,23 @@
       std::vector<std::unique_ptr<WebInputEvent>>(), latency_info);
 }
 
-ChromeLatencyInfo::InputType GetInputTypeForLatencyInfo(
+ChromeLatencyInfo2::InputType GetInputTypeForLatencyInfo(
     const WebInputEvent& input_event) {
   switch (input_event.GetType()) {
     case WebInputEvent::Type::kGestureScrollBegin:
-      return ChromeLatencyInfo::InputType::GESTURE_SCROLL_BEGIN;
+      return ChromeLatencyInfo2::InputType::GESTURE_SCROLL_BEGIN;
     case WebInputEvent::Type::kGestureScrollEnd:
-      return ChromeLatencyInfo::InputType::GESTURE_SCROLL_END;
+      return ChromeLatencyInfo2::InputType::GESTURE_SCROLL_END;
     case WebInputEvent::Type::kGestureScrollUpdate:
-      return ChromeLatencyInfo::InputType::GESTURE_SCROLL_UPDATE;
+      return ChromeLatencyInfo2::InputType::GESTURE_SCROLL_UPDATE;
     case WebInputEvent::Type::kGestureTap:
-      return ChromeLatencyInfo::InputType::GESTURE_TAP;
+      return ChromeLatencyInfo2::InputType::GESTURE_TAP;
     case WebInputEvent::Type::kGestureTapCancel:
-      return ChromeLatencyInfo::InputType::GESTURE_TAP_CANCEL;
+      return ChromeLatencyInfo2::InputType::GESTURE_TAP_CANCEL;
     case WebInputEvent::Type::kTouchMove:
-      return ChromeLatencyInfo::InputType::TOUCH_MOVED;
+      return ChromeLatencyInfo2::InputType::TOUCH_MOVED;
     default:
-      return ChromeLatencyInfo::InputType::UNSPECIFIED_OR_OTHER;
+      return ChromeLatencyInfo2::InputType::UNSPECIFIED_OR_OTHER;
   }
 }
 
@@ -594,20 +595,21 @@
     blink::mojom::WidgetInputHandler::DispatchEventCallback callback) {
   TRACE_EVENT1("input", "InputRouterImpl::FilterAndSendWebInputEvent", "type",
                WebInputEvent::GetName(input_event.GetType()));
-  TRACE_EVENT("input,benchmark,devtools.timeline,latencyInfo",
-              "LatencyInfo.Flow",
-              [&latency_info, &input_event](perfetto::EventContext ctx) {
-                ChromeLatencyInfo* info =
-                    ctx.event()->set_chrome_latency_info();
-                info->set_trace_id(latency_info.trace_id());
-                info->set_step(ChromeLatencyInfo::STEP_SEND_INPUT_EVENT_UI);
-                info->set_input_type(GetInputTypeForLatencyInfo(input_event));
+  TRACE_EVENT(
+      "input,benchmark,devtools.timeline,latencyInfo", "LatencyInfo.Flow",
+      [&latency_info, &input_event](perfetto::EventContext ctx) {
+        auto* info = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                         ->set_chrome_latency_info();
+        info->set_trace_id(latency_info.trace_id());
+        info->set_step(
+            perfetto::protos::pbzero::perfetto_pbzero_enum_ChromeLatencyInfo2::
+                Step::STEP_SEND_INPUT_EVENT_UI);
+        info->set_input_type(GetInputTypeForLatencyInfo(input_event));
 
-                tracing::FillFlowEvent(ctx,
-                                       perfetto::protos::pbzero::TrackEvent::
-                                           LegacyEvent::FLOW_INOUT,
-                                       latency_info.trace_id());
-              });
+        tracing::FillFlowEvent(
+            ctx, perfetto::protos::pbzero::TrackEvent::LegacyEvent::FLOW_INOUT,
+            latency_info.trace_id());
+      });
 
   output_stream_validator_.Validate(input_event);
   blink::mojom::InputEventResultState filtered_state =
diff --git a/components/input/render_input_router.cc b/components/input/render_input_router.cc
index 3b718d7..62c2a376 100644
--- a/components/input/render_input_router.cc
+++ b/components/input/render_input_router.cc
@@ -320,6 +320,18 @@
   TRACE_EVENT1("input", "RenderInputRouter::ForwardGestureEvent", "type",
                WebInputEvent::GetName(gesture_event.GetType()));
 
+  input::GestureEventWithLatencyInfo gesture_with_latency(gesture_event,
+                                                          latency_info);
+
+  // Assigns a `trace_id` to the latency object.
+  latency_tracker_->OnEventStart(&gesture_with_latency.latency);
+
+  TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
+              [&gesture_with_latency](perfetto::EventContext ctx) {
+                ui::LatencyInfo::FillTraceEvent(gesture_with_latency.latency,
+                                                ctx);
+              });
+
   // Early out if necessary, prior to performing latency logic.
   if (delegate_->IsIgnoringWebInputEvents(gesture_event)) {
     // IgnoreWebInputEvents is primarily concerned with suppressing event
@@ -360,8 +372,6 @@
     return;
   }
 
-  input::GestureEventWithLatencyInfo gesture_with_latency(gesture_event,
-                                                          latency_info);
   DispatchInputEventWithLatencyInfo(
       gesture_with_latency.event, &gesture_with_latency.latency,
       &gesture_with_latency.event.GetModifiableEventLatencyMetadata());
@@ -450,6 +460,16 @@
   // ignored if appropriate in FilterInputEvent().
 
   input::TouchEventWithLatencyInfo touch_with_latency(touch_event, latency);
+
+  // Assigns a `trace_id` to the latency object.
+  latency_tracker_->OnEventStart(&touch_with_latency.latency);
+
+  TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
+              [&touch_with_latency](perfetto::EventContext ctx) {
+                ui::LatencyInfo::FillTraceEvent(touch_with_latency.latency,
+                                                ctx);
+              });
+
   DispatchInputEventWithLatencyInfo(
       touch_with_latency.event, &touch_with_latency.latency,
       &touch_with_latency.event.GetModifiableEventLatencyMetadata());
diff --git a/components/input/render_input_router_latency_tracker.cc b/components/input/render_input_router_latency_tracker.cc
index 4e13d531..eacb591 100644
--- a/components/input/render_input_router_latency_tracker.cc
+++ b/components/input/render_input_router_latency_tracker.cc
@@ -214,8 +214,10 @@
 }
 
 void RenderInputRouterLatencyTracker::OnEventStart(ui::LatencyInfo* latency) {
-  static uint64_t global_trace_id = 0;
-  latency->set_trace_id(++global_trace_id);
+  if (latency->trace_id() == -1) {
+    static uint64_t global_trace_id = 0;
+    latency->set_trace_id(++global_trace_id);
+  }
 }
 
 }  // namespace input
diff --git a/components/input/render_input_router_latency_tracker.h b/components/input/render_input_router_latency_tracker.h
index da5bc26..2890e4c0 100644
--- a/components/input/render_input_router_latency_tracker.h
+++ b/components/input/render_input_router_latency_tracker.h
@@ -31,6 +31,9 @@
 
   virtual ~RenderInputRouterLatencyTracker();
 
+  // Sets `latency`'s `trace_id` field to the next global ID.
+  void OnEventStart(ui::LatencyInfo* latency);
+
   // Populates the LatencyInfo with relevant entries for latency tracking.
   // Called when an event is received by the RenderWidgetHost, prior to
   // that event being forwarded to the renderer (via the InputRouter).
@@ -49,11 +52,9 @@
   void reset_delegate() { render_input_router_delegate_ = nullptr; }
 
  private:
-  void OnEventStart(ui::LatencyInfo* latency);
-
-  bool has_seen_first_gesture_scroll_update_;
-  int64_t gesture_scroll_id_;
-  int64_t touch_trace_id_;
+  bool has_seen_first_gesture_scroll_update_ = false;
+  int64_t gesture_scroll_id_ = -1;
+  int64_t touch_trace_id_ = -1;
 
   // Whether the current stream of touch events includes more than one active
   // touch point. This is set in OnInputEvent, and cleared in OnInputEventAck.
diff --git a/components/javascript_dialogs/BUILD.gn b/components/javascript_dialogs/BUILD.gn
index 3f9c266..29e2506e 100644
--- a/components/javascript_dialogs/BUILD.gn
+++ b/components/javascript_dialogs/BUILD.gn
@@ -75,6 +75,13 @@
       "//ui/android",
     ]
   }
+
+  if (is_ios) {
+    sources += [
+      "ios/tab_modal_dialog_view_ios.h",
+      "ios/tab_modal_dialog_view_ios.mm",
+    ]
+  }
 }
 
 source_set("unit_tests") {
diff --git a/components/javascript_dialogs/ios/OWNERS b/components/javascript_dialogs/ios/OWNERS
new file mode 100644
index 0000000..5963bb3
--- /dev/null
+++ b/components/javascript_dialogs/ios/OWNERS
@@ -0,0 +1,2 @@
+file://ios/web/content/OWNERS
+gyuyoung@igalia.com
diff --git a/components/javascript_dialogs/ios/tab_modal_dialog_view_ios.h b/components/javascript_dialogs/ios/tab_modal_dialog_view_ios.h
new file mode 100644
index 0000000..4960cb4
--- /dev/null
+++ b/components/javascript_dialogs/ios/tab_modal_dialog_view_ios.h
@@ -0,0 +1,63 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_JAVASCRIPT_DIALOGS_IOS_TAB_MODAL_DIALOG_VIEW_IOS_H_
+#define COMPONENTS_JAVASCRIPT_DIALOGS_IOS_TAB_MODAL_DIALOG_VIEW_IOS_H_
+
+#import <memory>
+
+#import "base/functional/callback.h"
+#import "base/memory/weak_ptr.h"
+#import "components/javascript_dialogs/tab_modal_dialog_view.h"
+#import "content/public/browser/javascript_dialog_manager.h"
+
+namespace javascript_dialogs {
+
+// An iOS version of the JavaScript dialog referring to the Android
+// implementation.
+class TabModalDialogViewIOS : public TabModalDialogView {
+ public:
+  TabModalDialogViewIOS(const TabModalDialogViewIOS&) = delete;
+  TabModalDialogViewIOS& operator=(const TabModalDialogViewIOS&) = delete;
+
+  ~TabModalDialogViewIOS() override;
+
+  static base::WeakPtr<TabModalDialogViewIOS> Create(
+      content::WebContents* parent_web_contents,
+      content::WebContents* alerting_web_contents,
+      const std::u16string& title,
+      content::JavaScriptDialogType dialog_type,
+      const std::u16string& message_text,
+      const std::u16string& default_prompt_text,
+      content::JavaScriptDialogManager::DialogClosedCallback
+          callback_on_button_clicked,
+      base::OnceClosure callback_on_cancelled);
+
+  // TabModalDialogView:
+  void CloseDialogWithoutCallback() override;
+  std::u16string GetUserInput() override;
+
+ private:
+  TabModalDialogViewIOS(content::WebContents* parent_web_contents,
+                        content::WebContents* alerting_web_contents,
+                        const std::u16string& title,
+                        content::JavaScriptDialogType dialog_type,
+                        const std::u16string& message_text,
+                        const std::u16string& default_prompt_text,
+                        content::JavaScriptDialogManager::DialogClosedCallback
+                            callback_on_button_clicked,
+                        base::OnceClosure callback_on_cancelled);
+
+  std::unique_ptr<TabModalDialogViewIOS> dialog_;
+
+  content::JavaScriptDialogManager::DialogClosedCallback
+      callback_on_button_clicked_;
+  base::OnceClosure callback_on_cancelled_;
+
+  base::WeakPtrFactory<TabModalDialogViewIOS> weak_factory_{this};
+};
+
+}  // namespace javascript_dialogs
+
+#endif  // COMPONENTS_JAVASCRIPT_DIALOGS_IOS_TAB_MODAL_DIALOG_VIEW_IOS_H_
diff --git a/components/javascript_dialogs/ios/tab_modal_dialog_view_ios.mm b/components/javascript_dialogs/ios/tab_modal_dialog_view_ios.mm
new file mode 100644
index 0000000..d4f8473
--- /dev/null
+++ b/components/javascript_dialogs/ios/tab_modal_dialog_view_ios.mm
@@ -0,0 +1,57 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "components/javascript_dialogs/ios/tab_modal_dialog_view_ios.h"
+
+#import "content/public/browser/browser_thread.h"
+#import "content/public/browser/web_contents.h"
+
+namespace javascript_dialogs {
+
+// static
+base::WeakPtr<TabModalDialogViewIOS> TabModalDialogViewIOS::Create(
+    content::WebContents* parent_web_contents,
+    content::WebContents* alerting_web_contents,
+    const std::u16string& title,
+    content::JavaScriptDialogType dialog_type,
+    const std::u16string& message_text,
+    const std::u16string& default_prompt_text,
+    content::JavaScriptDialogManager::DialogClosedCallback
+        callback_on_button_clicked,
+    base::OnceClosure callback_on_cancelled) {
+  return (new TabModalDialogViewIOS(parent_web_contents, alerting_web_contents,
+                                    title, dialog_type, message_text,
+                                    default_prompt_text,
+                                    std::move(callback_on_button_clicked),
+                                    std::move(callback_on_cancelled)))
+      ->weak_factory_.GetWeakPtr();
+}
+
+// TabModalDialogViewIOS:
+TabModalDialogViewIOS::~TabModalDialogViewIOS() {}
+
+void TabModalDialogViewIOS::CloseDialogWithoutCallback() {
+  delete this;
+}
+
+std::u16string TabModalDialogViewIOS::GetUserInput() {
+  return std::u16string();
+}
+
+TabModalDialogViewIOS::TabModalDialogViewIOS(
+    content::WebContents* parent_web_contents,
+    content::WebContents* alerting_web_contents,
+    const std::u16string& title,
+    content::JavaScriptDialogType dialog_type,
+    const std::u16string& message_text,
+    const std::u16string& default_prompt_text,
+    content::JavaScriptDialogManager::DialogClosedCallback
+        callback_on_button_clicked,
+    base::OnceClosure callback_on_cancelled)
+    : callback_on_button_clicked_(std::move(callback_on_button_clicked)),
+      callback_on_cancelled_(std::move(callback_on_cancelled)) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+}  // namespace javascript_dialogs
diff --git a/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java b/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
index 96cbb06f5..0c292cb 100644
--- a/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
+++ b/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
@@ -15,6 +15,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.build.BuildConfig;
 import org.chromium.components.module_installer.engine.InstallEngine;
 import org.chromium.components.module_installer.engine.InstallListener;
 
@@ -155,7 +156,7 @@
     private ModuleDescriptor getModuleDescriptor() {
         ModuleDescriptor ret = mModuleDescriptor;
         if (ret == null) {
-            if (BundleUtils.isBundle()) {
+            if (BuildConfig.IS_BUNDLE) {
                 ret =
                         (ModuleDescriptor)
                                 instantiateReflectively(
diff --git a/components/module_installer/android/java/src/org/chromium/components/module_installer/engine/EngineFactory.java b/components/module_installer/android/java/src/org/chromium/components/module_installer/engine/EngineFactory.java
index 7c06daa..1056a0e 100644
--- a/components/module_installer/android/java/src/org/chromium/components/module_installer/engine/EngineFactory.java
+++ b/components/module_installer/android/java/src/org/chromium/components/module_installer/engine/EngineFactory.java
@@ -4,14 +4,11 @@
 
 package org.chromium.components.module_installer.engine;
 
-import org.chromium.base.BundleUtils;
+import org.chromium.build.BuildConfig;
 
 /** Factory used to build concrete engines. */
 public class EngineFactory {
     public InstallEngine getEngine() {
-        if (!BundleUtils.isBundle()) {
-            return new ApkEngine();
-        }
-        return new SplitCompatEngine();
+        return BuildConfig.IS_BUNDLE ? new SplitCompatEngine() : new ApkEngine();
     }
 }
diff --git a/components/module_installer/android/java/src/org/chromium/components/module_installer/util/ModuleUtil.java b/components/module_installer/android/java/src/org/chromium/components/module_installer/util/ModuleUtil.java
index 430bc36d..b36e0504 100644
--- a/components/module_installer/android/java/src/org/chromium/components/module_installer/util/ModuleUtil.java
+++ b/components/module_installer/android/java/src/org/chromium/components/module_installer/util/ModuleUtil.java
@@ -4,21 +4,20 @@
 
 package org.chromium.components.module_installer.util;
 
-import org.chromium.base.BundleUtils;
+import org.chromium.build.BuildConfig;
 
 /** Utilitary class (proxy) exposing DFM functionality to the broader application. */
 public class ModuleUtil {
-
     /** Updates the CrashKey report containing modules currently present. */
     public static void updateCrashKeys() {
-        if (!BundleUtils.isBundle()) return;
+        if (!BuildConfig.IS_BUNDLE) return;
 
         CrashKeyRecorder.updateCrashKeys();
     }
 
     /** Initializes the PlayCore SplitCompat framework. */
     public static void initApplication() {
-        if (!BundleUtils.isBundle()) return;
+        if (!BuildConfig.IS_BUNDLE) return;
 
         SplitCompatInitializer.initApplication();
         ActivityObserverUtil.registerDefaultObserver();
@@ -26,7 +25,7 @@
 
     /** Notifies the ActivityObserver when modules are installed. */
     public static void notifyModuleInstalled() {
-        if (!BundleUtils.isBundle()) return;
+        if (!BuildConfig.IS_BUNDLE) return;
 
         ActivityObserverUtil.notifyObservers();
     }
diff --git a/components/omnibox/browser/omnibox_url_emphasizer.cc b/components/omnibox/browser/omnibox_url_emphasizer.cc
index e136601..adebf8e3 100644
--- a/components/omnibox/browser/omnibox_url_emphasizer.cc
+++ b/components/omnibox/browser/omnibox_url_emphasizer.cc
@@ -34,5 +34,5 @@
       text, *autocomplete_scheme_classifier, &scheme, &host);
 
   int emphasize_values[] = {scheme.begin, scheme.len, host.begin, host.len};
-  return base::android::ToJavaIntArray(env, emphasize_values, 4);
+  return base::android::ToJavaIntArray(env, emphasize_values);
 }
diff --git a/components/omnibox/browser/suggestion_answer.h b/components/omnibox/browser/suggestion_answer.h
index 5641061..6f2bc3a 100644
--- a/components/omnibox/browser/suggestion_answer.h
+++ b/components/omnibox/browser/suggestion_answer.h
@@ -248,7 +248,6 @@
   GURL image_url_;
   ImageLine first_line_;
   ImageLine second_line_;
-  int type_ = -1;
 
   FRIEND_TEST_ALL_PREFIXES(SuggestionAnswerTest, DifferentValuesAreUnequal);
   FRIEND_TEST_ALL_PREFIXES(SuggestionAnswerTest, LogAnswerUsed);
diff --git a/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc
index 68cc0579..d8c441ce 100644
--- a/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc
@@ -85,8 +85,8 @@
 const char kAbandonReasonErrorPage[] = "ErrorPage";
 const char kAbandonReasonAppBackgrounded[] = "AppBackgrounded";
 
-const char kSuffixWasBackgrounded[] = ".WasAppBackgrounded";
-const char kSuffixWasHidden[] = ".WasTabHidden";
+const char kSuffixWasBackgrounded[] = ".WasBackgrounded";
+const char kSuffixWasHidden[] = ".WasHidden";
 const char kSuffixResponseFromCache[] = ".ResponseFromCache";
 
 const char kMilestoneNavigationStart[] = "NavigationStart";
@@ -571,7 +571,7 @@
 
   if (!started_in_foreground) {
     page_load_metrics::mojom::PageLoadTiming empty_timing;
-    OnHidden(empty_timing);
+    FlushMetricsOnAppEnterBackground(empty_timing);
   }
 
   return CONTINUE_OBSERVING;
diff --git a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestRule.java b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestRule.java
index 31646530..f977705 100644
--- a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestRule.java
+++ b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestRule.java
@@ -29,11 +29,7 @@
             @Override
             public void evaluate() throws Throwable {
                 setUp();
-                try {
-                    base.evaluate();
-                } finally {
-                    AccountManagerFacadeProvider.resetInstanceForTests();
-                }
+                base.evaluate();
             }
         };
     }
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc
index 4605f58..1368245e 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -645,10 +645,6 @@
   CHECK(!types_to_fetch_.empty());
 
   VLOG(2) << "Policy fetch starting";
-  for (const auto& type : types_to_fetch_) {
-    VLOG_POLICY(2, POLICY_FETCHING)
-        << "Fetching policy type: " << type.first << " -> " << type.second;
-  }
   auto params = DMServerJobConfiguration::CreateParams::WithClient(
       DeviceManagementService::JobConfiguration::TYPE_POLICY_FETCH, this);
   params.auth_data = DMAuth::FromDMToken(dm_token_);
@@ -676,6 +672,9 @@
   const em::PolicyFetchRequest::SignatureType signature_type =
       GetPolicyFetchRequestSignatureType();
   for (const auto& type_to_fetch : types_to_fetch_) {
+    VLOG_POLICY(2, POLICY_FETCHING)
+        << "Fetching policy type: " << type_to_fetch.first << " -> "
+        << type_to_fetch.second;
     em::PolicyFetchRequest* fetch_request = policy_request->add_requests();
     fetch_request->set_policy_type(type_to_fetch.first);
     if (!type_to_fetch.second.empty()) {
diff --git a/components/policy/resources/templates/policy_definitions/GenerativeAI/GenAiDefaultSettings.yaml b/components/policy/resources/templates/policy_definitions/GenerativeAI/GenAiDefaultSettings.yaml
index a794104a..173a95c 100644
--- a/components/policy/resources/templates/policy_definitions/GenerativeAI/GenAiDefaultSettings.yaml
+++ b/components/policy/resources/templates/policy_definitions/GenerativeAI/GenAiDefaultSettings.yaml
@@ -21,6 +21,7 @@
   dynamic_refresh: true
   per_profile: true
 future_on:
+- android
 - chrome.*
 - chrome_os
 items:
diff --git a/components/policy/test/data/pref_mapping/GenAiDefaultSettings.json b/components/policy/test/data/pref_mapping/GenAiDefaultSettings.json
index b3b6b8e..03be3552 100644
--- a/components/policy/test/data/pref_mapping/GenAiDefaultSettings.json
+++ b/components/policy/test/data/pref_mapping/GenAiDefaultSettings.json
@@ -238,5 +238,11 @@
         }
       }
     ]
+  },
+  {
+    "os": [
+      "android"
+    ],
+    "reason_for_missing_test": "No covered GenAI policies are currently supported on Android."
   }
 ]
diff --git a/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java b/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java
index 9f9da68e..ff4c8ec 100644
--- a/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java
+++ b/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java
@@ -9,16 +9,8 @@
  * SafeBrowsingApiBridge}.
  */
 public interface SafetyNetApiHandler {
-    /** Observer to be notified when the SafetyNetApiHandler determines the verdict for a url. */
+    /** Observer to be notified when the SafetyNetApiHandler determines the verify apps result. */
     interface Observer {
-        // TODO(crbug.com/40935425): Remove this function once internal reference is removed.
-        // Note: |checkDelta| is the time the remote call took in microseconds.
-        default void onUrlCheckDone(
-                long callbackId,
-                @SafeBrowsingResult int resultStatus,
-                String metadata,
-                long checkDelta) {}
-
         void onVerifyAppsEnabledDone(long callbackId, @VerifyAppsResult int result);
     }
 
@@ -33,14 +25,6 @@
     boolean init(Observer observer);
 
     /**
-     * TODO(crbug.com/40935425): Remove this function once internal reference is removed.
-     *
-     * <p>Start a URI-lookup to determine if it matches one of the specified threats. This is called
-     * on every URL resource Chrome loads, on the same sequence as |init|.
-     */
-    default void startUriLookup(long callbackId, String uri, int[] threatsOfInterest) {}
-
-    /**
      * Start a check to determine if a uri is in an allowlist. If true, password protection service
      * will consider the uri to be safe.
      *
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_util.h b/components/safe_browsing/android/safe_browsing_api_handler_util.h
index 600b3e2..e299dacf 100644
--- a/components/safe_browsing/android/safe_browsing_api_handler_util.h
+++ b/components/safe_browsing/android/safe_browsing_api_handler_util.h
@@ -13,16 +13,6 @@
 
 namespace safe_browsing {
 
-// TODO(crbug.com/40935425): Remove this enum once internal reference is
-// removed. These match what SafetyNetApiHandler.java uses for |resultStatus|
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.safe_browsing
-// GENERATED_JAVA_CLASS_NAME_OVERRIDE: SafeBrowsingResult
-enum class SafetyNetRemoteCallResultStatus {
-  INTERNAL_ERROR = -1,
-  SUCCESS = 0,
-  TIMEOUT = 1,
-};
-
 // Threat types as per the Java code.
 // This must match those in SafeBrowsingThreat.java in GMS's SafetyNet API.
 enum class SafetyNetJavaThreatType {
diff --git a/components/search_engines/template_url_data.cc b/components/search_engines/template_url_data.cc
index 3190727d..c82a12b 100644
--- a/components/search_engines/template_url_data.cc
+++ b/components/search_engines/template_url_data.cc
@@ -158,7 +158,8 @@
   // keywords to be lower case.
   keyword_ = base::i18n::ToLower(keyword);
 
-  base::TrimWhitespace(keyword_, base::TRIM_ALL, &keyword_);
+  // The omnibox doesn't properly handle search keywords with whitespace.
+  base::RemoveChars(keyword_, base::kWhitespaceUTF16, &keyword_);
 }
 
 void TemplateURLData::SetURL(const std::string& url) {
diff --git a/components/search_engines/template_url_data_unittest.cc b/components/search_engines/template_url_data_unittest.cc
index ca8107b..30b662a 100644
--- a/components/search_engines/template_url_data_unittest.cc
+++ b/components/search_engines/template_url_data_unittest.cc
@@ -45,6 +45,10 @@
 
   EXPECT_EQ(u"othershortname", data.short_name());
   EXPECT_EQ(u"otherkeyword", data.keyword());
+
+  data.SetKeyword(u" other other keyword ");
+
+  EXPECT_EQ(u"otherotherkeyword", data.keyword());
 }
 
 TEST(TemplateURLDataTest, AcceptKnownRegulatoryKeywords) {
diff --git a/components/search_engines/template_url_service_util_unittest.cc b/components/search_engines/template_url_service_util_unittest.cc
index 422a862..b800b238 100644
--- a/components/search_engines/template_url_service_util_unittest.cc
+++ b/components/search_engines/template_url_service_util_unittest.cc
@@ -221,7 +221,7 @@
   // Modify the keyword and title for original_turl and set safe_for_autoreplace
   // to false to simulate a "user edited" template url.
   original_turl_data->SetShortName(u"modified name");
-  original_turl_data->SetKeyword(u"new keyword");
+  original_turl_data->SetKeyword(u"newkeyword");
   original_turl_data->safe_for_autoreplace = false;
 
   std::unique_ptr<TemplateURL> original_turl =
@@ -245,7 +245,7 @@
 
   EXPECT_FALSE(url_to_update->safe_for_autoreplace);
   EXPECT_EQ(url_to_update->short_name(), u"modified name");
-  EXPECT_EQ(url_to_update->keyword(), u"new keyword");
+  EXPECT_EQ(url_to_update->keyword(), u"newkeyword");
 }
 
 class TemplateURLServiceUtilLoadTest : public testing::Test {
diff --git a/components/search_engines/template_url_starter_pack_data.cc b/components/search_engines/template_url_starter_pack_data.cc
index a90f430c..cdcc0dff 100644
--- a/components/search_engines/template_url_starter_pack_data.cc
+++ b/components/search_engines/template_url_starter_pack_data.cc
@@ -14,7 +14,7 @@
 namespace TemplateURLStarterPackData {
 
 // Update this whenever a change is made to any starter pack data.
-const int kCurrentDataVersion = 10;
+const int kCurrentDataVersion = 11;
 
 // Only update this if there's an incompatible change that requires force
 // updating the user's starter pack data. This will overwrite any of the
diff --git a/components/segmentation_platform/public/android/input_context_android_unittest.cc b/components/segmentation_platform/public/android/input_context_android_unittest.cc
index f0334726..41c99d2 100644
--- a/components/segmentation_platform/public/android/input_context_android_unittest.cc
+++ b/components/segmentation_platform/public/android/input_context_android_unittest.cc
@@ -67,25 +67,22 @@
   base::android::ScopedJavaLocalRef<jobjectArray> java_bool_keys =
       base::android::ToJavaArrayOfStrings(jni_env, bool_keys);
   base::android::ScopedJavaLocalRef<jbooleanArray> java_bool_values =
-      base::android::ToJavaBooleanArray(jni_env, bool_values,
-                                        std::size(bool_values));
+      base::android::ToJavaBooleanArray(jni_env, bool_values);
 
   base::android::ScopedJavaLocalRef<jobjectArray> java_int_keys =
       base::android::ToJavaArrayOfStrings(jni_env, int_keys);
   base::android::ScopedJavaLocalRef<jintArray> java_int_values =
-      base::android::ToJavaIntArray(jni_env, int_values, std::size(int_values));
+      base::android::ToJavaIntArray(jni_env, int_values);
 
   base::android::ScopedJavaLocalRef<jobjectArray> java_float_keys =
       base::android::ToJavaArrayOfStrings(jni_env, float_keys);
   base::android::ScopedJavaLocalRef<jfloatArray> java_float_values =
-      base::android::ToJavaFloatArray(jni_env, float_values,
-                                      std::size(float_values));
+      base::android::ToJavaFloatArray(jni_env, float_values);
 
   base::android::ScopedJavaLocalRef<jobjectArray> java_double_keys =
       base::android::ToJavaArrayOfStrings(jni_env, double_keys);
   base::android::ScopedJavaLocalRef<jdoubleArray> java_double_values =
-      base::android::ToJavaDoubleArray(jni_env, double_values,
-                                       std::size(double_values));
+      base::android::ToJavaDoubleArray(jni_env, double_values);
 
   base::android::ScopedJavaLocalRef<jobjectArray> java_string_keys =
       base::android::ToJavaArrayOfStrings(jni_env, string_keys);
@@ -96,14 +93,12 @@
   base::android::ScopedJavaLocalRef<jobjectArray> java_time_keys =
       base::android::ToJavaArrayOfStrings(jni_env, time_keys);
   base::android::ScopedJavaLocalRef<jlongArray> java_time_values =
-      base::android::ToJavaLongArray(jni_env, time_values,
-                                     std::size(time_values));
+      base::android::ToJavaLongArray(jni_env, time_values);
 
   base::android::ScopedJavaLocalRef<jobjectArray> java_int64_keys =
       base::android::ToJavaArrayOfStrings(jni_env, int64_keys);
   base::android::ScopedJavaLocalRef<jlongArray> java_int64_values =
-      base::android::ToJavaLongArray(jni_env, int64_values,
-                                     std::size(int64_values));
+      base::android::ToJavaLongArray(jni_env, int64_values);
 
   base::android::ScopedJavaLocalRef<jobjectArray> java_url_keys =
       base::android::ToJavaArrayOfStrings(jni_env, url_keys);
diff --git a/components/services/quarantine/public/mojom/BUILD.gn b/components/services/quarantine/public/mojom/BUILD.gn
index dfa9d15..695f5475 100644
--- a/components/services/quarantine/public/mojom/BUILD.gn
+++ b/components/services/quarantine/public/mojom/BUILD.gn
@@ -11,5 +11,6 @@
     "//mojo/public/mojom/base",
     "//sandbox/policy/mojom",
     "//url/mojom:url_mojom_gurl",
+    "//url/mojom:url_mojom_origin",
   ]
 }
diff --git a/components/services/quarantine/public/mojom/quarantine.mojom b/components/services/quarantine/public/mojom/quarantine.mojom
index 6f4f3f47..fd76f3b0 100644
--- a/components/services/quarantine/public/mojom/quarantine.mojom
+++ b/components/services/quarantine/public/mojom/quarantine.mojom
@@ -7,6 +7,7 @@
 import "mojo/public/mojom/base/file_path.mojom";
 import "sandbox/policy/mojom/sandbox.mojom";
 import "url/mojom/url.mojom";
+import "url/mojom/origin.mojom";
 
 enum QuarantineFileResult {
   OK,             // Success.
@@ -29,9 +30,15 @@
 [ServiceSandbox=sandbox.mojom.Sandbox.kNoSandbox]
 interface Quarantine {
 
+  // Quarantine a file that was downloaded from the internet. This method
+  // will apply platform-dependent annotations to the file to indicate that
+  // it came from the internet, and what URL(s) led to the file. For more
+  // details, see the documentation in
+  // //components/services/quarantine/quarantine.h.
  QuarantineFile(mojo_base.mojom.FilePath full_path,
                 url.mojom.Url source_url,
                 url.mojom.Url referrer_url,
+                url.mojom.Origin? request_initiator,
                 string client_guid)
      => (QuarantineFileResult result);
 };
diff --git a/components/services/quarantine/quarantine.cc b/components/services/quarantine/quarantine.cc
index 994fc0e5f..c593d60 100644
--- a/components/services/quarantine/quarantine.cc
+++ b/components/services/quarantine/quarantine.cc
@@ -13,6 +13,7 @@
 void QuarantineFile(const base::FilePath& file,
                     const GURL& source_url,
                     const GURL& referrer_url,
+                    const std::optional<url::Origin>& request_initiator,
                     const std::string& client_guid,
                     mojom::Quarantine::QuarantineFileCallback callback) {
   std::move(callback).Run(QuarantineFileResult::OK);
diff --git a/components/services/quarantine/quarantine.h b/components/services/quarantine/quarantine.h
index 2e89789..d882a7b 100644
--- a/components/services/quarantine/quarantine.h
+++ b/components/services/quarantine/quarantine.h
@@ -58,6 +58,9 @@
 //   |source_url|: URL from which the file content was downloaded. This is empty
 //     for off-the-record download.
 //   |referrer_url|: Referring URL. This is empty for off-the-record download.
+//   `request_initiator`: Origin initiating the request. This is meant to
+//     replace the source URL when the source URL is not suitable for use in an
+//     annotation (e.g. a data URL).
 //   |client_guid|: Only used on Windows. Identifies the client application
 //     that downloaded the file.
 //   |callback|: Will be called with the quarantine result on completion.
@@ -70,6 +73,7 @@
 void QuarantineFile(const base::FilePath& file,
                     const GURL& source_url,
                     const GURL& referrer_url,
+                    const std::optional<url::Origin>& request_initiator,
                     const std::string& client_guid,
                     mojom::Quarantine::QuarantineFileCallback callback);
 
diff --git a/components/services/quarantine/quarantine_chromeos.cc b/components/services/quarantine/quarantine_chromeos.cc
index 19b3d9e8..2f453f5 100644
--- a/components/services/quarantine/quarantine_chromeos.cc
+++ b/components/services/quarantine/quarantine_chromeos.cc
@@ -27,6 +27,7 @@
 void QuarantineFile(const base::FilePath& file,
                     const GURL& source_url_unsafe,
                     const GURL& referrer_url_unsafe,
+                    const std::optional<url::Origin>& request_initiator,
                     const std::string& client_guid,
                     mojom::Quarantine::QuarantineFileCallback callback) {
   if (!chromeos::DlpClient::Get() || !chromeos::DlpClient::Get()->IsAlive()) {
diff --git a/components/services/quarantine/quarantine_impl.cc b/components/services/quarantine/quarantine_impl.cc
index dacc0bc..4570284 100644
--- a/components/services/quarantine/quarantine_impl.cc
+++ b/components/services/quarantine/quarantine_impl.cc
@@ -34,6 +34,7 @@
     const base::FilePath& full_path,
     const GURL& source_url,
     const GURL& referrer_url,
+    const std::optional<url::Origin>& request_initiator,
     const std::string& client_guid,
     mojom::Quarantine::QuarantineFileCallback callback) {
 #if BUILDFLAG(IS_MAC)
@@ -50,7 +51,7 @@
       FROM_HERE,
       base::BindOnce(
           &quarantine::QuarantineFile, full_path, source_url, referrer_url,
-          client_guid,
+          request_initiator, client_guid,
           base::BindOnce(&ReplyToCallback,
                          base::SingleThreadTaskRunner::GetCurrentDefault(),
                          std::move(callback))));
diff --git a/components/services/quarantine/quarantine_impl.h b/components/services/quarantine/quarantine_impl.h
index b282cbf..b44a211 100644
--- a/components/services/quarantine/quarantine_impl.h
+++ b/components/services/quarantine/quarantine_impl.h
@@ -33,6 +33,7 @@
       const base::FilePath& full_path,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       const std::string& client_guid,
       mojom::Quarantine::QuarantineFileCallback callback) override;
 
diff --git a/components/services/quarantine/quarantine_mac.mm b/components/services/quarantine/quarantine_mac.mm
index 4b560cc2..d2db794 100644
--- a/components/services/quarantine/quarantine_mac.mm
+++ b/components/services/quarantine/quarantine_mac.mm
@@ -96,6 +96,7 @@
 void QuarantineFile(const base::FilePath& file,
                     const GURL& source_url_unsafe,
                     const GURL& referrer_url_unsafe,
+                    const std::optional<url::Origin>& request_initiator,
                     const std::string& client_guid,
                     mojom::Quarantine::QuarantineFileCallback callback) {
   if (!base::PathExists(file)) {
@@ -111,6 +112,9 @@
 
   GURL source_url = SanitizeUrlForQuarantine(source_url_unsafe);
   GURL referrer_url = SanitizeUrlForQuarantine(referrer_url_unsafe);
+  if (source_url.is_empty() && request_initiator.has_value()) {
+    source_url = SanitizeUrlForQuarantine(request_initiator->GetURL());
+  }
 
   // Don't consider it an error if we fail to add origin metadata.
   AddOriginMetadataToFile(file, source_url, referrer_url);
diff --git a/components/services/quarantine/quarantine_mac_unittest.mm b/components/services/quarantine/quarantine_mac_unittest.mm
index 40975a11..242400e 100644
--- a/components/services/quarantine/quarantine_mac_unittest.mm
+++ b/components/services/quarantine/quarantine_mac_unittest.mm
@@ -26,9 +26,11 @@
 namespace quarantine {
 namespace {
 
-void CheckQuarantineResult(QuarantineFileResult result,
+void CheckQuarantineResult(base::OnceClosure quit_closure,
+                           QuarantineFileResult result,
                            QuarantineFileResult expected_result) {
   EXPECT_EQ(expected_result, result);
+  std::move(quit_closure).Run();
 }
 
 class QuarantineMacTest : public testing::Test {
@@ -69,23 +71,37 @@
 };
 
 TEST_F(QuarantineMacTest, CheckMetadataSetCorrectly) {
-  QuarantineFile(
-      test_file_, source_url_, referrer_url_, "",
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  QuarantineFile(test_file_, source_url_, referrer_url_,
+                 /*request_initiator=*/std::nullopt, "",
+                 base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                                QuarantineFileResult::OK));
+  run_loop.Run();
   EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
 }
 
 TEST_F(QuarantineMacTest, SetMetadataMultipleTimes) {
-  GURL dummy_url("http://www.dummy.example.com");
-  QuarantineFile(
-      test_file_, source_url_, referrer_url_, "",
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  QuarantineFile(
-      test_file_, dummy_url, dummy_url, "",
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
+  {
+    base::RunLoop run_loop;
+    QuarantineFile(
+        test_file_, source_url_, referrer_url_,
+        /*request_initiator=*/std::nullopt, "",
+        base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                       QuarantineFileResult::OK));
+    run_loop.Run();
+  }
+
+  {
+    base::RunLoop run_loop;
+    GURL dummy_url("http://www.dummy.example.com");
+    QuarantineFile(
+        test_file_, dummy_url, dummy_url,
+        /*request_initiator=*/std::nullopt, "",
+        base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                       QuarantineFileResult::OK));
+    run_loop.Run();
+    EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
+  }
 }
 
 TEST_F(QuarantineMacTest, IsFileQuarantined_NoFile) {
@@ -99,20 +115,24 @@
 }
 
 TEST_F(QuarantineMacTest, IsFileQuarantined_SourceUrlOnly) {
-  QuarantineFile(
-      test_file_, source_url_, GURL(), std::string(),
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  QuarantineFile(test_file_, source_url_, GURL(),
+                 /*request_initiator=*/std::nullopt, std::string(),
+                 base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                                QuarantineFileResult::OK));
+  run_loop.Run();
   EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, GURL()));
   EXPECT_TRUE(IsFileQuarantined(test_file_, GURL(), GURL()));
   EXPECT_TRUE(IsFileQuarantined(test_file_, GURL(), referrer_url_));
 }
 
 TEST_F(QuarantineMacTest, IsFileQuarantined_FullMetadata) {
-  QuarantineFile(
-      test_file_, source_url_, referrer_url_, std::string(),
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  QuarantineFile(test_file_, source_url_, referrer_url_,
+                 /*request_initiator=*/std::nullopt, std::string(),
+                 base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                                QuarantineFileResult::OK));
+  run_loop.Run();
   EXPECT_TRUE(IsFileQuarantined(test_file_, GURL(), GURL()));
   EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, GURL()));
   EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
@@ -120,24 +140,28 @@
 }
 
 TEST_F(QuarantineMacTest, IsFileQuarantined_Sanitize) {
+  base::RunLoop run_loop;
   GURL host_url{"https://user:pass@example.com/foo/bar?x#y"};
   GURL host_url_clean{"https://example.com/foo/bar?x#y"};
   GURL referrer_url{"https://user:pass@example.com/foo/index?x#y"};
   GURL referrer_url_clean{"https://example.com/foo/index?x#y"};
 
-  QuarantineFile(
-      test_file_, host_url, referrer_url, std::string(),
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  base::RunLoop().RunUntilIdle();
+  QuarantineFile(test_file_, host_url, referrer_url,
+                 /*request_initiator=*/std::nullopt, std::string(),
+                 base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                                QuarantineFileResult::OK));
+  run_loop.Run();
   EXPECT_TRUE(
       IsFileQuarantined(test_file_, host_url_clean, referrer_url_clean));
 }
 
 TEST_F(QuarantineMacTest, IsFileQuarantined_AgentBundleIdentifier) {
-  QuarantineFile(
-      test_file_, source_url_, referrer_url_, "",
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  QuarantineFile(test_file_, source_url_, referrer_url_,
+                 /*request_initiator=*/std::nullopt, "",
+                 base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                                QuarantineFileResult::OK));
+  run_loop.Run();
 
   NSDictionary* properties = GetQuarantineProperties(test_file_);
   ASSERT_TRUE(properties);
@@ -157,10 +181,12 @@
 }
 
 TEST_F(QuarantineMacTest, NoWhereFromsKeyIfNoURLs) {
-  QuarantineFile(
-      test_file_, GURL(), GURL(), std::string(),
-      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  QuarantineFile(test_file_, GURL(), GURL(), /*request_initiator=*/std::nullopt,
+                 std::string(),
+                 base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                                QuarantineFileResult::OK));
+  run_loop.Run();
 
   NSString* file_path = base::apple::FilePathToNSString(test_file_);
   ASSERT_NE(nullptr, file_path);
@@ -178,5 +204,18 @@
   EXPECT_FALSE(attr);
 }
 
+TEST_F(QuarantineMacTest, RequestInitiatorReplacesSourceUrl) {
+  base::RunLoop run_loop;
+  QuarantineFile(test_file_, GURL("data://text/html,payload"), referrer_url_,
+                 /*request_initiator=*/
+                 url::Origin::Create(GURL("http://www.source.example.com/")),
+                 "",
+                 base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
+                                QuarantineFileResult::OK));
+  run_loop.Run();
+  EXPECT_TRUE(IsFileQuarantined(
+      test_file_, GURL("http://www.source.example.com/"), referrer_url_));
+}
+
 }  // namespace
 }  // namespace quarantine
diff --git a/components/services/quarantine/quarantine_service_unittest.cc b/components/services/quarantine/quarantine_service_unittest.cc
index 00b155e..d2d539d 100644
--- a/components/services/quarantine/quarantine_service_unittest.cc
+++ b/components/services/quarantine/quarantine_service_unittest.cc
@@ -59,7 +59,8 @@
 
   base::RunLoop run_loop;
   quarantine_->QuarantineFile(
-      test_file, GURL(kInternetURL), GURL(kInternetReferrerURL), std::string(),
+      test_file, GURL(kInternetURL), GURL(kInternetReferrerURL),
+      /*request_initiator=*/std::nullopt, std::string(),
       base::BindOnce(&QuarantineServiceTest::OnFileQuarantined,
                      base::Unretained(this), test_file,
                      run_loop.QuitClosure()));
diff --git a/components/services/quarantine/quarantine_unittest.cc b/components/services/quarantine/quarantine_unittest.cc
index 345ebd6..8f9e8c4e 100644
--- a/components/services/quarantine/quarantine_unittest.cc
+++ b/components/services/quarantine/quarantine_unittest.cc
@@ -64,7 +64,8 @@
 TEST_F(QuarantineTest, FileCanBeOpenedForReadAfterAnnotation) {
   base::FilePath test_file = GetTestFilePath();
   QuarantineFile(
-      test_file, GURL(kInternetURL), GURL(kInternetReferrerURL), kTestGUID,
+      test_file, GURL(kInternetURL), GURL(kInternetReferrerURL),
+      /*request_initiator=*/std::nullopt, kTestGUID,
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -76,7 +77,7 @@
 TEST_F(QuarantineTest, FileCanBeAnnotatedWithNoGUID) {
   QuarantineFile(
       GetTestFilePath(), GURL(kInternetURL), GURL(kInternetReferrerURL),
-      std::string(),
+      /*request_initiator=*/std::nullopt, std::string(),
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 }
diff --git a/components/services/quarantine/quarantine_win.cc b/components/services/quarantine/quarantine_win.cc
index 545552a..d51aee5a 100644
--- a/components/services/quarantine/quarantine_win.cc
+++ b/components/services/quarantine/quarantine_win.cc
@@ -225,6 +225,7 @@
 void QuarantineFile(const base::FilePath& file,
                     const GURL& source_url_unsafe,
                     const GURL& referrer_url_unsafe,
+                    const std::optional<url::Origin>& request_initiator,
                     const std::string& client_guid,
                     mojom::Quarantine::QuarantineFileCallback callback) {
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
@@ -245,6 +246,10 @@
   }
 
   GURL source_url = SanitizeUrlForQuarantine(source_url_unsafe);
+  if (source_url.is_empty() && request_initiator.has_value()) {
+    source_url = SanitizeUrlForQuarantine(request_initiator->GetURL());
+  }
+
   GURL referrer_url = SanitizeUrlForQuarantine(referrer_url_unsafe);
 
   if (file_size == 0 || IsEqualGUID(guid, GUID_NULL)) {
diff --git a/components/services/quarantine/quarantine_win_unittest.cc b/components/services/quarantine/quarantine_win_unittest.cc
index fa770d4..e20252be 100644
--- a/components/services/quarantine/quarantine_win_unittest.cc
+++ b/components/services/quarantine/quarantine_win_unittest.cc
@@ -187,7 +187,7 @@
 TEST_F(QuarantineWinTest, MissingFile) {
   QuarantineFile(GetTempDir().AppendASCII("does-not-exist.exe"),
                  GURL(kDummySourceUrl), GURL(kDummyReferrerUrl),
-                 kDummyClientGuid,
+                 /*request_initiator=*/std::nullopt, kDummyClientGuid,
                  base::BindOnce(&CheckQuarantineResult,
                                 QuarantineFileResult::FILE_MISSING));
   base::RunLoop().RunUntilIdle();
@@ -210,7 +210,8 @@
     ASSERT_TRUE(CreateFile(test_file));
 
     QuarantineFile(
-        test_file, GURL(source_url), GURL(), kDummyClientGuid,
+        test_file, GURL(source_url), GURL(), /*request_initiator=*/std::nullopt,
+        kDummyClientGuid,
         base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
     base::RunLoop().RunUntilIdle();
 
@@ -237,7 +238,8 @@
     ASSERT_TRUE(CreateFile(test_file));
 
     QuarantineFile(
-        test_file, GURL(source_url), GURL(), kDummyClientGuid,
+        test_file, GURL(source_url), GURL(), /*request_initiator=*/std::nullopt,
+        kDummyClientGuid,
         base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
     base::RunLoop().RunUntilIdle();
 
@@ -270,7 +272,7 @@
     ASSERT_TRUE(CreateFile(test_file));
     QuarantineFile(
         test_file, GURL("http://example.com/good"), GURL(referrer_url),
-        kDummyClientGuid,
+        /*request_initiator=*/std::nullopt, kDummyClientGuid,
         base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
     base::RunLoop().RunUntilIdle();
 
@@ -293,7 +295,8 @@
   ASSERT_TRUE(CreateFile(test_file));
 
   QuarantineFile(
-      test_file, GURL(), GURL(), kDummyClientGuid,
+      test_file, GURL(), GURL(), /*request_initiator=*/std::nullopt,
+      kDummyClientGuid,
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -314,7 +317,8 @@
   ASSERT_TRUE(base::WriteFile(test_file, ""));
 
   QuarantineFile(
-      test_file, net::FilePathToFileURL(test_file), GURL(), kDummyClientGuid,
+      test_file, net::FilePathToFileURL(test_file), GURL(),
+      /*request_initiator=*/std::nullopt, kDummyClientGuid,
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -336,7 +340,8 @@
   ASSERT_TRUE(CreateFile(test_file));
 
   QuarantineFile(
-      test_file, net::FilePathToFileURL(test_file), GURL(), std::string(),
+      test_file, net::FilePathToFileURL(test_file), GURL(),
+      /*request_initiator=*/std::nullopt, std::string(),
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -359,7 +364,8 @@
   std::string source_url("http://example.com/");
   source_url.append(INTERNET_MAX_URL_LENGTH * 2, 'a');
   QuarantineFile(
-      test_file, GURL(source_url), GURL(), std::string(),
+      test_file, GURL(source_url), GURL(), /*request_initiator=*/std::nullopt,
+      std::string(),
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -380,7 +386,8 @@
 
   ASSERT_TRUE(CreateFile(test_file));
   QuarantineFile(
-      test_file, source_url, GURL(), kDummyClientGuid,
+      test_file, source_url, GURL(), /*request_initiator=*/std::nullopt,
+      kDummyClientGuid,
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -398,7 +405,8 @@
   ASSERT_TRUE(CreateFile(test_file));
 
   // Files from a restricted site are deleted.
-  QuarantineFile(test_file, source_url, GURL(), kDummyClientGuid,
+  QuarantineFile(test_file, source_url, GURL(),
+                 /*request_initiator=*/std::nullopt, kDummyClientGuid,
                  base::BindOnce(&CheckQuarantineResult,
                                 QuarantineFileResult::BLOCKED_BY_POLICY));
   base::RunLoop().RunUntilIdle();
@@ -417,7 +425,8 @@
   // Ensure the file already contains a zone identifier.
   ASSERT_TRUE(AddInternetZoneIdentifierDirectly(test_file));
   QuarantineFile(
-      test_file, source_url, GURL(), kDummyClientGuid,
+      test_file, source_url, GURL(), /*request_initiator=*/std::nullopt,
+      kDummyClientGuid,
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -439,7 +448,8 @@
   ASSERT_TRUE(AddInternetZoneIdentifierDirectly(test_file));
 
   // Files from a restricted site are deleted.
-  QuarantineFile(test_file, source_url, GURL(), kDummyClientGuid,
+  QuarantineFile(test_file, source_url, GURL(),
+                 /*request_initiator=*/std::nullopt, kDummyClientGuid,
                  base::BindOnce(&CheckQuarantineResult,
                                 QuarantineFileResult::BLOCKED_BY_POLICY));
   base::RunLoop().RunUntilIdle();
@@ -463,7 +473,8 @@
 
   // An invalid GUID will cause QuarantineFile() to apply the MOTW directly.
   QuarantineFile(
-      test_file, host_url, referrer_url, std::string(),
+      test_file, host_url, referrer_url, /*request_initiator=*/std::nullopt,
+      std::string(),
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
@@ -484,11 +495,26 @@
       base::StrCat({"https://", GetInternetSite(), "/folder/index?x#y"}));
 
   QuarantineFile(
-      test_file, host_url, referrer_url, kDummyClientGuid,
+      test_file, host_url, referrer_url, /*request_initiator=*/std::nullopt,
+      kDummyClientGuid,
       base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(IsFileQuarantined(test_file, host_url_clean, referrer_url_clean));
 }
 
+TEST_F(QuarantineWinTest, RequestInitiatorReplacesSourceUrl) {
+  base::FilePath test_file = GetTempDir().AppendASCII("foo.exe");
+  ASSERT_TRUE(CreateFile(test_file));
+
+  GURL host_url(base::StrCat({"https://", GetInternetSite(), "/"}));
+  QuarantineFile(
+      test_file, GURL("data://text/html,payload"), GURL(),
+      url::Origin::Create(host_url), kDummyClientGuid,
+      base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(IsFileQuarantined(test_file, host_url, GURL()));
+}
+
 }  // namespace quarantine
diff --git a/components/signin/public/android/BUILD.gn b/components/signin/public/android/BUILD.gn
index b6c64b4..d4d69ff 100644
--- a/components/signin/public/android/BUILD.gn
+++ b/components/signin/public/android/BUILD.gn
@@ -7,6 +7,7 @@
     "$google_play_services_package:google_play_services_base_java",
     "//base:base_cached_flags_java",
     "//base:base_java",
+    "//base:service_loader_java",
     "//build/android:build_java",
     "//components/externalauth/android:java",
     "//net/android:net_java",
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
index 54e5c81..1ad5fe9 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
@@ -4,81 +4,55 @@
 package org.chromium.components.signin;
 
 import androidx.annotation.AnyThread;
-import androidx.annotation.MainThread;
 import androidx.annotation.VisibleForTesting;
 
 import org.jni_zero.CalledByNative;
 
-import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
-
-import java.util.concurrent.atomic.AtomicReference;
+import org.chromium.base.ResettersForTesting;
+import org.chromium.base.ServiceLoaderUtil;
 
 /**
- * AccountManagerFacadeProvider is intended to group all the
- * AccountManagerFacade instance manipulation methods in one place.
+ * AccountManagerFacadeProvider is intended to group all the AccountManagerFacade instance
+ * manipulation methods in one place.
  */
 public class AccountManagerFacadeProvider {
-    private static final String TAG = "AccManagerProvider";
-    private static final AtomicReference<AccountManagerFacade> sAtomicInstance =
-            new AtomicReference<>();
-    private static AccountManagerFacade sInstance;
-    private static AccountManagerFacade sTestingInstance;
+    // Holder needed to avoid init on instrumentation thread in tests.
+    private static class Holder {
+        private static final AccountManagerFacade INSTANCE;
+
+        static {
+            AccountManagerDelegate delegate =
+                    ServiceLoaderUtil.maybeCreate(AccountManagerDelegate.class);
+            if (delegate == null) {
+                delegate = new SystemAccountManagerDelegate();
+            }
+            INSTANCE = new AccountManagerFacadeImpl(delegate);
+        }
+    }
+
+    private static AccountManagerFacade sInstanceForTesting;
 
     private AccountManagerFacadeProvider() {}
 
-    /**
-     * Sets AccountManagerFacade singleton instance. Can only be called once.
-     * Tests can override the instance with {@link #setInstanceForTests}.
-     *
-     */
-    @MainThread
-    public static void setInstance(AccountManagerFacade accountManagerFacade) {
-        ThreadUtils.assertOnUiThread();
-        if (sInstance != null) {
-            throw new IllegalStateException("AccountManagerFacade is already initialized!");
-        }
-        sInstance = accountManagerFacade;
-        if (sTestingInstance != null) return;
-        sAtomicInstance.set(sInstance);
-    }
-
     /** Sets the test instance. */
     @VisibleForTesting
     @AnyThread
     public static void setInstanceForTests(AccountManagerFacade accountManagerFacade) {
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    sTestingInstance = accountManagerFacade;
-                    sAtomicInstance.set(sTestingInstance);
-                });
-    }
-
-    /** Resets the test instance set with {@link #setInstanceForTests}. */
-    @VisibleForTesting
-    @AnyThread
-    public static void resetInstanceForTests() {
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    sTestingInstance = null;
-                    sAtomicInstance.set(sInstance);
-                    Log.d(TAG, "reset AccountManagerFacade test instance");
-                });
+        sInstanceForTesting = accountManagerFacade;
+        ResettersForTesting.register(() -> sInstanceForTesting = null);
     }
 
     /**
-     * Singleton instance getter. Singleton must be initialized before calling this by
-     * {@link #setInstance} or {@link #setInstanceForTests}.
+     * Singleton instance getter.
      *
      * @return a singleton instance
      */
     @AnyThread
     @CalledByNative
     public static AccountManagerFacade getInstance() {
-        AccountManagerFacade instance = sAtomicInstance.get();
-        if (instance == null) {
-            throw new IllegalStateException("AccountManagerFacade is not yet initialized!");
+        if (sInstanceForTesting != null) {
+            return sInstanceForTesting;
         }
-        return instance;
+        return Holder.INSTANCE;
     }
 }
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java
index 394bf911b..c942f739 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java
@@ -13,7 +13,6 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -66,11 +65,6 @@
                 });
     }
 
-    @After
-    public void tearDown() {
-        AccountManagerFacadeProvider.resetInstanceForTests();
-    }
-
     @Test
     @SmallTest
     public void testIsCachePopulated() throws InterruptedException {
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesFetcherTestUtil.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesFetcherTestUtil.java
index 84ec507b..f1e6b78 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesFetcherTestUtil.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesFetcherTestUtil.java
@@ -41,7 +41,6 @@
     /** Restores the global state after the test completes. */
     @CalledByNative
     public void destroy() {
-        AccountManagerFacadeProvider.resetInstanceForTests();
         mMockFacade = null;
     }
 
diff --git a/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java b/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java
index b7892be..7174fcf5 100644
--- a/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java
+++ b/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java
@@ -487,11 +487,6 @@
                 originalToken.getToken());
     }
 
-    @Test(expected = IllegalStateException.class)
-    public void testAccountManagerFacadeProviderGetNullInstance() {
-        AccountManagerFacadeProvider.getInstance();
-    }
-
     @Test
     public void testGetAccountCapabilitiesResponseYes() throws Exception {
         AccountManagerFacade facade = new AccountManagerFacadeImpl(mDelegate);
diff --git a/components/signin/public/identity_manager/account_capabilities.cc b/components/signin/public/identity_manager/account_capabilities.cc
index 02ea4f5..8acfad8 100644
--- a/components/signin/public/identity_manager/account_capabilities.cc
+++ b/components/signin/public/identity_manager/account_capabilities.cc
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/signin/public/identity_manager/account_capabilities.h"
+
 #include <map>
 #include <string>
 #include <vector>
 
-#include "base/notreached.h"
-#include "components/signin/public/identity_manager/account_capabilities.h"
-
+#include "base/containers/heap_array.h"
 #include "base/no_destructor.h"
+#include "base/notreached.h"
 #include "components/signin/internal/identity_manager/account_capabilities_constants.h"
 #include "components/signin/public/identity_manager/tribool.h"
 
@@ -182,19 +183,19 @@
 
 base::android::ScopedJavaLocalRef<jobject>
 AccountCapabilities::ConvertToJavaAccountCapabilities(JNIEnv* env) const {
-  int capabilities_size = capabilities_map_.size();
+  const size_t num_caps = capabilities_map_.size();
   std::vector<std::string> capability_names;
-  auto capability_values = std::make_unique<bool[]>(capabilities_size);
-  int value_iterator = 0;
-  for (const auto& kv : capabilities_map_) {
-    capability_names.push_back(kv.first);
-    capability_values[value_iterator] = kv.second;
+  capability_names.reserve(num_caps);
+  auto capability_values = base::HeapArray<bool>::WithSize(num_caps);
+  size_t value_iterator = 0u;
+  for (const auto& [name, value] : capabilities_map_) {
+    capability_names.push_back(name);
+    capability_values[value_iterator] = value;
     value_iterator++;
   }
   return signin::Java_AccountCapabilities_Constructor(
       env, base::android::ToJavaArrayOfStrings(env, capability_names),
-      base::android::ToJavaBooleanArray(env, capability_values.get(),
-                                        capabilities_size));
+      base::android::ToJavaBooleanArray(env, capability_values));
 }
 #endif
 
diff --git a/components/subresource_filter/content/browser/BUILD.gn b/components/subresource_filter/content/browser/BUILD.gn
index 07b2672..0ab9b18 100644
--- a/components/subresource_filter/content/browser/BUILD.gn
+++ b/components/subresource_filter/content/browser/BUILD.gn
@@ -44,6 +44,7 @@
     "//base",
     "//components/content_settings/browser",
     "//components/content_settings/core/browser",
+    "//components/content_settings/core/browser:cookie_settings",
     "//components/content_settings/core/common",
     "//components/keyed_service/core",
     "//components/prefs:prefs",
@@ -113,6 +114,7 @@
     "//components/content_settings/browser",
     "//components/content_settings/browser:test_support",
     "//components/content_settings/core/browser",
+    "//components/content_settings/core/browser:cookie_settings",
     "//components/infobars/content",
     "//components/infobars/core",
     "//components/prefs:test_support",
diff --git a/components/subresource_filter/content/browser/DEPS b/components/subresource_filter/content/browser/DEPS
index 10cbb70..bfed2dde 100644
--- a/components/subresource_filter/content/browser/DEPS
+++ b/components/subresource_filter/content/browser/DEPS
@@ -16,6 +16,7 @@
   "+content/public/test",
   "+mojo/public",
   "+net/base",
+  "+net/cookies",
   "+services/metrics/public/cpp",
   "+services/network/public/mojom",
   "+ui/base",
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index e9741a8..f4221c4b 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -647,6 +647,7 @@
   return parent_filter
              ? std::make_unique<SafeBrowsingChildNavigationThrottle>(
                    navigation_handle, parent_filter,
+                   profile_interaction_manager_->AsWeakPtr(),
                    base::BindRepeating([](const GURL& url) {
                      return base::StringPrintf(
                          kDisallowChildFrameConsoleMessageFormat,
diff --git a/components/subresource_filter/content/browser/profile_interaction_manager.cc b/components/subresource_filter/content/browser/profile_interaction_manager.cc
index 8275315..a8f7d8f 100644
--- a/components/subresource_filter/content/browser/profile_interaction_manager.cc
+++ b/components/subresource_filter/content/browser/profile_interaction_manager.cc
@@ -179,6 +179,11 @@
   }
 }
 
+content_settings::CookieSettings*
+ProfileInteractionManager::GetCookieSettings() {
+  return profile_context_->cookie_settings();
+}
+
 content::WebContents* ProfileInteractionManager::GetWebContents() {
   CHECK(page_, base::NotFatalUntil::M129);
   CHECK(page_->IsPrimary(), base::NotFatalUntil::M129);
diff --git a/components/subresource_filter/content/browser/profile_interaction_manager.h b/components/subresource_filter/content/browser/profile_interaction_manager.h
index bdb0bb9..978976bc 100644
--- a/components/subresource_filter/content/browser/profile_interaction_manager.h
+++ b/components/subresource_filter/content/browser/profile_interaction_manager.h
@@ -21,6 +21,10 @@
 class WebContents;
 }  // namespace content
 
+namespace content_settings {
+class CookieSettings;
+}  // namespace content_settings
+
 namespace subresource_filter {
 
 class SubresourceFilterProfileContext;
@@ -39,6 +43,10 @@
   ProfileInteractionManager& operator=(const ProfileInteractionManager&) =
       delete;
 
+  base::WeakPtr<ProfileInteractionManager> AsWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
   void DidCreatePage(content::Page& page);
 
   // Invoked when the user has requested a reload of a page with blocked ads
@@ -68,6 +76,8 @@
   }
 #endif
 
+  content_settings::CookieSettings* GetCookieSettings();
+
  private:
   content::WebContents* GetWebContents();
 
@@ -86,6 +96,8 @@
 #if BUILDFLAG(IS_ANDROID)
   raw_ptr<AdsBlockedMessageDelegate> ads_blocked_message_delegate_;
 #endif
+
+  base::WeakPtrFactory<ProfileInteractionManager> weak_ptr_factory_{this};
 };
 
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.cc b/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.cc
index 60dc9b0..f9380d1 100644
--- a/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.cc
+++ b/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.cc
@@ -13,16 +13,32 @@
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/common/cookie_settings_base.h"
 #include "components/subresource_filter/content/browser/ad_tagging_utils.h"
+#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
 #include "components/subresource_filter/content/shared/browser/child_frame_navigation_filtering_throttle.h"
 #include "components/subresource_filter/core/browser/async_document_subresource_filter.h"
 #include "components/subresource_filter/core/common/common_features.h"
 #include "components/subresource_filter/core/common/time_measurements.h"
 #include "content/public/browser/navigation_handle.h"
+#include "net/cookies/static_cookie_policy.h"
 #include "third_party/blink/public/common/frame/frame_ad_evidence.h"
 #include "url/gurl.h"
 
+namespace {
+
+// Returns true iff the request is considered third-party.
+bool IsThirdPartyRequest(const GURL& url,
+                         const net::SiteForCookies& site_for_cookies) {
+  return net::StaticCookiePolicy(
+             net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES)
+             .CanAccessCookies(url, site_for_cookies) != net::OK;
+}
+
+}  // namespace
+
 namespace features {
 
 // Enables or disables performing SubresourceFilter checks from the Browser
@@ -38,6 +54,7 @@
 SafeBrowsingChildNavigationThrottle::SafeBrowsingChildNavigationThrottle(
     content::NavigationHandle* handle,
     AsyncDocumentSubresourceFilter* parent_frame_filter,
+    base::WeakPtr<ProfileInteractionManager> profile_interaction_manager,
     base::RepeatingCallback<std::string(const GURL& url)>
         disallow_message_callback,
     std::optional<blink::FrameAdEvidence> ad_evidence)
@@ -48,7 +65,8 @@
           base::FeatureList::IsEnabled(
               features::kSendCnameAliasesToSubresourceFilterFromBrowser),
           std::move(disallow_message_callback)),
-      ad_evidence_(std::move(ad_evidence)) {
+      ad_evidence_(std::move(ad_evidence)),
+      profile_interaction_manager_(profile_interaction_manager) {
   if (ad_evidence_.has_value()) {
     // Complete the ad evidence as it will be used to make best-effort tagging
     // decisions by request time for ongoing subframe navs.
@@ -88,14 +106,28 @@
   // allowed to get a response. As a result, we must defer while
   // we wait for the ruleset check to complete and pass handling the navigation
   // decision to the callback.
-  //
+  if (parent_frame_filter_->activation_state().activation_level ==
+      mojom::ActivationLevel::kEnabled) {
+    return true;
+  }
+
   // If `kTPCDAdHeuristicSubframeRequestTagging`, we always need to defer
   // navigation start to ensure we have the load policy calculated in order
   // to properly tag the navigation handle as an ad before it goes to the
   // network.
-  return parent_frame_filter_->activation_state().activation_level ==
-             mojom::ActivationLevel::kEnabled ||
-         base::FeatureList::IsEnabled(kTPCDAdHeuristicSubframeRequestTagging);
+  if (base::FeatureList::IsEnabled(kTPCDAdHeuristicSubframeRequestTagging)) {
+    // If `kCheckFor3pcException`, we only defer the navigation if a
+    // third-party cookie exceptions is applicable to it.
+    bool defer_for_tagging =
+        !kCheckFor3pcException.Get() || NavigationHasCookieException();
+    UMA_HISTOGRAM_BOOLEAN(
+        "PageLoad.FrameCounts.AdFrames.PerFrame.DeferredForTagging",
+        defer_for_tagging);
+
+    return defer_for_tagging;
+  }
+
+  return false;
 }
 
 void SafeBrowsingChildNavigationThrottle::
@@ -123,4 +155,34 @@
                                                         load_policy_);
 }
 
+bool SafeBrowsingChildNavigationThrottle::NavigationHasCookieException() const {
+  if (!profile_interaction_manager_) {
+    // This method informs whether navigations should be deferred for ad-tagging
+    // checks to be completed. Default to `true` so potentially affected
+    // navigations aren't missed.
+    return true;
+  }
+
+  net::IsolationInfo isolation_info = navigation_handle()->GetIsolationInfo();
+
+  if (!IsThirdPartyRequest(navigation_handle()->GetURL(),
+                           isolation_info.site_for_cookies())) {
+    return false;
+  }
+
+  using ThirdPartyCookieAllowMechanism =
+      content_settings::CookieSettingsBase::ThirdPartyCookieAllowMechanism;
+
+  ThirdPartyCookieAllowMechanism allow_mechanism =
+      profile_interaction_manager_->GetCookieSettings()
+          ->GetThirdPartyCookieAllowMechanism(
+              navigation_handle()->GetURL(), isolation_info.site_for_cookies(),
+              isolation_info.top_frame_origin()
+                  .value_or(url::Origin())
+                  .GetURL(),
+              net::CookieSettingOverrides(), nullptr);
+
+  return allow_mechanism != ThirdPartyCookieAllowMechanism::kNone;
+}
+
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.h b/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.h
index 433a965..2fcedfe 100644
--- a/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.h
+++ b/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle.h
@@ -8,6 +8,8 @@
 #include <optional>
 
 #include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "components/subresource_filter/content/shared/browser/child_frame_navigation_filtering_throttle.h"
 #include "third_party/blink/public/common/frame/frame_ad_evidence.h"
@@ -20,6 +22,7 @@
 namespace subresource_filter {
 
 class AsyncDocumentSubresourceFilter;
+class ProfileInteractionManager;
 
 // ChildFrameNavigationFilteringThrottle implementation for Safe Browsing.
 //
@@ -34,6 +37,7 @@
   SafeBrowsingChildNavigationThrottle(
       content::NavigationHandle* handle,
       AsyncDocumentSubresourceFilter* parent_frame_filter,
+      base::WeakPtr<ProfileInteractionManager> profile_interaction_manager,
       base::RepeatingCallback<std::string(const GURL& url)>
           disallow_message_callback,
       std::optional<blink::FrameAdEvidence> ad_evidence);
@@ -51,9 +55,13 @@
   bool ShouldDeferNavigation() const override;
   void OnReadyToResumeNavigationWithLoadPolicy() override;
   void NotifyLoadPolicy() const override;
+  bool NavigationHasCookieException() const;
 
   std::optional<blink::FrameAdEvidence> ad_evidence_;
 
+  // May be null. If non-null, must outlive this class.
+  base::WeakPtr<ProfileInteractionManager> profile_interaction_manager_;
+
   base::WeakPtrFactory<SafeBrowsingChildNavigationThrottle> weak_ptr_factory_{
       this};
 };
diff --git a/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle_unittest.cc b/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle_unittest.cc
index 899b742..c2240a0 100644
--- a/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/safe_browsing_child_navigation_throttle_unittest.cc
@@ -8,6 +8,7 @@
 #include <optional>
 
 #include "base/functional/bind.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "components/subresource_filter/content/shared/browser/child_frame_navigation_test_utils.h"
@@ -20,6 +21,8 @@
 
 namespace subresource_filter {
 
+class ProfileInteractionManager;
+
 class SafeBrowsingChildNavigationThrottleTest
     : public ChildFrameNavigationFilteringThrottleTestHarness {
  public:
@@ -41,6 +44,8 @@
     if (parent_filter_) {
       auto throttle = std::make_unique<SafeBrowsingChildNavigationThrottle>(
           navigation_handle, parent_filter_.get(),
+          /*profile_interaction_manager=*/
+          base::WeakPtr<ProfileInteractionManager>(),
           base::BindRepeating([](const GURL& filtered_url) {
             return base::StringPrintf(
                 kDisallowChildFrameConsoleMessageFormat,
diff --git a/components/subresource_filter/content/browser/subresource_filter_profile_context.cc b/components/subresource_filter/content/browser/subresource_filter_profile_context.cc
index eaa3dda..f692495 100644
--- a/components/subresource_filter/content/browser/subresource_filter_profile_context.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_profile_context.cc
@@ -6,18 +6,21 @@
 
 #include "base/check.h"
 #include "base/not_fatal_until.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/subresource_filter/content/browser/ads_intervention_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
 
 namespace subresource_filter {
 
 SubresourceFilterProfileContext::SubresourceFilterProfileContext(
-    HostContentSettingsMap* settings_map)
+    HostContentSettingsMap* settings_map,
+    scoped_refptr<content_settings::CookieSettings> cookie_settings)
     : settings_manager_(
           std::make_unique<SubresourceFilterContentSettingsManager>(
               settings_map)),
       ads_intervention_manager_(
-          std::make_unique<AdsInterventionManager>(settings_manager_.get())) {}
+          std::make_unique<AdsInterventionManager>(settings_manager_.get())),
+      cookie_settings_(std::move(cookie_settings)) {}
 
 SubresourceFilterProfileContext::~SubresourceFilterProfileContext() {}
 
@@ -33,6 +36,7 @@
   // sure they are reset in the right order to avoid holding a dangling pointer.
   ads_intervention_manager_.reset();
   settings_manager_.reset();
+  cookie_settings_.reset();
 }
 
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/subresource_filter_profile_context.h b/components/subresource_filter/content/browser/subresource_filter_profile_context.h
index e76f4d3..3fb3331 100644
--- a/components/subresource_filter/content/browser/subresource_filter_profile_context.h
+++ b/components/subresource_filter/content/browser/subresource_filter_profile_context.h
@@ -7,10 +7,15 @@
 
 #include <memory>
 
+#include "base/memory/scoped_refptr.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class HostContentSettingsMap;
 
+namespace content_settings {
+class CookieSettings;
+}  // namespace content_settings
+
 namespace subresource_filter {
 
 class SubresourceFilterContentSettingsManager;
@@ -30,7 +35,8 @@
   };
 
   explicit SubresourceFilterProfileContext(
-      HostContentSettingsMap* settings_map);
+      HostContentSettingsMap* settings_map,
+      scoped_refptr<content_settings::CookieSettings> cookie_settings);
 
   SubresourceFilterProfileContext(const SubresourceFilterProfileContext&) =
       delete;
@@ -47,6 +53,10 @@
     return ads_intervention_manager_.get();
   }
 
+  content_settings::CookieSettings* cookie_settings() {
+    return cookie_settings_.get();
+  }
+
   // Can be used to attach an embedder-level object to this object. Can only be
   // invoked once. |embedder_data| will be destroyed before the other objects
   // owned by this object, and thus it can safely depend on those other objects.
@@ -62,6 +72,8 @@
   // navigations.
   std::unique_ptr<AdsInterventionManager> ads_intervention_manager_;
 
+  scoped_refptr<content_settings::CookieSettings> cookie_settings_;
+
   // NOTE: Declared after the objects above to ensure that it is destroyed
   // before them.
   std::unique_ptr<EmbedderData> embedder_data_;
diff --git a/components/subresource_filter/content/browser/throttle_manager_test_support.cc b/components/subresource_filter/content/browser/throttle_manager_test_support.cc
index ac7f60a5..f30362a1 100644
--- a/components/subresource_filter/content/browser/throttle_manager_test_support.cc
+++ b/components/subresource_filter/content/browser/throttle_manager_test_support.cc
@@ -6,6 +6,7 @@
 
 #include "components/content_settings/browser/page_specific_content_settings.h"
 #include "components/content_settings/browser/test_page_specific_content_settings_delegate.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/infobars/content/content_infobar_manager.h"
 #include "components/safe_browsing/core/browser/db/database_manager.h"
@@ -18,11 +19,18 @@
     content::WebContents* web_contents) {
   // Set up the state that's required by ProfileInteractionManager.
   HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
+  content_settings::CookieSettings::RegisterProfilePrefs(prefs_.registry());
   settings_map_ = base::MakeRefCounted<HostContentSettingsMap>(
-      &prefs_, false /* is_off_the_record */, false /* store_last_modified */,
-      false /* restore_session */, false /* should_record_metrics */);
-  profile_context_ =
-      std::make_unique<SubresourceFilterProfileContext>(settings_map_.get());
+      &prefs_, /*is_off_the_record=*/false, /*store_last_modified=*/false,
+      /*restore_session=*/false, /*should_record_metrics=*/false);
+  cookie_settings_ = base::MakeRefCounted<content_settings::CookieSettings>(
+      settings_map_.get(), &prefs_,
+      /*tracking_protection_settings=*/nullptr,
+      /*is_incognito=*/false,
+      content_settings::CookieSettings::NoFedCmSharingPermissionsCallback(),
+      /*tpcd_metadata_manager=*/nullptr, "");
+  profile_context_ = std::make_unique<SubresourceFilterProfileContext>(
+      settings_map_.get(), cookie_settings_.get());
 
   // ProfileInteractionManager assumes that this object is present in the
   // context of the passed-in WebContents.
diff --git a/components/subresource_filter/content/browser/throttle_manager_test_support.h b/components/subresource_filter/content/browser/throttle_manager_test_support.h
index 853feca8e..ebc1a64f 100644
--- a/components/subresource_filter/content/browser/throttle_manager_test_support.h
+++ b/components/subresource_filter/content/browser/throttle_manager_test_support.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/memory/scoped_refptr.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 
 class HostContentSettingsMap;
@@ -16,6 +17,10 @@
 class WebContents;
 }
 
+namespace content_settings {
+class CookieSettings;
+}
+
 namespace subresource_filter {
 
 class SubresourceFilterProfileContext;
@@ -42,6 +47,7 @@
  private:
   sync_preferences::TestingPrefServiceSyncable prefs_;
   scoped_refptr<HostContentSettingsMap> settings_map_;
+  scoped_refptr<content_settings::CookieSettings> cookie_settings_;
   std::unique_ptr<SubresourceFilterProfileContext> profile_context_;
 };
 
diff --git a/components/subresource_filter/content/shared/browser/child_frame_navigation_test_utils.cc b/components/subresource_filter/content/shared/browser/child_frame_navigation_test_utils.cc
index eee11f1..8dd2db1 100644
--- a/components/subresource_filter/content/shared/browser/child_frame_navigation_test_utils.cc
+++ b/components/subresource_filter/content/shared/browser/child_frame_navigation_test_utils.cc
@@ -75,6 +75,7 @@
 void ChildFrameNavigationFilteringThrottleTestHarness::TearDown() {
   dealer_handle_.reset();
   ruleset_handle_.reset();
+  navigation_simulator_.reset();
   parent_filter_.reset();
   RunUntilIdle();
   content::RenderViewHostTestHarness::TearDown();
diff --git a/components/subresource_filter/core/common/common_features.cc b/components/subresource_filter/core/common/common_features.cc
index 48638aa..c5a0914 100644
--- a/components/subresource_filter/core/common/common_features.cc
+++ b/components/subresource_filter/core/common/common_features.cc
@@ -12,4 +12,8 @@
              "TPCDAdHeuristicSubframeRequestTagging",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+const base::FeatureParam<bool> kCheckFor3pcException{
+    &kTPCDAdHeuristicSubframeRequestTagging, /*name=*/"check_exceptions",
+    /*default_value=*/true};
+
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/core/common/common_features.h b/components/subresource_filter/core/common/common_features.h
index 2eb8ff1..3464003 100644
--- a/components/subresource_filter/core/common/common_features.h
+++ b/components/subresource_filter/core/common/common_features.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_COMMON_FEATURES_H_
 
 #include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
 
 namespace subresource_filter {
 
@@ -22,6 +23,11 @@
 // start.
 BASE_DECLARE_FEATURE(kTPCDAdHeuristicSubframeRequestTagging);
 
+// Param which governs whether to check if a third-party cookie exception
+// applies to a network request before removing the optimization which
+// parallelizes its start with filter list checks.
+extern const base::FeatureParam<bool> kCheckFor3pcException;
+
 // Param which governs how much to delay non-secure (i.e. http) subresources for
 // DelayUnsafeAds.
 extern const char kInsecureDelayParam[];
diff --git a/components/translate/content/android/translate_message.cc b/components/translate/content/android/translate_message.cc
index 8ed4381d..5150762 100644
--- a/components/translate/content/android/translate_message.cc
+++ b/components/translate/content/android/translate_message.cc
@@ -20,6 +20,7 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/containers/contains.h"
+#include "base/containers/heap_array.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
 #include "base/metrics/field_trial_params.h"
@@ -536,13 +537,15 @@
   return bridge_->ConstructMenuItemArray(
       env,
       base::android::ToJavaArrayOfStrings(env,
-                                          base::make_span(titles, item_count)),
+                                          base::span(titles).first(item_count)),
       base::android::ToJavaArrayOfStrings(
-          env, base::make_span(subtitles, item_count)),
-      base::android::ToJavaBooleanArray(env, has_checkmarks, item_count),
-      base::android::ToJavaIntArray(env, overflow_menu_item_ids, item_count),
+          env, base::span(subtitles).first(item_count)),
+      base::android::ToJavaBooleanArray(
+          env, base::span(has_checkmarks).first(item_count)),
+      base::android::ToJavaIntArray(
+          env, base::span(overflow_menu_item_ids).first(item_count)),
       base::android::ToJavaArrayOfStrings(
-          env, base::make_span(language_codes, item_count)));
+          env, base::span(language_codes).first(item_count)));
 }
 
 base::android::ScopedJavaLocalRef<jobjectArray>
@@ -728,7 +731,7 @@
       base::android::ToJavaArrayOfStrings(env, subtitles),
       /*has_checkmarks=*/
       base::android::ToJavaBooleanArray(
-          env, std::make_unique<bool[]>(titles.size()).get(), titles.size()),
+          env, base::HeapArray<bool>::WithSize(titles.size())),
       base::android::ToJavaIntArray(env, overflow_menu_item_ids),
       base::android::ToJavaArrayOfStrings(env, language_codes));
 }
diff --git a/components/visited_url_ranking/DEPS b/components/visited_url_ranking/DEPS
index ec98efc1..e55e622e 100644
--- a/components/visited_url_ranking/DEPS
+++ b/components/visited_url_ranking/DEPS
@@ -8,6 +8,7 @@
   "+components/segmentation_platform/internal/metadata",
   "+components/strings",
   "+components/sessions/core",
+  "+components/sync/protocol",
   "+components/sync_device_info",
   "+components/sync_sessions",
   "+ui/base",
diff --git a/components/visited_url_ranking/internal/BUILD.gn b/components/visited_url_ranking/internal/BUILD.gn
index 37abfee..041f1d7 100644
--- a/components/visited_url_ranking/internal/BUILD.gn
+++ b/components/visited_url_ranking/internal/BUILD.gn
@@ -100,6 +100,7 @@
     "//components/segmentation_platform/public",
     "//components/segmentation_platform/public:test_support",
     "//components/sessions",
+    "//components/sync/protocol",
     "//components/sync_sessions",
     "//components/url_deduplication",
     "//components/visited_url_ranking/public",
diff --git a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc
index 6720d0c..973be35 100644
--- a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc
+++ b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc
@@ -14,6 +14,8 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/url_row.h"
+#include "components/sync_device_info/device_info_sync_service.h"
+#include "components/sync_device_info/local_device_info_util.h"
 #include "components/url_deduplication/url_deduplication_helper.h"
 #include "components/visited_url_ranking/public/features.h"
 #include "components/visited_url_ranking/public/fetch_result.h"
@@ -64,8 +66,10 @@
 using URLVisitVariant = URLVisitAggregate::URLVisitVariant;
 
 HistoryURLVisitDataFetcher::HistoryURLVisitDataFetcher(
-    history::HistoryService* history_service)
-    : history_service_(history_service) {}
+    history::HistoryService* history_service,
+    syncer::DeviceInfoSyncService* device_info_sync_service)
+    : history_service_(history_service),
+      device_info_sync_service_(device_info_sync_service) {}
 
 HistoryURLVisitDataFetcher::~HistoryURLVisitDataFetcher() = default;
 
@@ -116,11 +120,25 @@
         1, 100, 100);
   }
 
-  std::map<std::string, URLVisitAggregate::HistoryData> url_annotations;
+  std::map<std::string, std::pair<std::string, syncer::DeviceInfo::FormFactor>>
+      sync_device_info;
+  syncer::DeviceInfoTracker* device_info_tracker =
+      device_info_sync_service_->GetDeviceInfoTracker();
+  if (device_info_tracker) {
+    for (const syncer::DeviceInfo* device_info :
+         device_info_tracker->GetAllDeviceInfo()) {
+      sync_device_info[device_info->guid()] = {device_info->client_name(),
+                                               device_info->form_factor()};
+    }
+  }
+
   base::Time::Exploded time_exploded;
   config.clock->Now().LocalExplode(&time_exploded);
   DayGroup current_day_group = GetDayGroupForExplodedTime(time_exploded);
   TimeGroup current_time_group = GetTimeGroupForExplodedTime(time_exploded);
+  syncer::DeviceInfo::FormFactor local_device_form_factor =
+      syncer::GetLocalDeviceFormFactor();
+  std::map<std::string, URLVisitAggregate::HistoryData> url_annotations;
   for (auto& annotated_visit : annotated_visits) {
     // The `originator_cache_guid` field is only set for foreign session visits.
     Source current_visit_source =
@@ -135,10 +153,27 @@
                                       annotated_visit.url_row.title(),
                                       config.deduplication_helper);
     if (url_annotations.find(url_key) == url_annotations.end()) {
+      std::optional<std::string> client_name = std::nullopt;
+      syncer::DeviceInfo::FormFactor device_type =
+          syncer::DeviceInfo::FormFactor::kUnknown;
+      if (annotated_visit.visit_row.originator_cache_guid.empty()) {
+        device_type = local_device_form_factor;
+      } else {
+        auto it = sync_device_info.find(
+            annotated_visit.visit_row.originator_cache_guid);
+        if (it != sync_device_info.end()) {
+          client_name = it->second.first;
+          device_type = it->second.second;
+        }
+      }
+
       // `GetAnnotatedVisits` returns a reverse-chronological sorted list of
-      // annotated visits, thus, the first visit in the vector is the last
-      // active (i.e. most recent) visit for a given URL.
-      url_annotations.emplace(url_key, std::move(annotated_visit));
+      // annotated visits, thus, the first visit in the vector is the most
+      // recently navigated visit for a given URL.
+      url_annotations.emplace(std::piecewise_construct,
+                              std::forward_as_tuple(url_key),
+                              std::forward_as_tuple(std::move(annotated_visit),
+                                                    client_name, device_type));
     } else {
       auto& history = url_annotations.at(url_key);
       history.visit_count += 1;
diff --git a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h
index 5527ba8..c59c113 100644
--- a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h
+++ b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h
@@ -20,12 +20,18 @@
 class HistoryService;
 }  // namespace history
 
+namespace syncer {
+class DeviceInfoSyncService;
+}
+
 namespace visited_url_ranking {
 
 // Fetches URL visit data from the history service.
 class HistoryURLVisitDataFetcher : public URLVisitDataFetcher {
  public:
-  explicit HistoryURLVisitDataFetcher(history::HistoryService* history_service);
+  HistoryURLVisitDataFetcher(
+      history::HistoryService* history_service,
+      syncer::DeviceInfoSyncService* device_info_sync_service);
   HistoryURLVisitDataFetcher(const HistoryURLVisitDataFetcher&) = delete;
   ~HistoryURLVisitDataFetcher() override;
 
@@ -44,6 +50,8 @@
 
   const raw_ptr<history::HistoryService> history_service_;
 
+  const raw_ptr<syncer::DeviceInfoSyncService> device_info_sync_service_;
+
   // The task tracker for the HistoryService callbacks.
   base::CancelableTaskTracker task_tracker_;
 
diff --git a/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc b/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc
index d52eb68..b52cf58 100644
--- a/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc
+++ b/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc
@@ -4,10 +4,15 @@
 
 #include "components/visited_url_ranking/internal/history_url_visit_data_fetcher.h"
 
+#include <memory>
+#include <string>
 #include <utility>
+#include <vector>
 
 #include "base/functional/callback.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -17,6 +22,10 @@
 #include "base/time/time.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_types.h"
+#include "components/sync/protocol/sync_enums.pb.h"
+#include "components/sync_device_info/device_info.h"
+#include "components/sync_device_info/device_info_sync_service.h"
+#include "components/sync_device_info/device_info_tracker.h"
 #include "components/visited_url_ranking/public/fetch_result.h"
 #include "components/visited_url_ranking/public/fetcher_config.h"
 #include "components/visited_url_ranking/public/url_visit.h"
@@ -32,6 +41,7 @@
 history::AnnotatedVisit SampleAnnotatedVisit(
     history::VisitID visit_id,
     const GURL& url,
+    const std::u16string& title,
     float visibility_score,
     const std::string& originator_cache_guid,
     const std::optional<std::string> app_id = std::nullopt,
@@ -41,6 +51,7 @@
   history::AnnotatedVisit annotated_visit;
   history::URLRow url_row;
   url_row.set_url(url);
+  url_row.set_title(title);
   annotated_visit.url_row = std::move(url_row);
   history::VisitContentModelAnnotations model_annotations;
   model_annotations.visibility_score = visibility_score;
@@ -78,6 +89,50 @@
                          base::CancelableTaskTracker* tracker));
 };
 
+class MockDeviceInfoTracker : public syncer::DeviceInfoTracker {
+ public:
+  MOCK_CONST_METHOD0(IsSyncing, bool());
+
+  MOCK_CONST_METHOD1(GetDeviceInfo,
+                     syncer::DeviceInfo*(const std::string& client_id));
+
+  MOCK_CONST_METHOD0(GetAllDeviceInfo,
+                     std::vector<const syncer::DeviceInfo*>());
+
+  MOCK_CONST_METHOD0(GetAllChromeDeviceInfo,
+                     std::vector<const syncer::DeviceInfo*>());
+
+  MOCK_METHOD1(AddObserver, void(Observer* observer));
+
+  MOCK_METHOD1(RemoveObserver, void(Observer* observer));
+
+  MOCK_CONST_METHOD0(CountActiveDevicesByType,
+                     std::map<syncer::DeviceInfo::FormFactor, int>());
+
+  MOCK_METHOD0(ForcePulseForTest, void());
+
+  MOCK_CONST_METHOD1(IsRecentLocalCacheGuid,
+                     bool(const std::string& cache_guid));
+};
+
+class MockDeviceInfoSyncService : public syncer::DeviceInfoSyncService {
+ public:
+  MockDeviceInfoSyncService() = default;
+  MockDeviceInfoSyncService(const MockDeviceInfoSyncService&) = delete;
+  MockDeviceInfoSyncService& operator=(const MockDeviceInfoSyncService&) =
+      delete;
+  ~MockDeviceInfoSyncService() override = default;
+
+  MOCK_METHOD0(GetLocalDeviceInfoProvider, syncer::LocalDeviceInfoProvider*());
+
+  MOCK_METHOD0(GetDeviceInfoTracker, syncer::DeviceInfoTracker*());
+
+  MOCK_METHOD0(GetControllerDelegate,
+               base::WeakPtr<syncer::DataTypeControllerDelegate>());
+
+  MOCK_METHOD0(RefreshLocalDeviceInfo, void());
+};
+
 struct HistoryScenario {
  public:
   HistoryScenario(base::Time current_time_arg,
@@ -143,15 +198,45 @@
 using URLType = visited_url_ranking::FetchOptions::URLType;
 using ResultOption = visited_url_ranking::FetchOptions::ResultOption;
 
+constexpr char kSampleForeignDeviceGUID[] = "foreign_guid";
+constexpr char kSampleForeignDeviceClientName[] = "Windows PC";
+const syncer::DeviceInfo kSampleForeignDeviceInfo{
+    kSampleForeignDeviceGUID,
+    kSampleForeignDeviceClientName,
+    "",
+    "",
+    sync_pb::SyncEnums_DeviceType_TYPE_WIN,
+    syncer::DeviceInfo::OsType::kWindows,
+    syncer::DeviceInfo::FormFactor::kDesktop,
+    "",
+    "",
+    "",
+    "",
+    base::Time::Now(),
+    base::Seconds(1),
+    false,
+    sync_pb::
+        SyncEnums_SendTabReceivingType_SEND_TAB_RECEIVING_TYPE_CHROME_OR_UNSPECIFIED,
+    std::nullopt,
+    std::nullopt,
+    "",
+    {},
+    std::nullopt};
+
 class HistoryURLVisitDataFetcherTest : public testing::Test {
  public:
   HistoryURLVisitDataFetcherTest() {
     clock_.SetNow(base::Time::Now());
 
     mock_history_service_ = std::make_unique<MockHistoryService>();
+    mock_device_info_tracker_ = std::make_unique<MockDeviceInfoTracker>();
+    mock_device_info_sync_service_ =
+        std::make_unique<MockDeviceInfoSyncService>();
+    EXPECT_CALL(*mock_device_info_sync_service_, GetDeviceInfoTracker())
+        .WillRepeatedly(testing::Return(mock_device_info_tracker_.get()));
 
     history_url_visit_fetcher_ = std::make_unique<HistoryURLVisitDataFetcher>(
-        mock_history_service_.get());
+        mock_history_service_.get(), mock_device_info_sync_service_.get());
   }
 
   FetchOptions GetSampleFetchOptions() {
@@ -168,10 +253,10 @@
     std::vector<history::AnnotatedVisit> annotated_visits;
     annotated_visits.emplace_back(
         SampleAnnotatedVisit(1, GURL(base::StrCat({kSampleSearchUrl, "1"})),
-                             1.0f, "", "sample_app_id"));
+                             u"Search 1", 1.0f, "", "sample_app_id"));
     annotated_visits.emplace_back(
         SampleAnnotatedVisit(2, GURL(base::StrCat({kSampleSearchUrl, "2"})),
-                             0.75f, "foreign_session_guid"));
+                             u"Search 2", 0.75f, kSampleForeignDeviceGUID));
     return annotated_visits;
   }
 
@@ -180,12 +265,23 @@
     std::vector<history::AnnotatedVisit> annotated_visits;
     for (size_t i = 0; i < scenario.timestamps.size(); i++) {
       annotated_visits.emplace_back(SampleAnnotatedVisit(
-          i + 1, GURL(kSampleSearchUrl), 1.0f, "", "", scenario.timestamps[i]));
+          i + 1, GURL(kSampleSearchUrl), base::NumberToString16(i), 1.0f, "",
+          "", scenario.timestamps[i]));
     }
 
     return annotated_visits;
   }
 
+  void SetDeviceInfoTrackerExpectations() {
+    std::vector<const syncer::DeviceInfo*> device_infos;
+    device_infos.push_back(&kSampleForeignDeviceInfo);
+    EXPECT_CALL(*mock_device_info_tracker_, GetAllDeviceInfo())
+        .WillOnce(testing::Return(device_infos));
+    EXPECT_CALL(*mock_device_info_tracker_,
+                IsRecentLocalCacheGuid(kSampleForeignDeviceGUID))
+        .WillRepeatedly(testing::Return(false));
+  }
+
   void SetHistoryServiceExpectations(
       std::vector<history::AnnotatedVisit> annotated_visits) {
     EXPECT_CALL(*mock_history_service_,
@@ -226,10 +322,13 @@
  private:
   base::test::TaskEnvironment task_env_;
   std::unique_ptr<MockHistoryService> mock_history_service_;
+  std::unique_ptr<MockDeviceInfoTracker> mock_device_info_tracker_;
+  std::unique_ptr<MockDeviceInfoSyncService> mock_device_info_sync_service_;
   std::unique_ptr<HistoryURLVisitDataFetcher> history_url_visit_fetcher_;
 };
 
 TEST_F(HistoryURLVisitDataFetcherTest, FetchURLVisitDataDefaultSources) {
+  SetDeviceInfoTrackerExpectations();
   SetHistoryServiceExpectations(GetSampleAnnotatedVisits());
 
   FetchOptions options = FetchOptions(
@@ -250,6 +349,17 @@
       &result.data.at(entry_url.spec()));
   EXPECT_EQ(history->last_app_id, "sample_app_id");
   EXPECT_EQ(history->total_foreground_duration.InSeconds(), 0);
+  EXPECT_EQ(history->visit.source, URLVisit::Source::kLocal);
+
+  const GURL visit2_url = GURL(base::StrCat({kSampleSearchUrl, "2"}));
+  const auto* history_data2 = std::get_if<URLVisitAggregate::HistoryData>(
+      &result.data.at(visit2_url.spec()));
+  EXPECT_EQ(history_data2->visit.url, visit2_url);
+  EXPECT_EQ(history_data2->visit.title, u"Search 2");
+  EXPECT_EQ(history_data2->visit.client_name, kSampleForeignDeviceClientName);
+  EXPECT_EQ(history_data2->visit.device_type,
+            syncer::DeviceInfo::FormFactor::kDesktop);
+  EXPECT_EQ(history_data2->visit.source, URLVisit::Source::kForeign);
 }
 
 TEST_F(HistoryURLVisitDataFetcherTest,
@@ -259,12 +369,12 @@
   const float kSampleVisibilityScore = 0.75f;
   std::vector<history::AnnotatedVisit> annotated_visits;
   annotated_visits.emplace_back(SampleAnnotatedVisit(
-      1, GURL(kSampleSearchUrl),
+      1, GURL(kSampleSearchUrl), u"Search 1",
       history::VisitContentModelAnnotations::kDefaultVisibilityScore,
       /*originator_cache_guid=*/""));
-  annotated_visits.emplace_back(
-      SampleAnnotatedVisit(2, GURL(kSampleSearchUrl), kSampleVisibilityScore,
-                           /*originator_cache_guid=*/""));
+  annotated_visits.emplace_back(SampleAnnotatedVisit(
+      2, GURL(kSampleSearchUrl), u"Search 2", kSampleVisibilityScore,
+      /*originator_cache_guid=*/""));
   SetHistoryServiceExpectations(std::move(annotated_visits));
 
   auto result = FetchAndGetResult(GetSampleFetchOptions());
@@ -289,23 +399,26 @@
 
   std::vector<history::AnnotatedVisit> annotated_visits;
   annotated_visits.emplace_back(
-      SampleAnnotatedVisit(1, GURL("http://gmail.com/"),
+      SampleAnnotatedVisit(1, GURL("http://gmail.com/"), /*title=*/u"Gmail",
                            /*visibility_score=*/1.0,
                            /*originator_cache_guid=*/"",
                            /*app_id=*/std::nullopt, base::Time::Now(),
                            /*visit_duration=*/base::Milliseconds(0)));
   annotated_visits.emplace_back(SampleAnnotatedVisit(
-      2, GURL("https://gmail.com/"), /*visibility_score=*/1.0f,
+      2, GURL("https://gmail.com/"), /*title=*/u"Gmail",
+      /*visibility_score=*/1.0f,
       /*originator_cache_guid=*/"", /*app_id=*/std::nullopt, base::Time::Now(),
       /*visit_duration=*/base::Milliseconds(0),
       /*referring_visit_id=*/1));
   annotated_visits.emplace_back(SampleAnnotatedVisit(
-      3, GURL("https://mail.google.com/mail/u/0/"), /*visibility_score=*/1.0f,
+      3, GURL("https://mail.google.com/mail/u/0/"), /*title=*/u"Gmail",
+      /*visibility_score=*/1.0f,
       /*originator_cache_guid=*/"", /*app_id=*/std::nullopt, base::Time::Now(),
       /*visit_duration=*/base::Milliseconds(0),
       /*referring_visit_id=*/2));
   annotated_visits.emplace_back(SampleAnnotatedVisit(
       4, GURL("https://mail.google.com/mail/u/0/#inbox"),
+      /*title=*/u"Gmail Inbox",
       /*visibility_score=*/1.0f,
       /*originator_cache_guid=*/"", /*app_id=*/std::nullopt, base::Time::Now(),
       /*visit_duration=*/base::Minutes(1),
diff --git a/components/visited_url_ranking/internal/session_url_visit_data_fetcher.cc b/components/visited_url_ranking/internal/session_url_visit_data_fetcher.cc
index 01a6d3b..433ce9f 100644
--- a/components/visited_url_ranking/internal/session_url_visit_data_fetcher.cc
+++ b/components/visited_url_ranking/internal/session_url_visit_data_fetcher.cc
@@ -58,7 +58,8 @@
           auto last_active_tab = URLVisitAggregate::Tab(
               tab->tab_id.id(),
               URLVisit(tab_url, current_navigation.title(), tab->timestamp,
-                       session->GetDeviceFormFactor(), source),
+                       session->GetDeviceFormFactor(), source,
+                       session->GetSessionName()),
               session->GetSessionTag(), session->GetSessionName());
           auto tab_data =
               URLVisitAggregate::TabData(std::move(last_active_tab));
diff --git a/components/visited_url_ranking/public/url_visit.cc b/components/visited_url_ranking/public/url_visit.cc
index e5105f1..0432bbe 100644
--- a/components/visited_url_ranking/public/url_visit.cc
+++ b/components/visited_url_ranking/public/url_visit.cc
@@ -16,12 +16,14 @@
                    const std::u16string& title_arg,
                    const base::Time& last_modified_arg,
                    syncer::DeviceInfo::FormFactor device_type_arg,
-                   Source source_arg)
+                   Source source_arg,
+                   const std::optional<std::string>& client_name_arg)
     : url(url_arg),
       title(title_arg),
       last_modified(last_modified_arg),
       device_type(device_type_arg),
-      source(source_arg) {}
+      source(source_arg),
+      client_name(client_name_arg) {}
 
 URLVisit::URLVisit(const URLVisit&) = default;
 
@@ -138,8 +140,18 @@
 URLVisitAggregate::TabData::~TabData() = default;
 
 URLVisitAggregate::HistoryData::HistoryData(
-    history::AnnotatedVisit annotated_visit)
-    : last_visited(std::move(annotated_visit)) {
+    history::AnnotatedVisit annotated_visit,
+    std::optional<std::string> client_name,
+    syncer::DeviceInfo::FormFactor device_type)
+    : last_visited(std::move(annotated_visit)),
+      visit(last_visited.url_row.url(),
+            last_visited.url_row.title(),
+            last_visited.visit_row.visit_time,
+            device_type,
+            last_visited.visit_row.originator_cache_guid.empty()
+                ? URLVisit::Source::kLocal
+                : URLVisit::Source::kForeign,
+            std::move(client_name)) {
   if (last_visited.context_annotations.total_foreground_duration
           .InMilliseconds() > 0) {
     total_foreground_duration =
diff --git a/components/visited_url_ranking/public/url_visit.h b/components/visited_url_ranking/public/url_visit.h
index 6dfa382..50d85b9 100644
--- a/components/visited_url_ranking/public/url_visit.h
+++ b/components/visited_url_ranking/public/url_visit.h
@@ -42,7 +42,8 @@
            const std::u16string& title_arg,
            const base::Time& last_modified_arg,
            syncer::DeviceInfo::FormFactor device_type_arg,
-           Source source_arg);
+           Source source_arg,
+           const std::optional<std::string>& client_name = std::nullopt);
   URLVisit(const URLVisit&);
   ~URLVisit();
 
@@ -58,6 +59,9 @@
       syncer::DeviceInfo::FormFactor::kUnknown;
   // The source from which the visit originated (i.e. local or remote).
   Source source = Source::kNotApplicable;
+  // The visit's user visible client name, if applicable. Only set for remote
+  // sources.
+  std::optional<std::string> client_name;
 };
 
 /**
@@ -105,7 +109,10 @@
   };
 
   struct HistoryData {
-    explicit HistoryData(history::AnnotatedVisit annotated_visit);
+    explicit HistoryData(history::AnnotatedVisit annotated_visit,
+                         std::optional<std::string> client_name = std::nullopt,
+                         syncer::DeviceInfo::FormFactor device_type_arg =
+                             syncer::DeviceInfo::FormFactor::kUnknown);
     HistoryData(const HistoryData&) = delete;
     HistoryData(HistoryData&& other);
     HistoryData& operator=(HistoryData&& other);
@@ -115,8 +122,11 @@
     // time period.
     history::AnnotatedVisit last_visited;
 
-    // The last `app_id` value if any for any of the visits associated with the
-    // URL visit aggregate.
+    // Associated URL visit data.
+    URLVisit visit;
+
+    // The last `app_id` value if any for any of the visits associated with
+    // the URL visit aggregate.
     std::optional<std::string> last_app_id = std::nullopt;
 
     // Whether any of the annotated visits for the given URL visit aggregate are
diff --git a/components/visited_url_ranking/public/url_visit_util.cc b/components/visited_url_ranking/public/url_visit_util.cc
index 62a9dbfe..9153014 100644
--- a/components/visited_url_ranking/public/url_visit_util.cc
+++ b/components/visited_url_ranking/public/url_visit_util.cc
@@ -303,10 +303,10 @@
     const URLVisitAggregate& url_visit_aggregate) {
   const auto& fetcher_data_map = url_visit_aggregate.fetcher_data_map;
   for (const auto& fetcher : {Fetcher::kTabModel, Fetcher::kSession}) {
-    if (fetcher_data_map.find(fetcher) != fetcher_data_map.end()) {
+    auto it = fetcher_data_map.find(fetcher);
+    if (it != fetcher_data_map.end()) {
       const URLVisitAggregate::TabData* tab_data =
-          std::get_if<URLVisitAggregate::TabData>(
-              &fetcher_data_map.at(fetcher));
+          std::get_if<URLVisitAggregate::TabData>(&it->second);
       return tab_data;
     }
   }
@@ -338,6 +338,19 @@
   return nullptr;
 }
 
+const URLVisitAggregate::HistoryData* GetHistoryDataIfExists(
+    const URLVisitAggregate& url_visit_aggregate) {
+  const auto& fetcher_data_map = url_visit_aggregate.fetcher_data_map;
+  auto it = fetcher_data_map.find(Fetcher::kHistory);
+  if (it != fetcher_data_map.end()) {
+    const URLVisitAggregate::HistoryData* history_data =
+        std::get_if<URLVisitAggregate::HistoryData>(&it->second);
+    return history_data;
+  }
+
+  return nullptr;
+}
+
 const history::AnnotatedVisit* GetHistoryEntryVisitIfExists(
     const URLVisitAggregate& url_visit_aggregate) {
   const auto& fetcher_data_map = url_visit_aggregate.fetcher_data_map;
diff --git a/components/visited_url_ranking/public/url_visit_util.h b/components/visited_url_ranking/public/url_visit_util.h
index 33f5cbc..9af58d3 100644
--- a/components/visited_url_ranking/public/url_visit_util.h
+++ b/components/visited_url_ranking/public/url_visit_util.h
@@ -61,6 +61,9 @@
 const URLVisitAggregate::Tab* GetTabIfExists(
     const URLVisitAggregate& url_visit_aggregate);
 
+const URLVisitAggregate::HistoryData* GetHistoryDataIfExists(
+    const URLVisitAggregate& url_visit_aggregate);
+
 // Returns a history entry if it exists for a `URLVisitAggregate`.
 const history::AnnotatedVisit* GetHistoryEntryVisitIfExists(
     const URLVisitAggregate& url_visit_aggregate);
diff --git a/components/viz/service/display/overdraw_tracker.cc b/components/viz/service/display/overdraw_tracker.cc
index a19c305d..b5b2fd9 100644
--- a/components/viz/service/display/overdraw_tracker.cc
+++ b/components/viz/service/display/overdraw_tracker.cc
@@ -35,12 +35,12 @@
   // integers while preserving the desired level of decimal precision.
   constexpr int kConversionFactor = 100'000;
 
-  // The expected overdraw ranges is [1, 6].
+  // The expected overdraw ranges is [1, 12].
   UMA_HISTOGRAM_CUSTOM_COUNTS(
       kAverageOverdrawHistogramName,
       base::ClampRound<int>(overdraw * kConversionFactor),
       /*minimum=*/1 * kConversionFactor,
-      /*maximum=*/(6 * kConversionFactor) + 1, /*bucket_count=*/50);
+      /*maximum=*/(12 * kConversionFactor) + 1, /*bucket_count=*/50);
 }
 
 }  // namespace
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 51ffde03..4e692b6 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -282,8 +282,7 @@
   RunEventTest(FILE_PATH_LITERAL("aria-haspopup-changed.html"));
 }
 
-// crbug.com/1511111 leaving disabled after re-enabling test suite.
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTestExceptUIA,
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsAriaHiddenChanged) {
   RunEventTest(FILE_PATH_LITERAL("aria-hidden-changed.html"));
 }
@@ -513,8 +512,7 @@
   RunEventTest(FILE_PATH_LITERAL("anonymous-block-children-changed.html"));
 }
 
-// crbug.com/1511111 leaving disabled after re-enabling test suite.
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTestExceptUIA,
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsChildrenChangedOnlyOnAncestor) {
   RunEventTest(FILE_PATH_LITERAL("children-changed-only-on-ancestor.html"));
 }
@@ -603,14 +601,12 @@
       FILE_PATH_LITERAL("aria-expanded-and-collapsed-reparenting.html"));
 }
 
-// crbug.com/1511111 leaving disabled after re-enabling test suite.
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTestExceptUIA,
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsAriaHiddenDescendants) {
   RunEventTest(FILE_PATH_LITERAL("aria-hidden-descendants.html"));
 }
 
-// crbug.com/1511111 leaving disabled after re-enabling test suite.
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTestExceptUIA,
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsAriaHiddenSingleDescendant) {
   RunEventTest(FILE_PATH_LITERAL("aria-hidden-single-descendant.html"));
 }
@@ -622,9 +618,8 @@
       FILE_PATH_LITERAL("aria-hidden-single-descendant-display-none.html"));
 }
 
-// crbug.com/1511111 leaving disabled after re-enabling test suite.
 IN_PROC_BROWSER_TEST_P(
-    DumpAccessibilityEventsTestExceptUIA,
+    DumpAccessibilityEventsTest,
     AccessibilityEventsAriaHiddenSingleDescendantVisibilityHidden) {
   RunEventTest(FILE_PATH_LITERAL(
       "aria-hidden-single-descendant-visibility-hidden.html"));
@@ -709,16 +704,8 @@
   RunEventTest(FILE_PATH_LITERAL("focus-listbox-multiselect.html"));
 }
 
-// TODO(crbug.com/40823137): Flaky on Linux.
-#if BUILDFLAG(IS_LINUX)
-#define MAYBE_AccessibilityEventsIframeSrcChanged \
-  DISABLED_AccessibilityEventsIframeSrcChanged
-#else
-#define MAYBE_AccessibilityEventsIframeSrcChanged \
-  AccessibilityEventsIframeSrcChanged
-#endif
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
-                       MAYBE_AccessibilityEventsIframeSrcChanged) {
+                       AccessibilityEventsIframeSrcChanged) {
   RunEventTest(FILE_PATH_LITERAL("iframe-src-changed.html"));
 }
 
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 7e405f7d..697062e 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1815,13 +1815,7 @@
   RunHtmlTest(FILE_PATH_LITERAL("canvas-fallback.html"));
 }
 
-// TODO(crbug.com/40758178): fails on Windows.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_AccessibilityCaption DISABLED_AccessibilityCaption
-#else
-#define MAYBE_AccessibilityCaption AccessibilityCaption
-#endif
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, MAYBE_AccessibilityCaption) {
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityCaption) {
   RunHtmlTest(FILE_PATH_LITERAL("caption.html"));
 }
 
@@ -2137,10 +2131,9 @@
   RunHtmlTest(FILE_PATH_LITERAL("form-validation-message.html"));
 }
 
-// https://crbug.com/944519
 IN_PROC_BROWSER_TEST_P(
     DumpAccessibilityTreeTest,
-    DISABLED_AccessibilityFormValidationMessageRemovedAfterErrorCorrected) {
+    AccessibilityFormValidationMessageRemovedAfterErrorCorrected) {
   RunHtmlTest(FILE_PATH_LITERAL(
       "form-validation-message-removed-after-error-corrected.html"));
 }
@@ -2236,9 +2229,8 @@
   RunHtmlTest(FILE_PATH_LITERAL("iframe-empty.html"));
 }
 
-// Test is flaky: https://crbug.com/1181596
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       DISABLED_AccessibilityIframeAriaHidden) {
+                       AccessibilityIframeAriaHidden) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-aria-hidden.html"));
 }
 
@@ -2307,9 +2299,8 @@
   RunHtmlTest(FILE_PATH_LITERAL("iframe.html"));
 }
 
-// https://crbug.com/622387
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       DISABLED_AccessibilityIframeCrossProcess) {
+                       AccessibilityIframeCrossProcess) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-cross-process.html"));
 }
 
@@ -2357,33 +2348,22 @@
   RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-scrolled.html"));
 }
 
-// TODO(crbug.com/40801320): test is flaky on all platforms
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       DISABLED_AccessibilityIframeWithInvalidChildren) {
+                       AccessibilityIframeWithInvalidChildren) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-with-invalid-children.html"));
 }
 
-// TODO(crbug.com/40801320): test is flaky on all platforms
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       DISABLED_AccessibilityIframeWithInvalidChildrenAdded) {
+                       AccessibilityIframeWithInvalidChildrenAdded) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-with-invalid-children-added.html"));
 }
 
-// TODO(accessibility) Test fails on Android, even without expectations.
-#if BUILDFLAG(IS_ANDROID)
-#define MAYBE_AccessibilityIframeWithRegionRole \
-  DISABLED_AccessibilityIframeWithRegionRole
-#else
-#define MAYBE_AccessibilityIframeWithRegionRole \
-  AccessibilityIframeWithRegionRole
-#endif
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       MAYBE_AccessibilityIframeWithRegionRole) {
+                       AccessibilityIframeWithRegionRole) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-with-region-role.html"));
 }
 
-// TODO(crbug.com/40070579): Fix and reenable the test.
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, DISABLED_AccessibilityImg) {
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityImg) {
   RunHtmlTest(FILE_PATH_LITERAL("img.html"));
 }
 
@@ -2413,17 +2393,10 @@
   RunHtmlTest(FILE_PATH_LITERAL("in-page-links.html"));
 }
 
-// TODO(crbug.com/40919402): Flaky on CrOS MSan.
-#if BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)
-#define MAYBE_InertAttribute DISABLED_InertAttribute
-#else
-#define MAYBE_InertAttribute InertAttribute
-#endif
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, MAYBE_InertAttribute) {
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, InertAttribute) {
   RunHtmlTest(FILE_PATH_LITERAL("inert-attribute.html"));
 }
 
-// TODO(crbug.com/40758178): fails on Windows.
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityInputButton) {
   RunHtmlTest(FILE_PATH_LITERAL("input-button.html"));
 }
@@ -2937,7 +2910,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       DISABLED_AccessibilityMapWithAriaOwns) {
+                       AccessibilityMapWithAriaOwns) {
   RunHtmlTest(FILE_PATH_LITERAL("map-with-aria-owns.html"));
 }
 
@@ -3088,15 +3061,38 @@
   RunHtmlTest(FILE_PATH_LITERAL("optgroup.html"));
 }
 
-// TODO(crbug.com/40848920): test timeouts on Fuchsia
-#if BUILDFLAG(IS_FUCHSIA)
-#define MAYBE_AccessibilityOpenModal DISABLED_AccessibilityOpenModal
+#if BUILDFLAG(IS_MAC)
+// On a Mac, <select> uses native widget, and the a11y tree does not contain
+// <select> contents ( unless it's a select that uses appearance: base-select
+// which never uses a native widget on any platform)
+#define MAYBE_AccessibilityOptgroupMenulist \
+  DISABLED_AccessibilityOptgroupMenulist
 #else
-#define MAYBE_AccessibilityOpenModal AccessibilityOpenModal
-#endif  // BUILDFLAG(IS_FUCHSIA)
+#define MAYBE_AccessibilityOptgroupMenulist AccessibilityOptgroupMenulist
+#endif  // BUILDFLAG(IS_MAC)
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       MAYBE_AccessibilityOpenModal) {
+                       MAYBE_AccessibilityOptgroupMenulist) {
+  RunHtmlTest(FILE_PATH_LITERAL("optgroup-menulist.html"));
+}
+
+#if BUILDFLAG(IS_MAC)
+// TODO(crbug.com/364913803): / Failing on Mac. Even though it's a custom
+// <select>, it's somehow hitting Mac native context menu code.
+#define MAYBE_AccessibilityOptgroupCustomMenulist \
+  DISABLED_AccessibilityOptgroupCustomMenulist
+#else
+#define MAYBE_AccessibilityOptgroupCustomMenulist \
+  AccessibilityOptgroupCustomMenulist
+#endif  // BUILDFLAG(IS_MAC)
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
+                       MAYBE_AccessibilityOptgroupCustomMenulist) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kEnableExperimentalWebPlatformFeatures);
+  RunHtmlTest(FILE_PATH_LITERAL("optgroup-custom-menulist.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityOpenModal) {
   RunHtmlTest(FILE_PATH_LITERAL("open-modal.html"));
 }
 
@@ -3378,14 +3374,8 @@
   RunHtmlTest(FILE_PATH_LITERAL("sub.html"));
 }
 
-// TODO(crbug.com/40930250): Flaky
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_AccessibilitySub DISABLED_AccessibilitySub
-#else
-#define MAYBE_AccessibilitySub AccessibilitySub
-#endif
 IN_PROC_BROWSER_TEST_P(YieldingParserDumpAccessibilityTreeTest,
-                       MAYBE_AccessibilitySub) {
+                       AccessibilitySub) {
   RunHtmlTest(FILE_PATH_LITERAL("sub.html"));
 }
 
@@ -3393,13 +3383,7 @@
   RunHtmlTest(FILE_PATH_LITERAL("sup.html"));
 }
 
-// TODO(crbug.com/40758178): fails on Windows.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_AccessibilitySummary DISABLED_AccessibilitySummary
-#else
-#define MAYBE_AccessibilitySummary AccessibilitySummary
-#endif
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, MAYBE_AccessibilitySummary) {
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilitySummary) {
   RunHtmlTest(FILE_PATH_LITERAL("summary.html"));
 }
 
@@ -3627,14 +3611,7 @@
   RunHtmlTest(FILE_PATH_LITERAL("title-changed.html"));
 }
 
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-// Flaky on Win/Mac: crbug.com/508532
-#define MAYBE_AccessibilityTransition DISABLED_AccessibilityTransition
-#else
-#define MAYBE_AccessibilityTransition AccessibilityTransition
-#endif
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       MAYBE_AccessibilityTransition) {
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityTransition) {
   RunHtmlTest(FILE_PATH_LITERAL("transition.html"));
 }
 
@@ -3669,16 +3646,8 @@
   RunHtmlTest(FILE_PATH_LITERAL("video-text-only.html"));
 }
 
-// TODO(crbug.com/40874552): This test is failing on Android.
-#if BUILDFLAG(IS_ANDROID)
-#define MAYBE_AccessibilityNodeChangedCrashInEditableText \
-  DISABLED_AccessibilityNodeChangedCrashInEditableText
-#else
-#define MAYBE_AccessibilityNodeChangedCrashInEditableText \
-  AccessibilityNodeChangedCrashInEditableText
-#endif  // BUILDFLAG(IS_ANDROID)
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       MAYBE_AccessibilityNodeChangedCrashInEditableText) {
+                       AccessibilityNodeChangedCrashInEditableText) {
   RunHtmlTest(FILE_PATH_LITERAL("node-changed-crash-in-editable-text.html"));
 }
 
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index e732081..982535f 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -822,10 +822,9 @@
   float dip_scale = 1 / root_manager->device_scale_factor();
   gfx::Rect absolute_rect = gfx::ScaleToEnclosingRect(
       node->GetUnclippedRootFrameBoundsRect(), dip_scale, dip_scale);
-  int rect[4] = {absolute_rect.x(), absolute_rect.y(), absolute_rect.right(),
-                 absolute_rect.bottom()};
-
-  return base::android::ToJavaIntArray(env, rect, static_cast<size_t>(4));
+  int rect[] = {absolute_rect.x(), absolute_rect.y(), absolute_rect.right(),
+                absolute_rect.bottom()};
+  return base::android::ToJavaIntArray(env, rect);
 }
 
 static size_t ActualUnignoredChildCount(const ui::AXNode* node) {
@@ -966,10 +965,9 @@
   std::vector<int> suggestion_ends;
   node->GetSuggestions(&suggestion_starts, &suggestion_ends);
   if (suggestion_starts.size() && suggestion_ends.size()) {
-    suggestion_starts_java = base::android::ToJavaIntArray(
-        env, suggestion_starts.data(), suggestion_starts.size());
-    suggestion_ends_java = base::android::ToJavaIntArray(
-        env, suggestion_ends.data(), suggestion_ends.size());
+    suggestion_starts_java =
+        base::android::ToJavaIntArray(env, suggestion_starts);
+    suggestion_ends_java = base::android::ToJavaIntArray(env, suggestion_ends);
 
     // Currently we don't retrieve the text of each suggestion, so
     // store a blank string for now.
@@ -1555,8 +1553,7 @@
     coords[4 * i + 2] = char_bounds.right();
     coords[4 * i + 3] = char_bounds.bottom();
   }
-  return base::android::ToJavaIntArray(env, coords.data(),
-                                       static_cast<size_t>(4 * len));
+  return base::android::ToJavaIntArray(env, coords);
 }
 
 jboolean WebContentsAccessibilityAndroid::GetImageData(
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index aefd316..af30554 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -303,6 +303,7 @@
       const std::string& client_guid,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
       RenameCompletionCallback callback) override;
 
@@ -383,11 +384,13 @@
     const std::string& client_guid,
     const GURL& source_url,
     const GURL& referrer_url,
+    const std::optional<url::Origin>& request_initiator,
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
     RenameCompletionCallback callback) {
   DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
   download::DownloadFileImpl::RenameAndAnnotate(
-      full_path, client_guid, source_url, referrer_url, mojo::NullRemote(),
+      full_path, client_guid, source_url, referrer_url, request_initiator,
+      mojo::NullRemote(),
       base::BindOnce(DownloadFileWithDelay::RenameCallbackWrapper, owner_,
                      std::move(callback)));
 }
diff --git a/content/browser/download/save_file.cc b/content/browser/download/save_file.cc
index ce468dae..6440597 100644
--- a/content/browser/download/save_file.cc
+++ b/content/browser/download/save_file.cc
@@ -68,9 +68,11 @@
     const GURL& referrer_url,
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
     download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback) {
-  file_.AnnotateWithSourceInformation(client_guid, source_url, referrer_url,
-                                      std::move(remote_quarantine),
-                                      std::move(on_annotation_done_callback));
+  // TODO(crbug.com/351165321): Consider propagating request_initiator
+  // information here.
+  file_.AnnotateWithSourceInformation(
+      client_guid, source_url, referrer_url, /*request_initiator=*/std::nullopt,
+      std::move(remote_quarantine), std::move(on_annotation_done_callback));
 }
 
 base::FilePath SaveFile::FullPath() const {
diff --git a/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc b/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
index 349ffdc..10cef46 100644
--- a/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
@@ -67,6 +67,7 @@
   void QuarantineFile(const base::FilePath& full_path,
                       const GURL& source_url,
                       const GURL& referrer_url,
+                      const std::optional<url::Origin>& request_initiator,
                       const std::string& client_guid,
                       QuarantineFileCallback callback) override {
     paths.push_back(full_path);
diff --git a/content/browser/file_system_access/file_system_access_safe_move_helper.cc b/content/browser/file_system_access/file_system_access_safe_move_helper.cc
index 0fa95c7..4fe08e48 100644
--- a/content/browser/file_system_access/file_system_access_safe_move_helper.cc
+++ b/content/browser/file_system_access/file_system_access_safe_move_helper.cc
@@ -344,6 +344,9 @@
     quarantine::mojom::Quarantine* raw_quarantine = quarantine_remote.get();
     raw_quarantine->QuarantineFile(
         target_url.path(), authority_url, referrer_url,
+        // TODO(crbug.com/351165321): Consider propagating request_initiator
+        // information here.
+        /*request_initiator=*/std::nullopt,
         GetContentClient()
             ->browser()
             ->GetApplicationClientGUIDForQuarantineCheck(),
diff --git a/content/browser/file_system_access/file_system_access_safe_move_helper_unittest.cc b/content/browser/file_system_access/file_system_access_safe_move_helper_unittest.cc
index d34f919..e91ccee 100644
--- a/content/browser/file_system_access/file_system_access_safe_move_helper_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_safe_move_helper_unittest.cc
@@ -54,6 +54,7 @@
   void QuarantineFile(const base::FilePath& full_path,
                       const GURL& source_url,
                       const GURL& referrer_url,
+                      const std::optional<url::Origin>& request_initiator,
                       const std::string& client_guid,
                       QuarantineFileCallback callback) override {
     paths.push_back(full_path);
diff --git a/content/browser/first_party_sets/first_party_sets_loader.cc b/content/browser/first_party_sets/first_party_sets_loader.cc
index e09df288..52453960b 100644
--- a/content/browser/first_party_sets/first_party_sets_loader.cc
+++ b/content/browser/first_party_sets/first_party_sets_loader.cc
@@ -11,9 +11,11 @@
 #include "base/files/file_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/sequence_checker.h"
+#include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/version.h"
 #include "content/browser/first_party_sets/first_party_set_parser.h"
+#include "net/base/features.h"
 #include "net/first_party_sets/global_first_party_sets.h"
 #include "net/first_party_sets/local_set_declaration.h"
 
@@ -66,10 +68,16 @@
     return;
   }
 
-  // We use USER_BLOCKING here since First-Party Set initialization blocks
-  // network navigations at startup.
+  // We may use USER_BLOCKING here since First-Party Set initialization may
+  // block network navigations at startup. Otherwise, initialization blocks
+  // resolution of promises from `document.requestStorageAccess()`, but those
+  // calls are unlikely to occur during startup.
+  base::TaskPriority priority =
+      base::FeatureList::IsEnabled(net::features::kWaitForFirstPartySetsInit)
+          ? base::TaskPriority::USER_BLOCKING
+          : base::TaskPriority::USER_VISIBLE;
   base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
+      FROM_HERE, {base::MayBlock(), priority},
       base::BindOnce(&ReadSetsFile, std::move(sets_file)),
       base::BindOnce(&FirstPartySetsLoader::OnReadSetsFile,
                      weak_factory_.GetWeakPtr(), std::move(version)));
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index ffe9e2d..de563c62 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -1418,15 +1418,20 @@
   return s;
 }
 
-Status IndexedDBBackingStore::DeleteDatabase(
-    const std::u16string& name,
-    TransactionalLevelDBTransaction* transaction) {
+Status IndexedDBBackingStore::DeleteDatabase(const std::u16string& name,
+                                             std::vector<PartitionedLock> locks,
+                                             base::OnceClosure on_complete) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 #if DCHECK_IS_ON()
   DCHECK(initialized_);
 #endif
   TRACE_EVENT0("IndexedDB", "IndexedDBBackingStore::DeleteDatabase");
 
+  scoped_refptr<TransactionalLevelDBTransaction> transaction =
+      transactional_leveldb_factory_->CreateLevelDBTransaction(
+          db(), db()->scopes()->CreateScope(std::move(locks)));
+  transaction->set_commit_cleanup_complete_callback(std::move(on_complete));
+
   Status s;
   bool success = false;
   int64_t id = 0;
@@ -1464,11 +1469,11 @@
   bool database_has_blob_references =
       active_blob_registry()->MarkDatabaseDeletedAndCheckIfReferenced(id);
   if (database_has_blob_references) {
-    s = MergeDatabaseIntoActiveBlobJournal(transaction, id);
+    s = MergeDatabaseIntoActiveBlobJournal(transaction.get(), id);
     if (!s.ok())
       return s;
   } else {
-    s = MergeDatabaseIntoRecoveryBlobJournal(transaction, id);
+    s = MergeDatabaseIntoRecoveryBlobJournal(transaction.get(), id);
     if (!s.ok())
       return s;
     need_cleanup = true;
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index 558a2de..67950ca 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -418,9 +418,9 @@
   // `max_object_store_id` fields are outputs.
   virtual leveldb::Status CreateDatabase(
       blink::IndexedDBDatabaseMetadata& metadata);
-  virtual leveldb::Status DeleteDatabase(
-      const std::u16string& name,
-      TransactionalLevelDBTransaction* transaction);
+  virtual leveldb::Status DeleteDatabase(const std::u16string& name,
+                                         std::vector<PartitionedLock> locks,
+                                         base::OnceClosure on_complete);
   // Changes the database version to |version|.
   [[nodiscard]] virtual leveldb::Status SetDatabaseVersion(
       Transaction* transaction,
diff --git a/content/browser/indexed_db/indexed_db_bucket_context.h b/content/browser/indexed_db/indexed_db_bucket_context.h
index b13b571..7598fcc7 100644
--- a/content/browser/indexed_db/indexed_db_bucket_context.h
+++ b/content/browser/indexed_db/indexed_db_bucket_context.h
@@ -342,10 +342,6 @@
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
 
-  TransactionalLevelDBFactory& transactional_leveldb_factory() const {
-    return *transactional_leveldb_factory_;
-  }
-
  private:
   friend IndexedDBBucketContextHandle;
   friend class IndexedDBBackingStoreTest;
diff --git a/content/browser/indexed_db/indexed_db_connection_coordinator.cc b/content/browser/indexed_db/indexed_db_connection_coordinator.cc
index 01c7cda..8e213dc 100644
--- a/content/browser/indexed_db/indexed_db_connection_coordinator.cc
+++ b/content/browser/indexed_db/indexed_db_connection_coordinator.cc
@@ -20,7 +20,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/functional/callback_tags.h"
 #include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
@@ -28,11 +27,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "components/services/storage/indexed_db/locks/partitioned_lock.h"
 #include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h"
-#include "components/services/storage/indexed_db/scopes/leveldb_scope.h"
-#include "components/services/storage/indexed_db/scopes/leveldb_scopes.h"
-#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h"
-#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_factory.h"
-#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h"
 #include "components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom.h"
 #include "content/browser/indexed_db/indexed_db_backing_store.h"
 #include "content/browser/indexed_db/indexed_db_bucket_context.h"
@@ -529,20 +523,13 @@
         indexed_db::kBackingStoreActionUmaName,
         indexed_db::IndexedDBAction::kDatabaseDeleteAttempt);
     // This is used to check if this class is still alive after the destruction
-    // of the TransactionalLevelDBTransaction, which can synchronously cause the
-    // system to be shut down if the disk is really bad.
+    // of the backing store, which can synchronously cause the system to be shut
+    // down if the disk is really bad.
     base::WeakPtr<DeleteRequest> weak_ptr = weak_factory_.GetWeakPtr();
     if (db_->backing_store()) {
-      scoped_refptr<TransactionalLevelDBTransaction> txn;
-      TransactionalLevelDBDatabase* db = db_->backing_store()->db();
-      if (db) {
-        txn = db->class_factory()->CreateLevelDBTransaction(
-            db, db->scopes()->CreateScope(std::move(lock_receiver_.locks)));
-        txn->set_commit_cleanup_complete_callback(
-            std::move(on_database_deleted_));
-      }
-      saved_leveldb_status_ =
-          db_->backing_store()->DeleteDatabase(db_->metadata_.name, txn.get());
+      saved_leveldb_status_ = db_->backing_store()->DeleteDatabase(
+          db_->metadata_.name, std::move(lock_receiver_.locks),
+          std::move(on_database_deleted_));
       base::UmaHistogramEnumeration(
           "WebCore.IndexedDB.BackingStore.DeleteDatabaseStatus",
           leveldb_env::GetLevelDBStatusUMAValue(saved_leveldb_status_),
diff --git a/content/browser/indexed_db/indexed_db_connection_coordinator.h b/content/browser/indexed_db/indexed_db_connection_coordinator.h
index 694e77a..bfe2d0b 100644
--- a/content/browser/indexed_db/indexed_db_connection_coordinator.h
+++ b/content/browser/indexed_db/indexed_db_connection_coordinator.h
@@ -15,7 +15,6 @@
 #include "base/memory/weak_ptr.h"
 #include "content/browser/indexed_db/indexed_db_bucket_context.h"
 #include "content/browser/indexed_db/indexed_db_task_helper.h"
-#include "content/browser/indexed_db/list_set.h"
 #include "content/common/content_export.h"
 #include "third_party/leveldatabase/src/include/leveldb/status.h"
 
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 7daa883e..5ead634 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -16,7 +16,6 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
@@ -28,10 +27,6 @@
 #include "components/services/storage/indexed_db/locks/partitioned_lock.h"
 #include "components/services/storage/indexed_db/locks/partitioned_lock_id.h"
 #include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h"
-#include "components/services/storage/indexed_db/scopes/leveldb_scope.h"
-#include "components/services/storage/indexed_db/scopes/leveldb_scopes.h"
-#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h"
-#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h"
 #include "content/browser/indexed_db/indexed_db_bucket_context.h"
 #include "content/browser/indexed_db/indexed_db_bucket_context_handle.h"
 #include "content/browser/indexed_db/indexed_db_callback_helpers.h"
diff --git a/content/browser/interest_group/auction_metrics_recorder.h b/content/browser/interest_group/auction_metrics_recorder.h
index bc7a051b..d2e629f 100644
--- a/content/browser/interest_group/auction_metrics_recorder.h
+++ b/content/browser/interest_group/auction_metrics_recorder.h
@@ -63,6 +63,26 @@
 //   OnAuctionEnd, just before the Event is written to the UkmRecorder.
 class CONTENT_EXPORT AuctionMetricsRecorder {
  public:
+  // Helper class for aggregating latencies for events that occur many times
+  // during the auction, for which we want to produce aggregate measurements
+  // to record using separate metrics.
+  class LatencyAggregator {
+   public:
+    LatencyAggregator() = default;
+    LatencyAggregator(const LatencyAggregator&) = delete;
+    LatencyAggregator& operator=(const LatencyAggregator&) = delete;
+
+    void RecordLatency(base::TimeDelta latency);
+    int32_t GetNumRecords();
+    base::TimeDelta GetMeanLatency();
+    base::TimeDelta GetMaxLatency();
+
+   private:
+    int32_t num_records_ = 0;
+    base::TimeDelta sum_latency_;
+    base::TimeDelta max_latency_;
+  };
+
   // This object's construction time is that recorded as the auction's start
   // time for measuring end-to-end latency, LoadInterestGroupPhase latency,
   // ConfigPromisesResolved latency, etc.
@@ -206,26 +226,6 @@
   using UkmEntry = ukm::builders::AdsInterestGroup_AuctionLatency_V2;
   using EntrySetFunction = UkmEntry& (UkmEntry::*)(int64_t value);
 
-  // Helper class for aggregating latencies for events that occur many times
-  // during the auction, for which we want to produce aggregate measurements
-  // to record using separate metrics.
-  class LatencyAggregator {
-   public:
-    LatencyAggregator() = default;
-    LatencyAggregator(const LatencyAggregator&) = delete;
-    LatencyAggregator& operator=(const LatencyAggregator&) = delete;
-
-    void RecordLatency(base::TimeDelta latency);
-    int32_t GetNumRecords();
-    base::TimeDelta GetMeanLatency();
-    base::TimeDelta GetMaxLatency();
-
-   private:
-    int32_t num_records_ = 0;
-    base::TimeDelta sum_latency_;
-    base::TimeDelta max_latency_;
-  };
-
   // Helper class for keeping track of the earliest recorded time among events
   // that may occur many times during the auction, and specifically phase start
   // times, used to better understand auction latency.
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index 343aff6..78630cd 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -2387,7 +2387,8 @@
                 /*debug_loss_report_url=*/std::nullopt,
                 /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
                 /*real_time_contributions=*/{},
-                /*scoring_latency=*/base::TimeDelta(),
+                /*score_ad_timing_metrics=*/
+                auction_worklet::mojom::SellerTimingMetrics::New(),
                 /*score_ad_dependency_latencies=*/
                 auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                     /*code_ready_latency=*/std::nullopt,
@@ -10837,7 +10838,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -10863,7 +10865,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -11127,7 +11130,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -11385,7 +11389,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -11415,7 +11420,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -11618,7 +11624,8 @@
             /*debug_win_report_url=*/std::nullopt,
             /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -11699,7 +11706,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -11789,7 +11797,8 @@
               /*debug_loss_report_url=*/std::nullopt,
               /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
               /*real_time_contributions=*/{},
-              /*scoring_latency=*/base::TimeDelta(),
+              /*score_ad_timing_metrics=*/
+              auction_worklet::mojom::SellerTimingMetrics::New(),
               /*score_ad_dependency_latencies=*/
               auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                   /*code_ready_latency=*/std::nullopt,
@@ -11916,7 +11925,8 @@
               /*debug_loss_report_url=*/std::nullopt,
               /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
               /*real_time_contributions=*/{},
-              /*scoring_latency=*/base::TimeDelta(),
+              /*score_ad_timing_metrics=*/
+              auction_worklet::mojom::SellerTimingMetrics::New(),
               /*score_ad_dependency_latencies=*/
               auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                   /*code_ready_latency=*/std::nullopt,
@@ -12317,7 +12327,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -12378,7 +12389,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -12435,7 +12447,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -12519,7 +12532,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -12549,7 +12563,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -12700,7 +12715,8 @@
                     /*debug_loss_report_url=*/std::nullopt,
                     /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
                     /*real_time_contributions=*/{},
-                    /*scoring_latency=*/base::TimeDelta(),
+                    /*score_ad_timing_metrics=*/
+                    auction_worklet::mojom::SellerTimingMetrics::New(),
                     /*score_ad_dependency_latencies=*/
                     auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                         /*code_ready_latency=*/std::nullopt,
@@ -12728,7 +12744,8 @@
                     /*debug_win_report_url=*/std::nullopt,
                     /*pa_requests=*/{},
                     /*real_time_contributions=*/{},
-                    /*scoring_latency=*/base::TimeDelta(),
+                    /*score_ad_timing_metrics=*/
+                    auction_worklet::mojom::SellerTimingMetrics::New(),
                     /*score_ad_dependency_latencies=*/
                     auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                         /*code_ready_latency=*/std::nullopt,
@@ -13184,7 +13201,8 @@
           /*debug_win_report_url=*/std::nullopt,
           /*pa_requests=*/std::move(seller_pa_requests),
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -13279,7 +13297,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -13407,7 +13426,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -14712,7 +14732,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -14970,7 +14991,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::Milliseconds(0),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             ScoreAdDependencyLatencies::New(test_case.dependency_latencies),
             /*errors=*/{});
@@ -15126,7 +15148,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::Milliseconds(0),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/base::Milliseconds(100),
@@ -15179,7 +15202,8 @@
           /*debug_loss_report_url=*/std::nullopt,
           /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::Milliseconds(0),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/base::Milliseconds(100),
@@ -16715,7 +16739,8 @@
           /*debug_win_report_url=*/std::nullopt,
           std::move(score_ad_1_pa_requests),
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -16837,7 +16862,10 @@
             /*debug_win_report_url=*/std::nullopt,
             /*pa_requests=*/std::move(seller_pa_requests),
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::Milliseconds(100 * i + 20),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(
+                /*js_fetch_latency=*/std::nullopt,
+                /*scoring_latency=*/base::Milliseconds(100 * i + 20)),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -16923,6 +16951,356 @@
                                                            /*value=*/0)))));
 }
 
+TEST_F(AuctionRunnerTest, PrivateAggregationTimeMetricsPerParticipant) {
+  const int kNumBidders = 2;
+  const int kIgsPerBidder = 3;
+  UseMockWorkletService();
+
+  // Create multiple IGs per buyers to make it clear things are being
+  // done per-buyer/per-seller.
+  std::vector<StorageInterestGroup> bidders;
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, kBidder1Name, kBidder1Url,
+      /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad1.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, "2", kBidder1Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad1.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, "3", kBidder1Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad1.com")));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "2", base::Milliseconds(500));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "3", base::Milliseconds(500));
+
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder2, kBidder2Name, kBidder2Url,
+      /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad2.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder2, "4", kBidder2Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad2.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder2, "5", kBidder2Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad2.com")));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "4", base::Milliseconds(150));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "5", base::Milliseconds(150));
+
+  StartAuction(kSellerUrl, std::move(bidders));
+
+  mock_auction_process_manager_->WaitForWorklets(kNumBidders,
+                                                 /*num_sellers=*/1);
+
+  auto seller_worklet = mock_auction_process_manager_->TakeSellerWorklet();
+  ASSERT_TRUE(seller_worklet);
+
+  std::array<std::unique_ptr<MockBidderWorklet>, kNumBidders> bidder_worklets;
+  bidder_worklets[0] =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url);
+  bidder_worklets[1] =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
+  for (int i = 0; i < kNumBidders; ++i) {
+    ASSERT_TRUE(bidder_worklets[i]);
+    for (int ig = 0; ig < kIgsPerBidder; ++ig) {
+      bidder_worklets[i]->SetCodeFetchLatencies(
+          base::Milliseconds(100 * i + ig * 20 + 20),
+          base::Milliseconds(100 * i + ig * 20 + 45));
+      std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+          bidder_pa_requests;
+      bidder_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+          /*bucket=*/100 * i,
+          auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+          Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce)));
+      bidder_worklets[i]->InvokeGenerateBidCallback(
+          ig == 0 ? std::make_optional<double>(i + 1) : std::nullopt,
+          /*bid_currency=*/std::nullopt,
+          blink::AdDescriptor(
+              GURL(base::StringPrintf("https://ad%d.com/", i + 1))),
+          auction_worklet::mojom::BidRole::kUnenforcedKAnon,
+          /*further_bids=*/{},
+          /*ad_component_descriptors=*/std::nullopt,
+          /*duration=*/base::Seconds(5),
+          /*bidding_signals_data_version=*/std::nullopt,
+          /*debug_loss_report_url=*/std::nullopt,
+          /*debug_win_report_url=*/std::nullopt, std::move(bidder_pa_requests));
+    }
+
+    std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+        seller_pa_requests;
+    seller_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+        /*bucket=*/10, auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+        Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce)));
+
+    auto score_ad_params = seller_worklet->WaitForScoreAd();
+    mojo::Remote<auction_worklet::mojom::ScoreAdClient>(
+        std::move(score_ad_params.score_ad_client))
+        ->OnScoreAdComplete(
+            /*score=*/i + 1,
+            /*reject_reason=*/
+            auction_worklet::mojom::RejectReason::kNotAvailable,
+            auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(),
+            /*bid_in_seller_currency=*/std::nullopt,
+            /*scoring_signals_data_version=*/std::nullopt,
+            /*debug_loss_report_url=*/std::nullopt,
+            /*debug_win_report_url=*/std::nullopt,
+            /*pa_requests=*/std::move(seller_pa_requests),
+            /*real_time_contributions=*/{},
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(
+                /*js_fetch_latency=*/base::Milliseconds(100 * i + 45),
+                /*scoring_latency=*/base::Milliseconds(100 * i + 20)),
+            /*score_ad_dependency_latencies=*/
+            auction_worklet::mojom::ScoreAdDependencyLatencies::New(
+                /*code_ready_latency=*/std::nullopt,
+                /*direct_from_seller_signals_latency=*/std::nullopt,
+                /*trusted_scoring_signals_latency=*/
+                base::Milliseconds(100 * i + 21),
+                /*deps_wait_start_time=*/base::TimeTicks::Now(),
+                /*score_ad_start_time=*/base::TimeTicks::Now(),
+                /*score_ad_finish_time=*/base::TimeTicks::Now()),
+            /*errors=*/{});
+  }
+
+  std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+      bidder_report_pa_requests, seller_report_pa_requests;
+  bidder_report_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+      /*bucket=*/50, auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+      Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+  seller_report_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+      /*bucket=*/60, auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+      Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+
+  // Need to flush the service pipe to make sure the AuctionRunner has
+  // received the score.
+  seller_worklet->Flush();
+  seller_worklet->WaitForReportResult();
+  seller_worklet->SetCodeFetchLatency(base::Milliseconds(400));
+  seller_worklet->InvokeReportResultCallback(
+      /*report_url=*/std::nullopt,
+      /*ad_beacon_map=*/{}, std::move(seller_report_pa_requests));
+  mock_auction_process_manager_->WaitForWinningBidderReload();
+  auto winning_bidder_worklet =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
+  ASSERT_TRUE(winning_bidder_worklet);
+  winning_bidder_worklet->WaitForReportWin();
+  winning_bidder_worklet->SetCodeFetchLatencies(base::Milliseconds(400),
+                                                base::Milliseconds(500));
+  winning_bidder_worklet->InvokeReportWinCallback(
+      /*report_url=*/std::nullopt,
+      /*ad_beacon_map=*/{}, /*ad_macro_map=*/{},
+      std::move(bidder_report_pa_requests));
+  auction_run_loop_->Run();
+
+  EXPECT_THAT(
+      private_aggregation_manager_.TakePrivateAggregationRequests(),
+      testing::UnorderedElementsAre(
+          testing::Pair(kBidder1,
+                        // 52 = (truncated) average of 20, 45, 40, 65, 60, 85.
+                        ElementsAreRequests(
+                            BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                           /*value=*/52))),
+          testing::Pair(kBidder2,
+                        ElementsAreRequests(
+                            BuildPrivateAggregationRequest(/*bucket=*/100,
+                                                           /*value=*/152),
+                            BuildPrivateAggregationRequest(/*bucket=*/50,
+                                                           /*value=*/450))),
+          testing::Pair(kSeller,
+                        // 95 = average of 45 and 145.
+                        ElementsAreRequests(
+                            BuildPrivateAggregationRequest(/*bucket=*/10,
+                                                           /*value=*/95),
+                            BuildPrivateAggregationRequest(/*bucket=*/60,
+                                                           /*value=*/400)))));
+}
+
+TEST_F(AuctionRunnerTest, PrivateAggregationMetricsPerParticipant) {
+  const int kNumBidders = 2;
+  UseMockWorkletService();
+
+  all_buyers_group_limit_ = 3;
+
+  // Create multiple IGs per buyers with different properties, to test IG-count
+  // related metrics.
+  std::vector<StorageInterestGroup> bidders;
+  // bidder1 has 4 IGs with ads, one without; but the limit is 3 so we expect
+  // only 3 to participate.
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, kBidder1Name, kBidder1Url,
+      /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad1.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, "2", kBidder1Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad1.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, "3", kBidder1Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad1.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, "4", kBidder1Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, /*ad_url=*/std::nullopt));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder1, "5", kBidder1Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad1.com")));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "2", base::Milliseconds(500));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "3", base::Milliseconds(500));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "4", base::Milliseconds(500));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "5", base::Milliseconds(500));
+  // Give earlier groups higher priority.
+  double priority = 10.0;
+  for (auto& ig : bidders) {
+    ig.interest_group.priority = priority;
+    --priority;
+  }
+
+  // bidder2 has 2 IGs with ads.
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder2, kBidder2Name, kBidder2Url,
+      /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad2.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder2, "6", kBidder2Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, GURL("https://ad2.com")));
+  bidders.emplace_back(MakeInterestGroup(
+      kBidder2, "7", kBidder2Url, /*trusted_bidding_signals_url=*/std::nullopt,
+      /*trusted_bidding_signals_keys=*/{}, /*ad_url=*/std::nullopt));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "6", base::Milliseconds(150));
+  mock_auction_process_manager_->SetExpectedBuyerBidTimeout(
+      "7", base::Milliseconds(150));
+
+  StartAuction(kSellerUrl, std::move(bidders));
+
+  mock_auction_process_manager_->WaitForWorklets(kNumBidders,
+                                                 /*num_sellers=*/1);
+
+  auto seller_worklet = mock_auction_process_manager_->TakeSellerWorklet();
+  ASSERT_TRUE(seller_worklet);
+
+  std::array<std::unique_ptr<MockBidderWorklet>, kNumBidders> bidder_worklets;
+  bidder_worklets[0] =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url);
+  bidder_worklets[1] =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
+  for (int i = 0; i < kNumBidders; ++i) {
+    ASSERT_TRUE(bidder_worklets[i]);
+    for (int ig = 0; ig < (i == 0 ? 3 : 2); ++ig) {
+      std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+          bidder_pa_requests;
+      bidder_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+          /*bucket=*/100 * i,
+          auction_worklet::mojom::BaseValue::kParticipatingInterestGroupCount,
+          Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce)));
+      bidder_worklets[i]->InvokeGenerateBidCallback(
+          ig == 0 ? std::make_optional<double>(i + 1) : std::nullopt,
+          /*bid_currency=*/std::nullopt,
+          blink::AdDescriptor(
+              GURL(base::StringPrintf("https://ad%d.com/", i + 1))),
+          auction_worklet::mojom::BidRole::kUnenforcedKAnon,
+          /*further_bids=*/{},
+          /*ad_component_descriptors=*/std::nullopt,
+          /*duration=*/base::Seconds(5),
+          /*bidding_signals_data_version=*/std::nullopt,
+          /*debug_loss_report_url=*/std::nullopt,
+          /*debug_win_report_url=*/std::nullopt, std::move(bidder_pa_requests));
+    }
+
+    std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+        seller_pa_requests;
+    seller_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+        /*bucket=*/10,
+        auction_worklet::mojom::BaseValue::kParticipatingInterestGroupCount,
+        Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce)));
+
+    auto score_ad_params = seller_worklet->WaitForScoreAd();
+    mojo::Remote<auction_worklet::mojom::ScoreAdClient>(
+        std::move(score_ad_params.score_ad_client))
+        ->OnScoreAdComplete(
+            /*score=*/i + 1,
+            /*reject_reason=*/
+            auction_worklet::mojom::RejectReason::kNotAvailable,
+            auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(),
+            /*bid_in_seller_currency=*/std::nullopt,
+            /*scoring_signals_data_version=*/std::nullopt,
+            /*debug_loss_report_url=*/std::nullopt,
+            /*debug_win_report_url=*/std::nullopt,
+            /*pa_requests=*/std::move(seller_pa_requests),
+            /*real_time_contributions=*/{},
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(
+                /*js_fetch_latency=*/base::Milliseconds(100 * i + 45),
+                /*scoring_latency=*/base::Milliseconds(100 * i + 20)),
+            /*score_ad_dependency_latencies=*/
+            auction_worklet::mojom::ScoreAdDependencyLatencies::New(
+                /*code_ready_latency=*/std::nullopt,
+                /*direct_from_seller_signals_latency=*/std::nullopt,
+                /*trusted_scoring_signals_latency=*/
+                base::Milliseconds(100 * i + 21),
+                /*deps_wait_start_time=*/base::TimeTicks::Now(),
+                /*score_ad_start_time=*/base::TimeTicks::Now(),
+                /*score_ad_finish_time=*/base::TimeTicks::Now()),
+            /*errors=*/{});
+  }
+
+  std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+      bidder_report_pa_requests, seller_report_pa_requests;
+  bidder_report_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+      /*bucket=*/50,
+      auction_worklet::mojom::BaseValue::kParticipatingInterestGroupCount,
+      Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+  seller_report_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+      /*bucket=*/60,
+      auction_worklet::mojom::BaseValue::kParticipatingInterestGroupCount,
+      Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+
+  // Need to flush the service pipe to make sure the AuctionRunner has
+  // received the score.
+  seller_worklet->Flush();
+  seller_worklet->WaitForReportResult();
+  seller_worklet->InvokeReportResultCallback(
+      /*report_url=*/std::nullopt,
+      /*ad_beacon_map=*/{}, std::move(seller_report_pa_requests));
+  mock_auction_process_manager_->WaitForWinningBidderReload();
+  auto winning_bidder_worklet =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
+  ASSERT_TRUE(winning_bidder_worklet);
+  winning_bidder_worklet->WaitForReportWin();
+  winning_bidder_worklet->InvokeReportWinCallback(
+      /*report_url=*/std::nullopt,
+      /*ad_beacon_map=*/{}, /*ad_macro_map=*/{},
+      std::move(bidder_report_pa_requests));
+  auction_run_loop_->Run();
+
+  EXPECT_THAT(
+      private_aggregation_manager_.TakePrivateAggregationRequests(),
+      testing::UnorderedElementsAre(
+          testing::Pair(
+              kBidder1,
+              // 3 IGs are actually useful.
+              ElementsAreRequests(BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                                 /*value=*/3))),
+          testing::Pair(
+              kBidder2,
+              // 2 IGs w/ads
+              ElementsAreRequests(BuildPrivateAggregationRequest(/*bucket=*/100,
+                                                                 /*value=*/2),
+                                  BuildPrivateAggregationRequest(/*bucket=*/50,
+                                                                 /*value=*/2))),
+          testing::Pair(kSeller,
+                        // No IG metric for sellers.
+                        ElementsAreRequests(
+                            BuildPrivateAggregationRequest(/*bucket=*/10,
+                                                           /*value=*/0),
+                            BuildPrivateAggregationRequest(/*bucket=*/60,
+                                                           /*value=*/0)))));
+}
+
 TEST_F(AuctionRunnerTest, ComponentAuctionPrivateAggregationTimeMetrics) {
   const int kNumBidders = 2;
   UseMockWorkletService();
@@ -16954,6 +17332,8 @@
     bidder_worklets[i]->SetBidderTrustedSignalsFetchLatency(
         base::Milliseconds(100 * i + 1));
     bidder_worklets[i]->SetBiddingLatency(base::Milliseconds(100 * i + 10));
+    bidder_worklets[i]->SetCodeFetchLatencies(base::Milliseconds(100 * i + 20),
+                                              base::Milliseconds(100 * i + 30));
 
     std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
         bidder_pa_requests, component_seller_pa_requests;
@@ -16972,6 +17352,13 @@
         /*bucket=*/100 * i + 11,
         auction_worklet::mojom::BaseValue::kSignalsFetchTime,
         Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+    bidder_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+        /*bucket=*/100 * i + 2,
+        auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+        Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce)));
+    component_seller_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+        /*bucket=*/12, auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+        Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce)));
     bidder_worklets[i]->InvokeGenerateBidCallback(
         i + 1, /*bid_currency=*/std::nullopt,
         blink::AdDescriptor(
@@ -16998,7 +17385,10 @@
             /*debug_win_report_url=*/std::nullopt,
             /*pa_requests=*/std::move(component_seller_pa_requests),
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::Milliseconds(100 * i + 20),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(
+                /*js_fetch_latency=*/base::Milliseconds(100 * i + 50),
+                /*scoring_latency=*/base::Milliseconds(100 * i + 20)),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -17019,6 +17409,9 @@
   top_seller_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
       /*bucket=*/21, auction_worklet::mojom::BaseValue::kSignalsFetchTime,
       Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+  top_seller_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+      /*bucket=*/22, auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+      Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce)));
 
   auto top_score_ad_params = top_seller_worklet->WaitForScoreAd();
   mojo::Remote<auction_worklet::mojom::ScoreAdClient>(
@@ -17034,7 +17427,10 @@
           /*debug_win_report_url=*/std::nullopt,
           /*pa_requests=*/std::move(top_seller_pa_requests),
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::Milliseconds(30),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(
+              /*js_fetch_latency=*/base::Milliseconds(50),
+              /*scoring_latency=*/base::Milliseconds(30)),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -17070,8 +17466,21 @@
   top_seller_report_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
       /*bucket=*/71, auction_worklet::mojom::BaseValue::kSignalsFetchTime,
       Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+  bidder_report_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+      /*bucket=*/52, auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+      Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+  component_seller_report_pa_requests.push_back(
+      BuildPrivateAggregationForBaseValue(
+          /*bucket=*/62,
+          auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+          Reserved(
+              auction_worklet::mojom::ReservedEventType::kReservedAlways)));
+  top_seller_report_pa_requests.push_back(BuildPrivateAggregationForBaseValue(
+      /*bucket=*/72, auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+      Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways)));
 
   top_seller_worklet->WaitForReportResult();
+  top_seller_worklet->SetCodeFetchLatency(base::Milliseconds(1000));
   top_seller_worklet->SetReportingLatency(base::Milliseconds(200));
   top_seller_worklet->InvokeReportResultCallback(
       /*report_url=*/std::nullopt,
@@ -17083,6 +17492,7 @@
   component_seller_worklet->set_expect_send_pending_signals_requests_called(
       false);
   component_seller_worklet->WaitForReportResult();
+  component_seller_worklet->SetCodeFetchLatency(base::Milliseconds(1100));
   component_seller_worklet->SetReportingLatency(base::Milliseconds(250));
   component_seller_worklet->InvokeReportResultCallback(
       /*report_url=*/std::nullopt,
@@ -17093,6 +17503,8 @@
       mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
   ASSERT_TRUE(winning_bidder_worklet);
   winning_bidder_worklet->WaitForReportWin();
+  winning_bidder_worklet->SetCodeFetchLatencies(base::Milliseconds(1200),
+                                                base::Milliseconds(1300));
   winning_bidder_worklet->SetReportingLatency(base::Milliseconds(300));
   winning_bidder_worklet->InvokeReportWinCallback(
       /*report_url=*/std::nullopt,
@@ -17103,51 +17515,66 @@
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
-          testing::Pair(
-              kBidder1,
-              ElementsAreRequests(BuildPrivateAggregationRequest(/*bucket=*/0,
-                                                                 /*value=*/10),
-                                  BuildPrivateAggregationRequest(/*bucket=*/1,
-                                                                 /*value=*/1))),
-          testing::Pair(
-              kBidder2,
-              ElementsAreRequests(BuildPrivateAggregationRequest(/*bucket=*/100,
-                                                                 /*value=*/110),
-                                  BuildPrivateAggregationRequest(/*bucket=*/101,
-                                                                 /*value=*/101),
-                                  BuildPrivateAggregationRequest(/*bucket=*/50,
-                                                                 /*value=*/300),
-                                  // No signals fetch for reporting,
-                                  // so value = 0.
-                                  BuildPrivateAggregationRequest(/*bucket=*/51,
-                                                                 /*value=*/0))),
-          testing::Pair(
-              kComponentSeller1,
-              ElementsAreRequests(BuildPrivateAggregationRequest(/*bucket=*/10,
-                                                                 /*value=*/20),
-                                  BuildPrivateAggregationRequest(/*bucket=*/11,
-                                                                 /*value=*/21),
-                                  BuildPrivateAggregationRequest(/*bucket=*/110,
-                                                                 /*value=*/120),
-                                  BuildPrivateAggregationRequest(/*bucket=*/111,
-                                                                 /*value=*/121),
-                                  BuildPrivateAggregationRequest(/*bucket=*/60,
-                                                                 /*value=*/250),
-                                  // No signals fetch for reporting,
-                                  // so value = 0.
-                                  BuildPrivateAggregationRequest(/*bucket=*/61,
-                                                                 /*value=*/0))),
+          testing::Pair(kBidder1,
+                        ElementsAreRequests(
+                            BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                           /*value=*/10),
+                            BuildPrivateAggregationRequest(/*bucket=*/1,
+                                                           /*value=*/1),
+                            BuildPrivateAggregationRequest(/*bucket=*/2,
+                                                           /*value=*/25))),
+          testing::Pair(kBidder2,
+                        ElementsAreRequests(
+                            BuildPrivateAggregationRequest(/*bucket=*/100,
+                                                           /*value=*/110),
+                            BuildPrivateAggregationRequest(/*bucket=*/101,
+                                                           /*value=*/101),
+                            BuildPrivateAggregationRequest(/*bucket=*/102,
+                                                           /*value=*/125),
+                            BuildPrivateAggregationRequest(/*bucket=*/50,
+                                                           /*value=*/300),
+                            // No signals fetch for reporting,
+                            // so value = 0.
+                            BuildPrivateAggregationRequest(/*bucket=*/51,
+                                                           /*value=*/0),
+                            BuildPrivateAggregationRequest(/*bucket=*/52,
+                                                           /*value=*/1250))),
+          testing::Pair(kComponentSeller1,
+                        ElementsAreRequests(
+                            BuildPrivateAggregationRequest(/*bucket=*/10,
+                                                           /*value=*/20),
+                            BuildPrivateAggregationRequest(/*bucket=*/11,
+                                                           /*value=*/21),
+                            // 100 = (50 + 150)/2
+                            BuildPrivateAggregationRequest(/*bucket=*/12,
+                                                           /*value=*/100),
+                            BuildPrivateAggregationRequest(/*bucket=*/110,
+                                                           /*value=*/120),
+                            BuildPrivateAggregationRequest(/*bucket=*/111,
+                                                           /*value=*/121),
+                            BuildPrivateAggregationRequest(/*bucket=*/60,
+                                                           /*value=*/250),
+                            // No signals fetch for reporting,
+                            // so value = 0.
+                            BuildPrivateAggregationRequest(/*bucket=*/61,
+                                                           /*value=*/0),
+                            BuildPrivateAggregationRequest(/*bucket=*/62,
+                                                           /*value=*/1100))),
           testing::Pair(kSeller,
                         ElementsAreRequests(
                             BuildPrivateAggregationRequest(/*bucket=*/20,
                                                            /*value=*/30),
                             BuildPrivateAggregationRequest(/*bucket=*/21,
                                                            /*value=*/31),
+                            BuildPrivateAggregationRequest(/*bucket=*/22,
+                                                           /*value=*/50),
                             BuildPrivateAggregationRequest(/*bucket=*/70,
                                                            /*value=*/200),
                             // No signals fetch for reporting, so value = 0.
                             BuildPrivateAggregationRequest(/*bucket=*/71,
-                                                           /*value=*/0)))));
+                                                           /*value=*/0),
+                            BuildPrivateAggregationRequest(/*bucket=*/72,
+                                                           /*value=*/1000)))));
 }
 
 TEST_F(AuctionRunnerTest,
@@ -18161,6 +18588,70 @@
               testing::UnorderedElementsAre());
 }
 
+TEST_F(AuctionRunnerTest, PrivateAggregationBuyerReservedOnceFeatureDisabled2) {
+  // Test that the validation happens on the non-k-anon list, too.
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      blink::features::
+          kPrivateAggregationApiProtectedAudienceAdditionalExtensions);
+
+  std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr> pa_requests;
+  pa_requests.push_back(
+      BuildPrivateAggregationForEventRequest(
+          /*bucket=*/123, /*value=*/4,
+          /*event_type=*/
+          Reserved(auction_worklet::mojom::ReservedEventType::kReservedOnce),
+          /*filtering_id=*/std::nullopt)
+          .Clone());
+
+  StartStandardAuctionWithMockService();
+
+  auto seller_worklet = mock_auction_process_manager_->TakeSellerWorklet();
+  ASSERT_TRUE(seller_worklet);
+  auto bidder1_worklet =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url);
+  ASSERT_TRUE(bidder1_worklet);
+  auto bidder2_worklet =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
+  ASSERT_TRUE(bidder2_worklet);
+
+  bidder1_worklet->SetNonKAnonPARequests(std::move(pa_requests));
+  bidder1_worklet->InvokeGenerateBidCallback(
+      /*bid=*/6, /*bid_currency=*/std::nullopt,
+      blink::AdDescriptor(GURL("https://ad1.com/")),
+      auction_worklet::mojom::BidRole::kUnenforcedKAnon,
+      /*further_bids=*/{},
+      /*ad_component_descriptors=*/std::nullopt,
+      /*duration=*/base::TimeDelta(),
+      /*bidding_signals_data_version=*/std::nullopt,
+      /*debug_loss_report_url=*/std::nullopt,
+      /*debug_win_report_url=*/std::nullopt,
+      /*pa_requests=*/{},
+      /*real_time_contributions=*/{},
+      /*dependency_latencies=*/
+      auction_worklet::mojom::GenerateBidDependencyLatenciesPtr(),
+      auction_worklet::mojom::RejectReason::kNotAvailable);
+  // Bidder 2 doesn't bid.
+  bidder2_worklet->InvokeGenerateBidCallback(/*bid=*/std::nullopt);
+
+  // Since there's no acceptable bid, the seller worklet is never asked to
+  // score a bid.
+  auction_run_loop_->Run();
+
+  EXPECT_EQ("Private Aggregation request using disabled features",
+            TakeBadMessage());
+
+  // No bidder won.
+  EXPECT_FALSE(result_.winning_group_id);
+  EXPECT_FALSE(result_.ad_descriptor);
+  EXPECT_TRUE(result_.ad_component_descriptors.empty());
+  EXPECT_THAT(result_.errors, testing::ElementsAre());
+  EXPECT_THAT(result_.interest_groups_that_bid,
+              testing::UnorderedElementsAre());
+  EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
+              testing::UnorderedElementsAre());
+}
+
 TEST_F(AuctionRunnerTest, PrivateAggregationSellerReservedOnceFeatureDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
@@ -18208,7 +18699,8 @@
           /*debug_win_report_url=*/std::nullopt,
           /*pa_requests=*/std::move(pa_requests),
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
@@ -18298,6 +18790,66 @@
   }
 }
 
+// Test that non-kanon PA contributions gets its special checks for the right
+// form. (It should get rejected since it doesn't use reject-reason).
+TEST_F(AuctionRunnerTest, PrivateAggregationNonKAnonBadContribution) {
+  std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr> pa_requests;
+  pa_requests.push_back(
+      BuildPrivateAggregationForEventRequest(
+          /*bucket=*/123, /*value=*/4,
+          /*event_type=*/
+          Reserved(auction_worklet::mojom::ReservedEventType::kReservedAlways),
+          /*filtering_id=*/std::nullopt)
+          .Clone());
+
+  StartStandardAuctionWithMockService();
+
+  auto seller_worklet = mock_auction_process_manager_->TakeSellerWorklet();
+  ASSERT_TRUE(seller_worklet);
+  auto bidder1_worklet =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url);
+  ASSERT_TRUE(bidder1_worklet);
+  auto bidder2_worklet =
+      mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
+  ASSERT_TRUE(bidder2_worklet);
+
+  bidder1_worklet->SetNonKAnonPARequests(std::move(pa_requests));
+  bidder1_worklet->InvokeGenerateBidCallback(
+      /*bid=*/6, /*bid_currency=*/std::nullopt,
+      blink::AdDescriptor(GURL("https://ad1.com/")),
+      auction_worklet::mojom::BidRole::kUnenforcedKAnon,
+      /*further_bids=*/{},
+      /*ad_component_descriptors=*/std::nullopt,
+      /*duration=*/base::TimeDelta(),
+      /*bidding_signals_data_version=*/std::nullopt,
+      /*debug_loss_report_url=*/std::nullopt,
+      /*debug_win_report_url=*/std::nullopt,
+      /*pa_requests=*/{},
+      /*real_time_contributions=*/{},
+      /*dependency_latencies=*/
+      auction_worklet::mojom::GenerateBidDependencyLatenciesPtr(),
+      auction_worklet::mojom::RejectReason::kNotAvailable);
+  // Bidder 2 doesn't bid.
+  bidder2_worklet->InvokeGenerateBidCallback(/*bid=*/std::nullopt);
+
+  // Since there's no acceptable bid, the seller worklet is never asked to
+  // score a bid.
+  auction_run_loop_->Run();
+
+  EXPECT_EQ("Incorrect non-kanon Private Aggregation request",
+            TakeBadMessage());
+
+  // No bidder won.
+  EXPECT_FALSE(result_.winning_group_id);
+  EXPECT_FALSE(result_.ad_descriptor);
+  EXPECT_TRUE(result_.ad_component_descriptors.empty());
+  EXPECT_THAT(result_.errors, testing::ElementsAre());
+  EXPECT_THAT(result_.interest_groups_that_bid,
+              testing::UnorderedElementsAre());
+  EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
+              testing::UnorderedElementsAre());
+}
+
 TEST_F(AuctionRunnerTest, RealTimeReportingSellerBadContribution) {
   const struct TestCase {
     const char* expected_error_message;
@@ -18349,7 +18901,8 @@
             /*debug_loss_report_url=*/std::nullopt,
             /*debug_win_report_url=*/std::nullopt, /*pa_requests=*/{},
             std::move(real_time_contributions),
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -21176,7 +21729,8 @@
             test_case.seller_debug_loss_report_url,
             test_case.seller_debug_win_report_url, /*pa_requests=*/{},
             /*real_time_contributions=*/{},
-            /*scoring_latency=*/base::TimeDelta(),
+            /*score_ad_timing_metrics=*/
+            auction_worklet::mojom::SellerTimingMetrics::New(),
             /*score_ad_dependency_latencies=*/
             auction_worklet::mojom::ScoreAdDependencyLatencies::New(
                 /*code_ready_latency=*/std::nullopt,
@@ -21257,7 +21811,8 @@
           GURL("https://seller-debug-loss-reporting.com/1"),
           GURL("https://seller-debug-win-reporting.com/1"), /*pa_requests=*/{},
           /*real_time_contributions=*/{},
-          /*scoring_latency=*/base::TimeDelta(),
+          /*score_ad_timing_metrics=*/
+          auction_worklet::mojom::SellerTimingMetrics::New(),
           /*score_ad_dependency_latencies=*/
           auction_worklet::mojom::ScoreAdDependencyLatencies::New(
               /*code_ready_latency=*/std::nullopt,
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc
index 9827c95..e14783a 100644
--- a/content/browser/interest_group/interest_group_auction.cc
+++ b/content/browser/interest_group/interest_group_auction.cc
@@ -72,6 +72,7 @@
 #include "content/public/browser/auction_result.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/services/auction_worklet/public/cpp/private_aggregation_reporting.h"
 #include "content/services/auction_worklet/public/cpp/real_time_reporting.h"
 #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom-forward.h"
 #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
@@ -454,6 +455,8 @@
     const InterestGroupAuction::PostAuctionSignals& signals,
     const std::optional<InterestGroupAuction::PostAuctionSignals>&
         top_level_signals,
+    const InterestGroupAuction::PrivateAggregationAllParticipantsDataPtrs&
+        all_participant_data,
     std::map<PrivateAggregationKey,
              InterestGroupAuctionReporter::PrivateAggregationRequests>&
         private_aggregation_requests_reserved,
@@ -482,6 +485,10 @@
           top_level_signals.has_value() ? top_level_signals->winning_bid : 0.0;
     }
 
+    const PrivateAggregationParticipantData* participant_data =
+        all_participant_data[static_cast<size_t>(phase)];
+    CHECK(participant_data);
+
     for (auction_worklet::mojom::PrivateAggregationRequestPtr& request :
          requests) {
       bool reserved_once = IsPrivateAggregationRequestReservedOnce(*request);
@@ -492,7 +499,7 @@
           FillInPrivateAggregationRequest(
               std::move(request), winning_bid_to_use,
               highest_scoring_other_bid_to_use, state->reject_reason,
-              state->pa_timings(phase), is_winner);
+              *participant_data, state->pa_timings(phase), is_winner);
       if (converted_request.has_value()) {
         PrivateAggregationRequestWithEventType converted_request_value =
             std::move(converted_request.value());
@@ -526,11 +533,16 @@
         continue;
       }
 
+      const PrivateAggregationParticipantData* participant_data =
+          all_participant_data[static_cast<size_t>(
+              PrivateAggregationPhase::kBidder)];
+      CHECK(participant_data);
       std::optional<PrivateAggregationRequestWithEventType> converted_request =
           FillInPrivateAggregationRequest(
               std::move(request), signals.winning_bid,
               signals.highest_scoring_other_bid,
               auction_worklet::mojom::RejectReason::kBelowKAnonThreshold,
+              *participant_data,
               state->pa_timings(PrivateAggregationPhase::kBidder), false);
       if (converted_request.has_value()) {
         PrivateAggregationKey agg_key = {bidder,
@@ -923,17 +935,12 @@
     return false;
   }
 
-  if (base::ranges::any_of(
-          non_kanon_pa_requests,
-          [](const auction_worklet::mojom::PrivateAggregationRequestPtr&
-                 request_ptr) {
-            return request_ptr->contribution->is_histogram_contribution() &&
-                   request_ptr->contribution->get_histogram_contribution()
-                       ->filtering_id.has_value();
-          })) {
-    generate_bid_client_receiver_set.ReportBadMessage(
-        "Filtering ID set inappropriately");
-    return false;
+  for (const auto& non_kanon_request : non_kanon_pa_requests) {
+    if (!auction_worklet::HasKAnonFailureComponent(*non_kanon_request)) {
+      generate_bid_client_receiver_set.ReportBadMessage(
+          "Incorrect non-kanon Private Aggregation request");
+      return false;
+    }
   }
 
   return true;
@@ -1367,7 +1374,7 @@
       PrivateAggregationRequests pa_requests,
       PrivateAggregationRequests non_kanon_pa_requests,
       RealTimeReportingContributions real_time_contributions,
-      base::TimeDelta bidding_latency,
+      auction_worklet::mojom::BidderTimingMetricsPtr generate_bid_metrics,
       auction_worklet::mojom::GenerateBidDependencyLatenciesPtr
           generate_bid_dependency_latencies,
       auction_worklet::mojom::RejectReason reject_reason,
@@ -1375,8 +1382,15 @@
     BidState* state = generate_bid_client_receiver_set_.current_context();
     const blink::InterestGroup& interest_group = state->bidder->interest_group;
     state->pa_timings(PrivateAggregationPhase::kBidder).script_run_time =
-        bidding_latency;
-    auction_->ReportBiddingLatency(interest_group, bidding_latency);
+        generate_bid_metrics->script_latency;
+    auction_->ReportBiddingLatency(interest_group,
+                                   generate_bid_metrics->script_latency);
+    if (generate_bid_metrics->js_fetch_latency.has_value()) {
+      code_fetch_time_.RecordLatency(*generate_bid_metrics->js_fetch_latency);
+    }
+    if (generate_bid_metrics->wasm_fetch_latency.has_value()) {
+      code_fetch_time_.RecordLatency(*generate_bid_metrics->wasm_fetch_latency);
+    }
 
     // This is intentionally recorded here as opposed to in
     // OnGenerateBidCompleteInternal in order to exclude bids that were
@@ -1431,6 +1445,18 @@
 
   const url::Origin& owner() const { return owner_; }
 
+  const PrivateAggregationParticipantData& buyer_metrics() const {
+    return buyer_metrics_;
+  }
+
+  void FillInBidderParticipantDataMetrics() {
+    if (code_fetch_time_.GetNumRecords() != 0) {
+      buyer_metrics_.average_code_fetch_time =
+          code_fetch_time_.GetMeanLatency();
+    }
+    buyer_metrics_.participating_interest_group_count = bid_states_.size();
+  }
+
   void GetInterestGroupsThatBidAndReportBidCounts(
       blink::InterestGroupSet& interest_groups) const {
     size_t bid_count = 0;
@@ -1495,6 +1521,8 @@
       const std::optional<PostAuctionSignals>& top_level_signals,
       const BidState* non_top_level_seller_once_rep,
       const BidState* top_level_seller_once_rep,
+      const PrivateAggregationParticipantData* non_top_level_seller_data,
+      const PrivateAggregationParticipantData* top_level_seller_data,
       std::map<PrivateAggregationKey, PrivateAggregationRequests>&
           private_aggregation_requests_reserved,
       std::map<std::string, PrivateAggregationRequests>&
@@ -1503,11 +1531,21 @@
       return;
     }
 
+    FillInBidderParticipantDataMetrics();
+
     PrivateAggregationReservedOnceReps reps;
+    PrivateAggregationAllParticipantsDataPtrs all_participant_data;
     reps[static_cast<size_t>(PrivateAggregationPhase::kTopLevelSeller)] =
         top_level_seller_once_rep;
+    all_participant_data[static_cast<size_t>(
+        PrivateAggregationPhase::kTopLevelSeller)] = top_level_seller_data;
     reps[static_cast<size_t>(PrivateAggregationPhase::kNonTopLevelSeller)] =
         non_top_level_seller_once_rep;
+    all_participant_data[static_cast<size_t>(
+        PrivateAggregationPhase::kNonTopLevelSeller)] =
+        non_top_level_seller_data;
+    all_participant_data[static_cast<size_t>(
+        PrivateAggregationPhase::kBidder)] = &buyer_metrics_;
 
     // Figure out which bidder rep to use, out of those that didn't get blocked
     // by cumulative timeout.
@@ -1538,7 +1576,7 @@
       TakePrivateAggregationRequestsForBidState(
           state, /*is_component_auction=*/auction_->parent_, winner,
           non_kanon_winner, reps, signals, top_level_signals,
-          private_aggregation_requests_reserved,
+          all_participant_data, private_aggregation_requests_reserved,
           private_aggregation_requests_non_reserved);
     }
   }
@@ -2495,6 +2533,10 @@
   // Records the time at which StartGeneratingBids was called for UKM.
   base::TimeTicks start_generating_bids_time_;
 
+  // Per-buyer PA metrics.
+  PrivateAggregationParticipantData buyer_metrics_;
+  AuctionMetricsRecorder::LatencyAggregator code_fetch_time_;
+
   // True if any interest group owned by `owner_` participating in this auction
   // has `use_biddings_signals_prioritization` set to true. When this is true,
   // all GenerateBid() calls will be deferred until OnBiddingSignalsReceived()
@@ -3180,6 +3222,7 @@
       std::move(debug_loss_report_urls), GetKAnonKeysToJoin(),
       TakeReservedPrivateAggregationRequests(),
       TakeNonReservedPrivateAggregationRequests(),
+      ComputePrivateAggregationParticipantData(),
       TakeRealTimeReportingContributions());
 
   // Avoid dangling pointers for things transferred to the reporter.
@@ -3697,15 +3740,27 @@
     DCHECK(!leader.highest_scoring_other_bid_owner.has_value());
   }
 
-  // Figure out appropriate seller reps for "reserved.once".
+  // Summarize various metrics we collected in format convenient for using them
+  // as private aggregation base values. If `parent_ != nullptr`, it would have
+  // called this before it recursed to us.
+  FillInSellerParticipantDataMetrics();
+
+  // Figure out appropriate seller reps for "reserved.once", and which metrics
+  // go to which level.
   const BidState* non_top_level_seller_once_rep;
+  const PrivateAggregationParticipantData* non_top_level_seller_data;
   const BidState* top_level_seller_once_rep;
+  const PrivateAggregationParticipantData* top_level_seller_data;
   if (parent_) {
     non_top_level_seller_once_rep = seller_reserved_once_rep_;
+    non_top_level_seller_data = &seller_metrics_;
     top_level_seller_once_rep = parent_->seller_reserved_once_rep_;
+    top_level_seller_data = &parent_->seller_metrics_;
   } else {
     non_top_level_seller_once_rep = nullptr;
+    non_top_level_seller_data = nullptr;
     top_level_seller_once_rep = seller_reserved_once_rep_;
+    top_level_seller_data = &seller_metrics_;
   }
 
   std::map<PrivateAggregationKey, PrivateAggregationRequests>
@@ -3725,6 +3780,7 @@
     buyer_helper->TakePrivateAggregationRequests(
         winner, non_kanon_winner, signals, top_level_signals,
         non_top_level_seller_once_rep, top_level_seller_once_rep,
+        non_top_level_seller_data, top_level_seller_data,
         private_aggregation_requests_reserved,
         private_aggregation_requests_non_reserved);
 
@@ -3732,13 +3788,20 @@
   }
 
   PrivateAggregationReservedOnceReps additional_bid_reps;
+  PrivateAggregationAllParticipantsDataPtrs additional_bid_data;
   additional_bid_reps[static_cast<size_t>(
       PrivateAggregationPhase::kTopLevelSeller)] = top_level_seller_once_rep;
+  additional_bid_data[static_cast<size_t>(
+      PrivateAggregationPhase::kTopLevelSeller)] = top_level_seller_data;
   additional_bid_reps[static_cast<size_t>(
       PrivateAggregationPhase::kNonTopLevelSeller)] =
       non_top_level_seller_once_rep;
+  additional_bid_data[static_cast<size_t>(
+      PrivateAggregationPhase::kNonTopLevelSeller)] = non_top_level_seller_data;
   additional_bid_reps[static_cast<size_t>(PrivateAggregationPhase::kBidder)] =
       nullptr;
+  additional_bid_data[static_cast<size_t>(PrivateAggregationPhase::kBidder)] =
+      nullptr;
 
   for (std::unique_ptr<BidState>& bid_state : bid_states_for_additional_bids_) {
     const url::Origin& owner = bid_state->additional_bid_buyer.value();
@@ -3746,7 +3809,7 @@
     TakePrivateAggregationRequestsForBidState(
         bid_state, /*is_component_auction=*/parent_ != nullptr, winner,
         non_kanon_winner, additional_bid_reps, signals, top_level_signals,
-        private_aggregation_requests_reserved,
+        additional_bid_data, private_aggregation_requests_reserved,
         private_aggregation_requests_non_reserved);
     TakeDebugReportUrlsForBidState(
         bid_state, winner, signals, top_level_signals, owner, config_->seller,
@@ -3836,6 +3899,40 @@
   return std::move(private_aggregation_requests_non_reserved_);
 }
 
+InterestGroupAuctionReporter::PrivateAggregationAllParticipantsData
+InterestGroupAuction::ComputePrivateAggregationParticipantData() {
+  InterestGroupAuctionReporter::PrivateAggregationAllParticipantsData
+      all_participant_data;
+
+  ScoredBid* winner = leader_info().top_bid.get();
+  BidState* winner_bid_state = winner->bid->bid_state;
+
+  // For non-additional bids, find their BuyerHelper to get their metrics.
+  if (!winner_bid_state->additional_bid_buyer) {
+    const url::Origin& bid_origin =
+        winner_bid_state->bidder->interest_group.owner;
+    for (const auto& buyer_helper : winner->bid->auction->buyer_helpers_) {
+      if (buyer_helper->owner() == bid_origin) {
+        all_participant_data[static_cast<size_t>(
+            PrivateAggregationPhase::kBidder)] = buyer_helper->buyer_metrics();
+        break;
+      }
+    }
+  }
+
+  // `this` is always a top-level seller.
+  all_participant_data[static_cast<size_t>(
+      PrivateAggregationPhase::kTopLevelSeller)] = seller_metrics_;
+
+  if (winner->bid->auction != this) {
+    // There is a component seller as well.
+    all_participant_data[static_cast<size_t>(
+        PrivateAggregationPhase::kNonTopLevelSeller)] =
+        winner->bid->auction->seller_metrics_;
+  }
+  return all_participant_data;
+}
+
 std::map<url::Origin, InterestGroupAuction::RealTimeReportingContributions>
 InterestGroupAuction::TakeRealTimeReportingContributions() {
   for (auto& component_auction_info : component_auctions_) {
@@ -4073,6 +4170,12 @@
   }
 }
 
+void InterestGroupAuction::FillInSellerParticipantDataMetrics() {
+  if (code_fetch_time_.GetNumRecords() != 0) {
+    seller_metrics_.average_code_fetch_time = code_fetch_time_.GetMeanLatency();
+  }
+}
+
 uint16_t InterestGroupAuction::GetBuyerMultiBidLimit(const url::Origin& buyer) {
   uint16_t val = config_->non_shared_params.all_buyers_multi_bid_limit;
   auto it = config_->non_shared_params.per_buyer_multi_bid_limits.find(buyer);
@@ -5023,7 +5126,7 @@
     const std::optional<GURL>& debug_win_report_url,
     PrivateAggregationRequests pa_requests,
     RealTimeReportingContributions real_time_contributions,
-    base::TimeDelta scoring_latency,
+    auction_worklet::mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
     auction_worklet::mojom::ScoreAdDependencyLatenciesPtr
         score_ad_dependency_latencies,
     const std::vector<std::string>& errors) {
@@ -5043,14 +5146,19 @@
 
   auction_metrics_recorder_->RecordScoreAdFlowLatency(
       base::TimeTicks::Now() - bid->seller_worklet_score_ad_start);
-  auction_metrics_recorder_->RecordScoreAdLatency(scoring_latency);
+  auction_metrics_recorder_->RecordScoreAdLatency(
+      score_ad_timing_metrics->script_latency);
   auction_metrics_recorder_->RecordScoreAdDependencyLatencies(
       *score_ad_dependency_latencies);
+  if (score_ad_timing_metrics->js_fetch_latency.has_value()) {
+    code_fetch_time_.RecordLatency(*score_ad_timing_metrics->js_fetch_latency);
+  }
 
   TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", ScoreAdTraceEventName(*bid),
                                   bid->TraceIdForScoring());
   bid->EndTracingForScoring();
-  bid->bid_state->pa_timings(seller_phase()).script_run_time = scoring_latency;
+  bid->bid_state->pa_timings(seller_phase()).script_run_time =
+      score_ad_timing_metrics->script_latency;
   bid->bid_state->pa_timings(seller_phase()).signals_fetch_time =
       score_ad_dependency_latencies->trusted_scoring_signals_latency.value_or(
           base::TimeDelta());
diff --git a/content/browser/interest_group/interest_group_auction.h b/content/browser/interest_group/interest_group_auction.h
index 2ede4b9..c5adc2a 100644
--- a/content/browser/interest_group/interest_group_auction.h
+++ b/content/browser/interest_group/interest_group_auction.h
@@ -25,6 +25,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/time/time.h"
 #include "content/browser/interest_group/additional_bid_result.h"
+#include "content/browser/interest_group/auction_metrics_recorder.h"
 #include "content/browser/interest_group/auction_nonce_manager.h"
 #include "content/browser/interest_group/auction_worklet_manager.h"
 #include "content/browser/interest_group/bidding_and_auction_response.h"
@@ -176,6 +177,11 @@
   using RealTimeReportingContributions =
       std::vector<auction_worklet::mojom::RealTimeReportingContributionPtr>;
 
+  using PrivateAggregationAllParticipantsDataPtrs =
+      std::array<const PrivateAggregationParticipantData*,
+                 base::checked_cast<size_t>(
+                     PrivateAggregationPhase::kNumPhases)>;
+
   struct CONTENT_EXPORT BidState {
     explicit BidState(const SingleStorageInterestGroup&& bidder);
     ~BidState();
@@ -664,6 +670,11 @@
   std::map<std::string, PrivateAggregationRequests>
   TakeNonReservedPrivateAggregationRequests();
 
+  // Assembles per-participant metrics values relevant to the buyer and
+  // seller(s) of the winning bid.
+  InterestGroupAuctionReporter::PrivateAggregationAllParticipantsData
+  ComputePrivateAggregationParticipantData();
+
   // Retrieves all real time report contributions.
   std::map<url::Origin, InterestGroupAuction::RealTimeReportingContributions>
   TakeRealTimeReportingContributions();
@@ -1037,7 +1048,7 @@
       const std::optional<GURL>& debug_win_report_url,
       PrivateAggregationRequests pa_requests,
       RealTimeReportingContributions real_time_contributions,
-      base::TimeDelta scoring_latency,
+      auction_worklet::mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
       auction_worklet::mojom::ScoreAdDependencyLatenciesPtr
           score_ad_dependency_latencies,
       const std::vector<std::string>& errors) override;
@@ -1096,6 +1107,10 @@
       PostAuctionSignals& signals_out,
       std::optional<PostAuctionSignals>& top_level_signals_out);
 
+  // Fills in `seller_metrics_` based on the collected state.
+  // Used by TakeDebugReportUrlsAndFillInPrivateAggregationRequests().
+  void FillInSellerParticipantDataMetrics();
+
   // Returns the multi-bid limit configured for `buyer` by `config_`,
   // ensuring that it's at least 1.
   uint16_t GetBuyerMultiBidLimit(const url::Origin& buyer);
@@ -1414,6 +1429,10 @@
   // Holds a reference to the SellerWorklet used by the auction.
   std::unique_ptr<AuctionWorkletManager::WorkletHandle> seller_worklet_handle_;
 
+  // Metrics for this auction's seller.
+  PrivateAggregationParticipantData seller_metrics_;
+  AuctionMetricsRecorder::LatencyAggregator code_fetch_time_;
+
   // Stores all pending Private Aggregation API report requests of reserved
   // event type from the bidding and scoring phase. These are passed to the
   // InterestGroupAuctionReporter when it's created. Keyed by the origin of the
diff --git a/content/browser/interest_group/interest_group_auction_reporter.cc b/content/browser/interest_group/interest_group_auction_reporter.cc
index 3267a39..f5516ca 100644
--- a/content/browser/interest_group/interest_group_auction_reporter.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter.cc
@@ -235,6 +235,7 @@
         private_aggregation_requests_reserved,
     std::map<std::string, PrivateAggregationRequests>
         private_aggregation_requests_non_reserved,
+    PrivateAggregationAllParticipantsData all_participants_data,
     std::map<url::Origin, RealTimeReportingContributions>
         real_time_contributions)
     : interest_group_manager_(interest_group_manager),
@@ -264,6 +265,7 @@
           std::move(private_aggregation_requests_reserved)),
       private_aggregation_requests_non_reserved_(
           std::move(private_aggregation_requests_non_reserved)),
+      all_participants_data_(std::move(all_participants_data)),
       real_time_contributions_(std::move(real_time_contributions)),
       fenced_frame_reporter_(FencedFrameReporter::CreateForFledge(
           url_loader_factory_,
@@ -510,14 +512,16 @@
     const std::vector<std::string>& errors) {
   // On a seller load failure or crash, act as if the worklet returned no
   // results to advance to the next worklet.
-  OnSellerReportResultComplete(seller_info,
-                               /*winning_bid=*/0.0,
-                               /*highest_scoring_other_bid=*/0.0,
-                               /*signals_for_winner=*/std::nullopt,
-                               /*seller_report_url=*/std::nullopt,
-                               /*seller_ad_beacon_map=*/{},
-                               /*pa_requests=*/{},
-                               /*reporting_latency=*/base::TimeDelta(), errors);
+  OnSellerReportResultComplete(
+      seller_info,
+      /*winning_bid=*/0.0,
+      /*highest_scoring_other_bid=*/0.0,
+      /*signals_for_winner=*/std::nullopt,
+      /*seller_report_url=*/std::nullopt,
+      /*seller_ad_beacon_map=*/{},
+      /*pa_requests=*/{},
+      /*timing_metrics=*/auction_worklet::mojom::SellerTimingMetrics::New(),
+      errors);
 }
 
 void InterestGroupAuctionReporter::OnSellerWorkletReceived(
@@ -637,7 +641,7 @@
     const std::optional<GURL>& seller_report_url,
     const base::flat_map<std::string, GURL>& seller_ad_beacon_map,
     PrivateAggregationRequests pa_requests,
-    base::TimeDelta reporting_latency,
+    auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
     const std::vector<std::string>& errors) {
   TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "seller_worklet_report_result",
                                   seller_info->trace_id);
@@ -646,7 +650,15 @@
   log_private_aggregation_requests_callback_.Run(pa_requests);
 
   PrivateAggregationTimings timings;
-  timings.script_run_time = reporting_latency;
+  timings.script_run_time = timing_metrics->script_latency;
+
+  PrivateAggregationParticipantData& participant_data =
+      all_participants_data_[static_cast<size_t>(
+          seller_info == &top_level_seller_winning_bid_info_
+              ? PrivateAggregationPhase::kTopLevelSeller
+              : PrivateAggregationPhase::kNonTopLevelSeller)];
+  participant_data.average_code_fetch_time =
+      timing_metrics->js_fetch_latency.value_or(base::TimeDelta());
 
   if (!ValidateReportingPrivateAggregationRequests(pa_requests)) {
     pa_requests.clear();
@@ -659,10 +671,10 @@
     // meaningful thus not supported in reportResult(), so it is set to
     // std::nullopt.
     std::optional<PrivateAggregationRequestWithEventType> converted_request =
-        FillInPrivateAggregationRequest(std::move(request), winning_bid,
-                                        highest_scoring_other_bid,
-                                        /*reject_reason=*/std::nullopt, timings,
-                                        /*is_winner=*/true);
+        FillInPrivateAggregationRequest(
+            std::move(request), winning_bid, highest_scoring_other_bid,
+            /*reject_reason=*/std::nullopt, participant_data, timings,
+            /*is_winner=*/true);
 
     // Only private aggregation requests with reserved event types are kept for
     // seller.
@@ -928,13 +940,15 @@
     const std::vector<std::string>& errors) {
   // Nothing more to do. Act as if the worklet completed as normal, with no
   // results.
-  OnBidderReportWinComplete(/*winning_bid=*/0.0,
-                            /*highest_scoring_other_bid=*/0.0,
-                            /*bidder_report_url=*/std::nullopt,
-                            /*bidder_ad_beacon_map=*/{},
-                            /*bidder_ad_macro_map=*/{},
-                            /*pa_requests=*/{},
-                            /*reporting_latency=*/base::TimeDelta(), errors);
+  OnBidderReportWinComplete(
+      /*winning_bid=*/0.0,
+      /*highest_scoring_other_bid=*/0.0,
+      /*bidder_report_url=*/std::nullopt,
+      /*bidder_ad_beacon_map=*/{},
+      /*bidder_ad_macro_map=*/{},
+      /*pa_requests=*/{},
+      /*timing_metrics=*/auction_worklet::mojom::BidderTimingMetrics::New(),
+      errors);
 }
 
 void InterestGroupAuctionReporter::OnBidderReportWinComplete(
@@ -944,7 +958,7 @@
     const base::flat_map<std::string, GURL>& bidder_ad_beacon_map,
     const base::flat_map<std::string, std::string>& bidder_ad_macro_map,
     PrivateAggregationRequests pa_requests,
-    base::TimeDelta reporting_latency,
+    auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
     const std::vector<std::string>& errors) {
   TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "bidder_worklet_report_win",
                                   top_level_seller_winning_bid_info_.trace_id);
@@ -960,7 +974,22 @@
       winning_bid_info_.storage_interest_group->interest_group
           .aggregation_coordinator_origin};
   PrivateAggregationTimings timings;
-  timings.script_run_time = reporting_latency;
+
+  timings.script_run_time = timing_metrics->script_latency;
+
+  PrivateAggregationParticipantData& participant_data =
+      all_participants_data_[static_cast<size_t>(
+          PrivateAggregationPhase::kBidder)];
+  AuctionMetricsRecorder::LatencyAggregator code_fetch_time;
+  if (timing_metrics->js_fetch_latency.has_value()) {
+    code_fetch_time.RecordLatency(*timing_metrics->js_fetch_latency);
+  }
+  if (timing_metrics->wasm_fetch_latency.has_value()) {
+    code_fetch_time.RecordLatency(*timing_metrics->wasm_fetch_latency);
+  }
+  participant_data.average_code_fetch_time =
+      code_fetch_time.GetNumRecords() != 0 ? code_fetch_time.GetMeanLatency()
+                                           : base::TimeDelta();
 
   if (!ValidateReportingPrivateAggregationRequests(pa_requests)) {
     pa_requests.clear();
@@ -975,7 +1004,7 @@
         FillInPrivateAggregationRequest(
             std::move(request), winning_bid,
             /*highest_scoring_other_bid=*/highest_scoring_other_bid,
-            /*reject_reason=*/std::nullopt, timings,
+            /*reject_reason=*/std::nullopt, participant_data, timings,
             /*is_winner=*/true);
 
     if (converted_request.has_value()) {
diff --git a/content/browser/interest_group/interest_group_auction_reporter.h b/content/browser/interest_group/interest_group_auction_reporter.h
index 151d14d4..6a9d48bb 100644
--- a/content/browser/interest_group/interest_group_auction_reporter.h
+++ b/content/browser/interest_group/interest_group_auction_reporter.h
@@ -100,6 +100,11 @@
   using PrivateAggregationRequests =
       std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>;
 
+  using PrivateAggregationAllParticipantsData =
+      std::array<PrivateAggregationParticipantData,
+                 base::checked_cast<size_t>(
+                     PrivateAggregationPhase::kNumPhases)>;
+
   // Invoked when private aggregation requests are received from the worklet.
   using LogPrivateAggregationRequestsCallback = base::RepeatingCallback<void(
       const PrivateAggregationRequests& private_aggregation_requests)>;
@@ -258,6 +263,7 @@
           private_aggregation_requests_reserved,
       std::map<std::string, PrivateAggregationRequests>
           private_aggregation_requests_non_reserved,
+      PrivateAggregationAllParticipantsData all_participants_data,
       std::map<url::Origin, RealTimeReportingContributions>
           real_time_contributions);
 
@@ -374,7 +380,7 @@
       const std::optional<GURL>& seller_report_url,
       const base::flat_map<std::string, GURL>& seller_ad_beacon_map,
       PrivateAggregationRequests pa_requests,
-      base::TimeDelta reporting_latency,
+      auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
       const std::vector<std::string>& errors);
 
   // Invoked with the results from ReportResult. Split out as a separate
@@ -411,7 +417,7 @@
       const base::flat_map<std::string, GURL>& bidder_ad_beacon_map,
       const base::flat_map<std::string, std::string>& bidder_ad_macro_map,
       PrivateAggregationRequests pa_requests,
-      base::TimeDelta reporting_latency,
+      auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
       const std::vector<std::string>& errors);
 
   // Invoked with the results from ReportWin. Split out as a separate function
@@ -528,6 +534,9 @@
       private_aggregation_requests_reserved_;
   std::map<std::string, PrivateAggregationRequests>
       private_aggregation_requests_non_reserved_;
+  // Metrics from the parties that took part in winning, in case they want to
+  // request them from the reporting scripts.
+  PrivateAggregationAllParticipantsData all_participants_data_;
 
   // Stores all received pending Real Time Reporting contributions. until their
   // converted histograms flushed. Keyed by the origin of the script that issued
diff --git a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
index a388f2b3..16485d0 100644
--- a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
@@ -288,6 +288,7 @@
             std::move(debug_loss_report_urls_), k_anon_keys_to_join_,
             std::move(private_aggregation_requests_reserved_),
             std::move(private_aggregation_event_map_),
+            std::move(all_participanta_data_),
             std::move(real_time_contributions_));
     interest_group_auction_reporter_->Start(
         base::BindOnce(&InterestGroupAuctionReporterTest::OnCompleteCallback,
@@ -756,6 +757,9 @@
            InterestGroupAuctionReporter::PrivateAggregationRequests>
       private_aggregation_event_map_;
 
+  InterestGroupAuctionReporter::PrivateAggregationAllParticipantsData
+      all_participanta_data_;
+
   // The real time reporting histograms passed in to the constructor.
   std::map<url::Origin,
            InterestGroupAuctionReporter::RealTimeReportingContributions>
diff --git a/content/browser/interest_group/interest_group_pa_report_util.cc b/content/browser/interest_group/interest_group_pa_report_util.cc
index 5a066fa3..a3d3b733 100644
--- a/content/browser/interest_group/interest_group_pa_report_util.cc
+++ b/content/browser/interest_group/interest_group_pa_report_util.cc
@@ -47,6 +47,7 @@
     double winning_bid,
     double highest_scoring_other_bid,
     const std::optional<auction_worklet::mojom::RejectReason> reject_reason,
+    const PrivateAggregationParticipantData& participant_data,
     const PrivateAggregationTimings& timings) {
   // The mojom API declaration should ensure base_value is one of these cases.
   switch (base_value) {
@@ -67,6 +68,10 @@
         return static_cast<int>(reject_reason.value());
       }
       return std::nullopt;
+    case auction_worklet::mojom::BaseValue::kParticipatingInterestGroupCount:
+      return participant_data.participating_interest_group_count;
+    case auction_worklet::mojom::BaseValue::kAverageCodeFetchTime:
+      return participant_data.average_code_fetch_time.InMillisecondsF();
   }
   NOTREACHED();
 }
@@ -179,6 +184,7 @@
     double winning_bid,
     double highest_scoring_other_bid,
     const std::optional<auction_worklet::mojom::RejectReason> reject_reason,
+    const PrivateAggregationParticipantData& participant_data,
     const PrivateAggregationTimings& timings) {
   absl::uint128 bucket;
   int value;
@@ -189,9 +195,9 @@
     auction_worklet::mojom::SignalBucketPtr& bucket_obj =
         contribution->bucket->get_signal_bucket();
     std::optional<absl::uint128> bucket_opt = CalculateBucket(
-        bucket_obj,
-        GetBaseValue(bucket_obj->base_value, winning_bid,
-                     highest_scoring_other_bid, reject_reason, timings));
+        bucket_obj, GetBaseValue(bucket_obj->base_value, winning_bid,
+                                 highest_scoring_other_bid, reject_reason,
+                                 participant_data, timings));
     if (!bucket_opt.has_value()) {
       return nullptr;
     }
@@ -213,9 +219,9 @@
     const auction_worklet::mojom::SignalValuePtr& value_obj =
         contribution->value->get_signal_value();
     std::optional<int> value_opt = CalculateValue(
-        value_obj,
-        GetBaseValue(value_obj->base_value, winning_bid,
-                     highest_scoring_other_bid, reject_reason, timings));
+        value_obj, GetBaseValue(value_obj->base_value, winning_bid,
+                                highest_scoring_other_bid, reject_reason,
+                                participant_data, timings));
     if (!value_opt.has_value()) {
       return nullptr;
     }
@@ -299,6 +305,7 @@
     double winning_bid,
     double highest_scoring_other_bid,
     const std::optional<auction_worklet::mojom::RejectReason> reject_reason,
+    const PrivateAggregationParticipantData& participant_data,
     const PrivateAggregationTimings& timings,
     bool is_winner) {
   CHECK(request);
@@ -353,7 +360,7 @@
   blink::mojom::AggregatableReportHistogramContributionPtr
       calculated_contribution = CalculateContributionBucketAndValue(
           std::move(contribution->get_for_event_contribution()), winning_bid,
-          highest_scoring_other_bid, reject_reason, timings);
+          highest_scoring_other_bid, reject_reason, participant_data, timings);
   if (!calculated_contribution) {
     return std::nullopt;
   }
diff --git a/content/browser/interest_group/interest_group_pa_report_util.h b/content/browser/interest_group/interest_group_pa_report_util.h
index e3c59224..960b313 100644
--- a/content/browser/interest_group/interest_group_pa_report_util.h
+++ b/content/browser/interest_group/interest_group_pa_report_util.h
@@ -48,6 +48,17 @@
   base::TimeDelta signals_fetch_time;
 };
 
+struct CONTENT_EXPORT PrivateAggregationParticipantData {
+  // These metrics are set on bidders only; on sellers they are always 0.
+
+  // Number of interest groups that got selected to make bids (after filtering,
+  // capabilities checks, discarding those w/o ads, etc).
+  int participating_interest_group_count = 0;
+
+  // These metrics are set for both bidders and sellers.
+  base::TimeDelta average_code_fetch_time;
+};
+
 // Key used to group Private aggregation signals.
 struct CONTENT_EXPORT PrivateAggregationKey {
   PrivateAggregationKey(
@@ -118,6 +129,7 @@
     double winning_bid,
     double highest_scoring_other_bid,
     const std::optional<auction_worklet::mojom::RejectReason> reject_reason,
+    const PrivateAggregationParticipantData& participant_data,
     const PrivateAggregationTimings& timings,
     bool is_winner);
 
diff --git a/content/browser/interest_group/interest_group_pa_report_util_unittest.cc b/content/browser/interest_group/interest_group_pa_report_util_unittest.cc
index 1c25ed65..fe8720b 100644
--- a/content/browser/interest_group/interest_group_pa_report_util_unittest.cc
+++ b/content/browser/interest_group/interest_group_pa_report_util_unittest.cc
@@ -173,18 +173,22 @@
       blink::mojom::DebugModeDetails::New());
 
   EXPECT_EQ(kExpectedRequestWithReservedEventType,
-            FillInPrivateAggregationRequest(
-                request.Clone(),
-                /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-                /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
-                /*is_winner=*/true));
+            FillInPrivateAggregationRequest(request.Clone(),
+                                            /*winning_bid=*/1,
+                                            /*highest_scoring_other_bid=*/2,
+                                            /*reject_reason=*/std::nullopt,
+                                            PrivateAggregationParticipantData(),
+                                            PrivateAggregationTimings(),
+                                            /*is_winner=*/true));
 
   EXPECT_EQ(kExpectedRequestWithReservedEventType,
-            FillInPrivateAggregationRequest(
-                request.Clone(),
-                /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-                /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
-                /*is_winner=*/false));
+            FillInPrivateAggregationRequest(request.Clone(),
+                                            /*winning_bid=*/1,
+                                            /*highest_scoring_other_bid=*/2,
+                                            /*reject_reason=*/std::nullopt,
+                                            PrivateAggregationParticipantData(),
+                                            PrivateAggregationTimings(),
+                                            /*is_winner=*/false));
 }
 
 // FillInPrivateAggregationRequest() sets returned request's
@@ -203,11 +207,13 @@
   PrivateAggregationRequestWithEventType request_with_event_type(
       request.Clone(), /*event_type=*/std::nullopt);
   EXPECT_EQ(std::move(request_with_event_type),
-            FillInPrivateAggregationRequest(
-                request.Clone(),
-                /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-                /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
-                /*is_winner=*/true));
+            FillInPrivateAggregationRequest(request.Clone(),
+                                            /*winning_bid=*/1,
+                                            /*highest_scoring_other_bid=*/2,
+                                            /*reject_reason=*/std::nullopt,
+                                            PrivateAggregationParticipantData(),
+                                            PrivateAggregationTimings(),
+                                            /*is_winner=*/true));
 }
 
 TEST_F(InterestGroupPaReportUtilTest, ForEventContributionReservedEventType) {
@@ -220,7 +226,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedAlways)),
           /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
   EXPECT_EQ(
       kExpectedRequestWithReservedEventType,
@@ -231,7 +238,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedAlways)),
           /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/false));
 
   EXPECT_EQ(
@@ -243,7 +251,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
   EXPECT_FALSE(FillInPrivateAggregationRequest(
       CreateForEventRequest(
@@ -251,7 +260,8 @@
           /*event_type=*/
           Reserved(auction_worklet::mojom::ReservedEventType::kReservedWin)),
       /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-      /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+      /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+      PrivateAggregationTimings(),
       /*is_winner=*/false));
 
   EXPECT_EQ(
@@ -263,7 +273,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedLoss)),
           /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/false));
   EXPECT_FALSE(FillInPrivateAggregationRequest(
       CreateForEventRequest(
@@ -271,7 +282,8 @@
           /*event_type=*/
           Reserved(auction_worklet::mojom::ReservedEventType::kReservedLoss)),
       /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-      /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+      /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+      PrivateAggregationTimings(),
       /*is_winner=*/true));
 
   // reserved.once works and doesn't care about winner/loser.
@@ -285,33 +297,38 @@
                 Reserved(
                     auction_worklet::mojom::ReservedEventType::kReservedOnce)),
             /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-            /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+            /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+            PrivateAggregationTimings(),
             /*is_winner=*/is_winner));
   }
 }
 
 TEST_F(InterestGroupPaReportUtilTest,
        ForEventContributionNonReservedEventType) {
-  EXPECT_EQ(CreatePrivateAggregationRequestWithEventType(
-                CreateHistogramRequest(/*bucket=*/123, /*value=*/45),
-                /*event_type=*/"click"),
-            FillInPrivateAggregationRequest(
-                CreateForEventRequest(/*bucket=*/123, /*value=*/45,
-                                      /*event_type=*/NonReserved("click")),
-                /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-                /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
-                /*is_winner=*/true));
+  EXPECT_EQ(
+      CreatePrivateAggregationRequestWithEventType(
+          CreateHistogramRequest(/*bucket=*/123, /*value=*/45),
+          /*event_type=*/"click"),
+      FillInPrivateAggregationRequest(
+          CreateForEventRequest(/*bucket=*/123, /*value=*/45,
+                                /*event_type=*/NonReserved("click")),
+          /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
+          /*is_winner=*/true));
 
-  EXPECT_EQ(CreatePrivateAggregationRequestWithEventType(
-                CreateHistogramRequest(/*bucket=*/123, /*value=*/45),
-                /*event_type=*/"arbitrary.non.reserved"),
-            FillInPrivateAggregationRequest(
-                CreateForEventRequest(
-                    /*bucket=*/123, /*value=*/45,
-                    /*event_type=*/NonReserved("arbitrary.non.reserved")),
-                /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-                /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
-                /*is_winner=*/true));
+  EXPECT_EQ(
+      CreatePrivateAggregationRequestWithEventType(
+          CreateHistogramRequest(/*bucket=*/123, /*value=*/45),
+          /*event_type=*/"arbitrary.non.reserved"),
+      FillInPrivateAggregationRequest(
+          CreateForEventRequest(
+              /*bucket=*/123, /*value=*/45,
+              /*event_type=*/NonReserved("arbitrary.non.reserved")),
+          /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
+          /*is_winner=*/true));
 
   // The prefix is "reserved", not "reserved.", so still a valid non-reserved
   // event type.
@@ -323,7 +340,8 @@
           CreateForEventRequest(/*bucket=*/123, /*value=*/45,
                                 /*event_type=*/NonReserved("reserved-no-dot")),
           /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 
   // Requests of non-reserved event types are not kept for losing bidders.
@@ -331,7 +349,8 @@
       CreateForEventRequest(/*bucket=*/123, /*value=*/45,
                             /*event_type=*/NonReserved("click")),
       /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-      /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+      /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+      PrivateAggregationTimings(),
       /*is_winner=*/false));
 }
 
@@ -348,7 +367,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/10, /*highest_scoring_other_bid=*/1,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 
   // Value should be int(2.2 * 10) + 23 = 45.
@@ -362,7 +382,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/2.2, /*highest_scoring_other_bid=*/1,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 }
 
@@ -382,7 +403,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/15, /*highest_scoring_other_bid=*/14.6,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 
   // Value should be int(6.8 * 10) - 23 = 45.
@@ -398,7 +420,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/15, /*highest_scoring_other_bid=*/6.8,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 }
 
@@ -424,7 +447,7 @@
           /*winning_bid=*/0, /*highest_scoring_other_bid=*/0,
           /*reject_reason=*/
           auction_worklet::mojom::RejectReason::kPendingApprovalByExchange,
-          PrivateAggregationTimings(),
+          PrivateAggregationParticipantData(), PrivateAggregationTimings(),
           /*is_winner=*/false));
 
   // kInvalidBid is 1. Value should be int(1 * 39) + 6 = 45.
@@ -441,7 +464,7 @@
                   auction_worklet::mojom::ReservedEventType::kReservedLoss)),
           /*winning_bid=*/0, /*highest_scoring_other_bid=*/0,
           /*reject_reason=*/auction_worklet::mojom::RejectReason::kInvalidBid,
-          PrivateAggregationTimings(),
+          PrivateAggregationParticipantData(), PrivateAggregationTimings(),
           /*is_winner=*/false));
 
   // kNotAvailable is also reported. kNotAvailable is 0, so bucket is 0 * 39 + 6
@@ -465,7 +488,7 @@
                   auction_worklet::mojom::ReservedEventType::kReservedLoss)),
           /*winning_bid=*/2, /*highest_scoring_other_bid=*/1,
           /*reject_reason=*/auction_worklet::mojom::RejectReason::kNotAvailable,
-          PrivateAggregationTimings(),
+          PrivateAggregationParticipantData(), PrivateAggregationTimings(),
           /*is_winner=*/false));
 
   // FillInPrivateAggregationRequest() should return nullptr when its
@@ -477,7 +500,8 @@
           /*event_type=*/
           Reserved(auction_worklet::mojom::ReservedEventType::kReservedLoss)),
       /*winning_bid=*/0, /*highest_scoring_other_bid=*/0,
-      /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+      /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+      PrivateAggregationTimings(),
       /*is_winner=*/false));
 }
 
@@ -507,7 +531,8 @@
                     auction_worklet::mojom::ReservedEventType::kReservedLoss)),
             /*winning_bid=*/0, /*highest_scoring_other_bid=*/0,
             /*reject_reason=*/
-            auction_worklet::mojom::RejectReason::kNotAvailable, pa_timings,
+            auction_worklet::mojom::RejectReason::kNotAvailable,
+            PrivateAggregationParticipantData(), pa_timings,
             /*is_winner=*/false));
   }
 
@@ -533,7 +558,64 @@
                     auction_worklet::mojom::ReservedEventType::kReservedLoss)),
             /*winning_bid=*/0, /*highest_scoring_other_bid=*/0,
             /*reject_reason=*/
-            auction_worklet::mojom::RejectReason::kNotAvailable, pa_timings,
+            auction_worklet::mojom::RejectReason::kNotAvailable,
+            PrivateAggregationParticipantData(), pa_timings,
+            /*is_winner=*/false));
+  }
+}
+
+TEST_F(InterestGroupPaReportUtilTest, ForEventContributionBaseParticipantData) {
+  PrivateAggregationParticipantData pa_data;
+  pa_data.participating_interest_group_count = 40;
+  pa_data.average_code_fetch_time = base::Milliseconds(4.5);
+  {
+    auction_worklet::mojom::SignalBucket signal_bucket_script(
+        /*base_value=*/auction_worklet::mojom::BaseValue::
+            kParticipatingInterestGroupCount,
+        /*scale=*/1,
+        /*offset=*/
+        auction_worklet::mojom::BucketOffset::New(/*value=*/0,
+                                                  /*is_negative=*/false));
+
+    EXPECT_EQ(
+        CreatePrivateAggregationRequestWithEventType(
+            CreateHistogramRequest(/*bucket=*/40, /*value=*/45),
+            /*event_type=*/std::nullopt),
+        FillInPrivateAggregationRequest(
+            CreateForEventRequestWithBucketObject(
+                /*bucket=*/signal_bucket_script.Clone(), /*value=*/45,
+                /*event_type=*/
+                Reserved(
+                    auction_worklet::mojom::ReservedEventType::kReservedLoss)),
+            /*winning_bid=*/0, /*highest_scoring_other_bid=*/0,
+            /*reject_reason=*/
+            auction_worklet::mojom::RejectReason::kNotAvailable, pa_data,
+            PrivateAggregationTimings(),
+            /*is_winner=*/false));
+  }
+
+  {
+    auction_worklet::mojom::SignalBucket signal_bucket_script(
+        /*base_value=*/auction_worklet::mojom::BaseValue::kAverageCodeFetchTime,
+        /*scale=*/1,
+        /*offset=*/
+        auction_worklet::mojom::BucketOffset::New(/*value=*/0,
+                                                  /*is_negative=*/false));
+
+    EXPECT_EQ(
+        CreatePrivateAggregationRequestWithEventType(
+            CreateHistogramRequest(/*bucket=*/4, /*value=*/46),
+            /*event_type=*/std::nullopt),
+        FillInPrivateAggregationRequest(
+            CreateForEventRequestWithBucketObject(
+                /*bucket=*/signal_bucket_script.Clone(), /*value=*/46,
+                /*event_type=*/
+                Reserved(
+                    auction_worklet::mojom::ReservedEventType::kReservedLoss)),
+            /*winning_bid=*/0, /*highest_scoring_other_bid=*/0,
+            /*reject_reason=*/
+            auction_worklet::mojom::RejectReason::kNotAvailable, pa_data,
+            PrivateAggregationTimings(),
             /*is_winner=*/false));
   }
 }
@@ -552,7 +634,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedAlways)),
           /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/false));
 
   // Calculated negative value should be clamped to 0.
@@ -569,7 +652,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/1, /*highest_scoring_other_bid=*/6.8,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 }
 
@@ -588,7 +672,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/123, /*highest_scoring_other_bid=*/1,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 
   // No scale or offset are provided to value.
@@ -605,7 +690,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/45, /*highest_scoring_other_bid=*/1,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 }
 
@@ -627,7 +713,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/123, /*highest_scoring_other_bid=*/1,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 
   auction_worklet::mojom::SignalValue value(
@@ -647,7 +734,8 @@
               Reserved(
                   auction_worklet::mojom::ReservedEventType::kReservedWin)),
           /*winning_bid=*/45, /*highest_scoring_other_bid=*/1,
-          /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+          /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+          PrivateAggregationTimings(),
           /*is_winner=*/true));
 }
 
@@ -732,7 +820,8 @@
                              kReservedAlways)),
             /*winning_bid=*/test_case.base,
             /*highest_scoring_other_bid=*/0,
-            /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+            /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+            PrivateAggregationTimings(),
             /*is_winner=*/true);
     if (test_case.expected_bucket.has_value()) {
       ASSERT_TRUE(request.has_value());
@@ -806,7 +895,8 @@
                              kReservedAlways)),
             /*winning_bid=*/test_case.base,
             /*highest_scoring_other_bid=*/0,
-            /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
+            /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+            PrivateAggregationTimings(),
             /*is_winner=*/true);
 
     if (test_case.expected_value.has_value()) {
@@ -831,17 +921,19 @@
   for (std::optional<uint64_t> filtering_id : kFilteringIdTestCases) {
     // Filtering ID here is expected to be unchanged
     std::optional<uint64_t> expected_filtering_id = filtering_id;
-    EXPECT_EQ(CreatePrivateAggregationRequestWithEventType(
-                  CreateHistogramRequest(/*bucket=*/123, /*value=*/45,
-                                         expected_filtering_id),
-                  /*event_type=*/"click"),
-              FillInPrivateAggregationRequest(
-                  CreateForEventRequest(
-                      /*bucket=*/123, /*value=*/45,
-                      /*event_type=*/NonReserved("click"), filtering_id),
-                  /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
-                  /*reject_reason=*/std::nullopt, PrivateAggregationTimings(),
-                  /*is_winner=*/true));
+    EXPECT_EQ(
+        CreatePrivateAggregationRequestWithEventType(
+            CreateHistogramRequest(/*bucket=*/123, /*value=*/45,
+                                   expected_filtering_id),
+            /*event_type=*/"click"),
+        FillInPrivateAggregationRequest(
+            CreateForEventRequest(
+                /*bucket=*/123, /*value=*/45,
+                /*event_type=*/NonReserved("click"), filtering_id),
+            /*winning_bid=*/1, /*highest_scoring_other_bid=*/2,
+            /*reject_reason=*/std::nullopt, PrivateAggregationParticipantData(),
+            PrivateAggregationTimings(),
+            /*is_winner=*/true));
   }
 }
 
diff --git a/content/browser/interest_group/interest_group_storage.cc b/content/browser/interest_group/interest_group_storage.cc
index 523d4e4a..07c0044b 100644
--- a/content/browser/interest_group/interest_group_storage.cc
+++ b/content/browser/interest_group/interest_group_storage.cc
@@ -1013,7 +1013,7 @@
 
 // Initializes the tables, returning true on success.
 // The tables cannot exist when calling this function.
-bool CreateV29Schema(sql::Database& db) {
+bool CreateCurrentSchema(sql::Database& db) {
   DCHECK(!db.DoesTableExist("interest_groups"));
   static const char kInterestGroupTableSql[] =
       // clang-format off
@@ -5593,7 +5593,7 @@
   }
 
   if (new_db) {
-    bool create_schema_result = CreateV29Schema(*db_);
+    bool create_schema_result = CreateCurrentSchema(*db_);
     ReportCreateSchemaResult(
         /*create_schema_result=*/create_schema_result,
         /*raze_if_incompatible_result=*/raze_if_incompatible_result,
diff --git a/content/browser/interest_group/mock_auction_process_manager.cc b/content/browser/interest_group/mock_auction_process_manager.cc
index 80570687..2e3fb73 100644
--- a/content/browser/interest_group/mock_auction_process_manager.cc
+++ b/content/browser/interest_group/mock_auction_process_manager.cc
@@ -219,6 +219,13 @@
   bidding_latency_ = delta;
 }
 
+void MockBidderWorklet::SetCodeFetchLatencies(
+    std::optional<base::TimeDelta> js_fetch_latency,
+    std::optional<base::TimeDelta> wasm_fetch_latency) {
+  js_fetch_latency_ = js_fetch_latency;
+  wasm_fetch_latency_ = wasm_fetch_latency;
+}
+
 void MockBidderWorklet::InvokeGenerateBidCallback(
     std::optional<double> bid,
     const std::optional<blink::AdCurrency>& bid_currency,
@@ -262,6 +269,12 @@
             /*generate_bid_finish_time=*/base::TimeTicks::Now());
   }
 
+  std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+      non_kanon_pa_requests;
+  for (const auto& request : non_kanon_pa_requests_) {
+    non_kanon_pa_requests.push_back(request->Clone());
+  }
+
   std::vector<auction_worklet::mojom::BidderWorkletBidPtr> bids;
   if (!bid.has_value()) {
     DCHECK(further_bids.empty());
@@ -274,9 +287,13 @@
         base::flat_map<std::string,
                        auction_worklet::mojom::PrioritySignalsDoublePtr>(),
         /*pa_requests=*/std::move(pa_requests),
-        /*non_kanon_pa_requests=*/{},
+        /*non_kanon_pa_requests=*/std::move(non_kanon_pa_requests),
         /*real_time_contributions=*/{},
-        /*bidding_latency=*/bidding_latency_,
+        /*generate_bid_metrics=*/
+        auction_worklet::mojom::BidderTimingMetrics::New(
+            /*js_fetch_latency=*/js_fetch_latency_,
+            /*wasm_fetch_latency=*/wasm_fetch_latency_,
+            /*script_latency=*/bidding_latency_),
         /*generate_bid_dependency_latencies=*/std::move(dependency_latencies),
         reject_reason,
         /*errors=*/std::vector<std::string>());
@@ -299,9 +316,13 @@
       base::flat_map<std::string,
                      auction_worklet::mojom::PrioritySignalsDoublePtr>(),
       /*pa_requests=*/std::move(pa_requests),
-      /*non_kanon_pa_requests=*/{},
+      /*non_kanon_pa_requests=*/std::move(non_kanon_pa_requests),
       /*real_time_contributions=*/std::move(real_time_contributions),
-      /*bidding_latency=*/bidding_latency_,
+      /*generated_bid_metrics=*/
+      auction_worklet::mojom::BidderTimingMetrics::New(
+          /*js_fetch_latency=*/js_fetch_latency_,
+          /*wasm_fetch_latency=*/wasm_fetch_latency_,
+          /*script_latency=*/bidding_latency_),
       /*generate_bid_dependency_latencies=*/std::move(dependency_latencies),
       reject_reason,
       /*errors=*/std::vector<std::string>());
@@ -328,7 +349,12 @@
   DCHECK(report_win_callback_);
   std::move(report_win_callback_)
       .Run(report_url, std::move(ad_beacon_map), std::move(ad_macro_map),
-           std::move(pa_requests), reporting_latency_, std::move(errors));
+           std::move(pa_requests),
+           auction_worklet::mojom::BidderTimingMetrics::New(
+               /*js_fetch_latency=*/js_fetch_latency_,
+               /*wasm_fetch_latency=*/wasm_fetch_latency_,
+               /*script_latency=*/reporting_latency_),
+           std::move(errors));
 }
 
 void MockBidderWorklet::Flush() {
@@ -510,7 +536,11 @@
   DCHECK(report_result_callback_);
   std::move(report_result_callback_)
       .Run(/*signals_for_winner=*/std::nullopt, std::move(report_url),
-           ad_beacon_map, std::move(pa_requests), reporting_latency_, errors);
+           ad_beacon_map, std::move(pa_requests),
+           auction_worklet::mojom::SellerTimingMetrics::New(
+               /*js_fetch_latency=*/js_fetch_latency_,
+               /*script_latency=*/reporting_latency_),
+           errors);
 }
 
 void MockSellerWorklet::Flush() {
diff --git a/content/browser/interest_group/mock_auction_process_manager.h b/content/browser/interest_group/mock_auction_process_manager.h
index e37efb6..2f005369 100644
--- a/content/browser/interest_group/mock_auction_process_manager.h
+++ b/content/browser/interest_group/mock_auction_process_manager.h
@@ -142,12 +142,22 @@
   // OnGenerateBidComplete()), respectively, to return `delta`.
   void SetBidderTrustedSignalsFetchLatency(base::TimeDelta delta);
   void SetBiddingLatency(base::TimeDelta delta);
+  void SetCodeFetchLatencies(std::optional<base::TimeDelta> js_fetch_latency,
+                             std::optional<base::TimeDelta> wasm_fetch_latency);
 
   // Same for `reporting_latency` for ReportWin()
   void SetReportingLatency(base::TimeDelta delta) {
     reporting_latency_ = delta;
   }
 
+  // Controls what's passed to `non_kanon_pa_requests` of the generate bid
+  // callback.
+  void SetNonKAnonPARequests(
+      std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+          non_kanon_pa_requests) {
+    non_kanon_pa_requests_ = std::move(non_kanon_pa_requests);
+  }
+
   // Invokes the GenerateBid callback. A bid of base::nullopt means no bid
   // should be offered. Waits for the GenerateBid() call first, if needed.
   void InvokeGenerateBidCallback(
@@ -210,6 +220,9 @@
 
   std::optional<std::string> selected_buyer_and_seller_reporting_id_;
 
+  std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
+      non_kanon_pa_requests_;
+
   std::unique_ptr<base::RunLoop> generate_bid_run_loop_;
   std::unique_ptr<base::RunLoop> report_win_run_loop_;
   ReportWinCallback report_win_callback_;
@@ -231,6 +244,8 @@
   // OnGenerateBidComplete()), respectively,
   base::TimeDelta trusted_signals_fetch_latency_;
   base::TimeDelta bidding_latency_;
+  std::optional<base::TimeDelta> js_fetch_latency_;
+  std::optional<base::TimeDelta> wasm_fetch_latency_;
 
   // To be fed as `reporting_latency` to ReportWin() callback.
   base::TimeDelta reporting_latency_;
@@ -365,6 +380,10 @@
     expect_send_pending_signals_requests_called_ = value;
   }
 
+  void SetCodeFetchLatency(std::optional<base::TimeDelta> js_fetch_latency) {
+    js_fetch_latency_ = js_fetch_latency;
+  }
+
  private:
   std::unique_ptr<base::RunLoop> score_ad_run_loop_;
   std::list<ScoreAdParams> score_ad_params_;
@@ -378,6 +397,9 @@
   // To be fed as `reporting_latency` to ReportResult() callback.
   base::TimeDelta reporting_latency_;
 
+  // Used for reporting callback as well.
+  std::optional<base::TimeDelta> js_fetch_latency_;
+
   // Receiver is last so that destroying `this` while there's a pending callback
   // over the pipe will not DCHECK.
   mojo::Receiver<auction_worklet::mojom::SellerWorklet> receiver_;
diff --git a/content/browser/interest_group/trusted_signals_fetcher.cc b/content/browser/interest_group/trusted_signals_fetcher.cc
index c0c76db..d9e31a6 100644
--- a/content/browser/interest_group/trusted_signals_fetcher.cc
+++ b/content/browser/interest_group/trusted_signals_fetcher.cc
@@ -484,25 +484,22 @@
     ttl = base::Milliseconds(std::max(0, ttl_ms_value->GetInt()));
   }
 
-  const std::string* content = compression_group_dict.FindString("content");
+  const auto* content = compression_group_dict.FindBlob("content");
   if (!content) {
-    return base::unexpected(CreateError(
-        base::StringPrintf("Compression group %i missing content string",
-                           *compression_group_id_opt)));
+    return base::unexpected(CreateError(base::StringPrintf(
+        "Compression group %i missing binary string \"content\"",
+        *compression_group_id_opt)));
   }
 
   compression_group_id = *compression_group_id_opt;
 
   CompressionGroupResult result;
   result.compression_scheme = compression_scheme_;
-  // TODO(crbug.com/333445540): This copy is unnecessary, since Value::Dict
-  // allows its values to be moved. Instead, make `compression_group_data` a
-  // std::string. Can then either switch the API to using a mojom::BigString and
-  // pass to Mojo as a std::string, and have the other end use BigBuffer
-  // directly (Which is what mojom::BigString is typemapped to), or continue to
-  // use mojom::BigBuffer pass as a span<uint8_t>.
-  result.compression_group_data =
-      std::vector<uint8_t>(content->begin(), content->end());
+  // TODO(crbug.com/333445540): This copy is only necessary because Value::Dict
+  // does not allow blob/binary types to be moved, unlike std::strings. Modify
+  // base::Value to allow that, and switch this code to take advantage of the
+  // capability.
+  result.compression_group_data = *content;
   result.ttl = ttl;
   return result;
 }
diff --git a/content/browser/interest_group/trusted_signals_fetcher_unittest.cc b/content/browser/interest_group/trusted_signals_fetcher_unittest.cc
index 8bbb07c..7fb7f7c 100644
--- a/content/browser/interest_group/trusted_signals_fetcher_unittest.cc
+++ b/content/browser/interest_group/trusted_signals_fetcher_unittest.cc
@@ -134,7 +134,7 @@
   // }
   const std::string_view kDefaultResponseBody =
       "A171636F6D7072657373696F6E47726F75707381A36574746C4D73186467636F6E74656E"
-      "747819636F6D7072657373696F6E2067726F757020636F6E74656E7472636F6D70726573"
+      "745819636F6D7072657373696F6E2067726F757020636F6E74656E7472636F6D70726573"
       "73696F6E47726F7570496400";
 
   TrustedSignalsFetcherTest() {
@@ -766,7 +766,7 @@
   //   ]
   // }
   SetResponseBodyAndAddHeaderFromHex(
-      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7467636F6E74656E"
+      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7447636F6E74656E"
       "7472636F6D7072657373696F6E47726F7570496403");
 
   auto result = RequestBiddingSignalsAndWaitForResult(bidding_signals_request);
@@ -1103,7 +1103,7 @@
       //     }
       //   ]
       // }
-      "A171636F6D7072657373696F6E47726F75707381A167636F6E74656E7467636F6E74656E"
+      "A171636F6D7072657373696F6E47726F75707381A167636F6E74656E7447636F6E74656E"
       "74",
 
       // {
@@ -1114,7 +1114,7 @@
       //     }
       //   ]
       // }
-      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7467636F6E74656E"
+      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7447636F6E74656E"
       "7472636F6D7072657373696F6E47726F75704964634A696D",
 
       // {
@@ -1125,7 +1125,7 @@
       //     }
       //   ]
       // }
-      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7467636F6E74656E"
+      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7447636F6E74656E"
       "7472636F6D7072657373696F6E47726F7570496420",
 
       // {
@@ -1136,7 +1136,7 @@
       //     }
       //   ]
       // }
-      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7467636F6E74656E"
+      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7447636F6E74656E"
       "7472636F6D7072657373696F6E47726F75704964F90000",
   };
 
@@ -1192,7 +1192,7 @@
       //     }
       //   ]
       // }
-      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E748167636F6E7465"
+      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E748147636F6E7465"
       "6E7472636F6D7072657373696F6E47726F7570496402",
   };
 
@@ -1205,7 +1205,7 @@
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error(),
               base::StringPrintf("Failed to load %s: Compression group %" PRIuS
-                                 " missing content string.",
+                                 " missing binary string \"content\".",
                                  TrustedBiddingSignalsUrl().spec().c_str(), i));
     ValidateRequestBody(kBasicBiddingSignalsRequestBody);
   }
@@ -1228,7 +1228,7 @@
       //   ]
       // }
       "A171636F6D7072657373696F6E47726F75707381A36574746C4D736A6772617065667275"
-      "697467636F6E74656E7467636F6E74656E7472636F6D7072657373696F6E47726F757049"
+      "697467636F6E74656E7447636F6E74656E7472636F6D7072657373696F6E47726F757049"
       "6400",
 
       // {
@@ -1241,7 +1241,7 @@
       //   ]
       // }
       "A171636F6D7072657373696F6E47726F75707381A36574746C4D73F9380067636F6E7465"
-      "6E7467636F6E74656E7472636F6D7072657373696F6E47726F7570496401",
+      "6E7447636F6E74656E7472636F6D7072657373696F6E47726F7570496401",
   };
 
   for (size_t i = 0; i < kTestCases.size(); ++i) {
@@ -1271,7 +1271,7 @@
   //   ]
   // }
   SetResponseBodyAndAddHeaderFromHex(
-      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7467636F6E74656E"
+      "A171636F6D7072657373696F6E47726F75707381A267636F6E74656E7447636F6E74656E"
       "7472636F6D7072657373696F6E47726F7570496400");
   auto bidding_signals_request = CreateBasicBiddingSignalsRequest();
   auto result = RequestBiddingSignalsAndWaitForResult(bidding_signals_request);
@@ -1296,7 +1296,7 @@
   // }
   SetResponseBodyAndAddHeaderFromHex(
       "A171636F6D7072657373696F6E47726F75707381A36574746C4D730067636F6E74656E74"
-      "67636F6E74656E7472636F6D7072657373696F6E47726F7570496400");
+      "47636F6E74656E7472636F6D7072657373696F6E47726F7570496400");
   auto bidding_signals_request = CreateBasicBiddingSignalsRequest();
   auto result = RequestBiddingSignalsAndWaitForResult(bidding_signals_request);
   TrustedSignalsFetcher::CompressionGroupResultMap expected_result;
@@ -1321,7 +1321,7 @@
   // }
   SetResponseBodyAndAddHeaderFromHex(
       "A171636F6D7072657373696F6E47726F75707381A36574746C4D732067636F6E74656E74"
-      "67636F6E74656E7472636F6D7072657373696F6E47726F7570496400");
+      "47636F6E74656E7472636F6D7072657373696F6E47726F7570496400");
   auto bidding_signals_request = CreateBasicBiddingSignalsRequest();
   auto result = RequestBiddingSignalsAndWaitForResult(bidding_signals_request);
   TrustedSignalsFetcher::CompressionGroupResultMap expected_result;
@@ -1453,8 +1453,8 @@
   //   ]
   // }
   SetResponseBodyAndAddHeaderFromHex(
-      "A171636F6D7072657373696F6E47726F75707382A267636F6E74656E7467636F6E74656E"
-      "7472636F6D7072657373696F6E47726F7570496400A267636F6E74656E7467636F6E7465"
+      "A171636F6D7072657373696F6E47726F75707382A267636F6E74656E7447636F6E74656E"
+      "7472636F6D7072657373696F6E47726F7570496400A267636F6E74656E7447636F6E7465"
       "6E7472636F6D7072657373696F6E47726F7570496400");
 
   auto bidding_signals_request = CreateBasicBiddingSignalsRequest();
@@ -1590,9 +1590,9 @@
   // }
   SetResponseBodyAndAddHeaderFromHex(
       "A171636F6D7072657373696F6E47726F75707383A36574746C4D730A67636F6E74656E74"
-      "68636F6E74656E743172636F6D7072657373696F6E47726F7570496400A267636F6E7465"
-      "6E7468636F6E74656E743272636F6D7072657373696F6E47726F7570496401A36574746C"
-      "4D73189667636F6E74656E7468636F6E74656E743372636F6D7072657373696F6E47726F"
+      "48636F6E74656E743172636F6D7072657373696F6E47726F7570496400A267636F6E7465"
+      "6E7448636F6E74656E743272636F6D7072657373696F6E47726F7570496401A36574746C"
+      "4D73189667636F6E74656E7448636F6E74656E743372636F6D7072657373696F6E47726F"
       "7570496402");
 
   auto result = RequestBiddingSignalsAndWaitForResult(bidding_signals_request);
@@ -1739,17 +1739,16 @@
   // }
   SetResponseBodyAndAddHeaderFromHex(
       "A171636F6D7072657373696F6E47726F75707383A36574746C4D730A67636F6E74656E74"
-      "68636F6E74656E743172636F6D7072657373696F6E47726F7570496400A267636F6E7465"
+      "48636F6E74656E743172636F6D7072657373696F6E47726F7570496400A267636F6E7465"
       "6E740272636F6D7072657373696F6E47726F7570496401A36574746C4D73189667636F6E"
-      "74656E7468636F6E74656E743372636F6D7072657373696F6E47726F7570496402");
+      "74656E7448636F6E74656E743372636F6D7072657373696F6E47726F7570496402");
 
   auto result = RequestBiddingSignalsAndWaitForResult(bidding_signals_request);
   ASSERT_FALSE(result.has_value());
-  EXPECT_EQ(
-      result.error(),
-      base::StringPrintf(
-          "Failed to load %s: Compression group 1 missing content string.",
-          TrustedBiddingSignalsUrl().spec().c_str()));
+  EXPECT_EQ(result.error(),
+            base::StringPrintf("Failed to load %s: Compression group 1 missing "
+                               "binary string \"content\".",
+                               TrustedBiddingSignalsUrl().spec().c_str()));
   ValidateRequestBody(kExpectedRequestBody);
 }
 
diff --git a/content/browser/navigation_transitions/back_forward_transition_animation_manager_android_browsertest.cc b/content/browser/navigation_transitions/back_forward_transition_animation_manager_android_browsertest.cc
index ae7a21d..9bbb57e 100644
--- a/content/browser/navigation_transitions/back_forward_transition_animation_manager_android_browsertest.cc
+++ b/content/browser/navigation_transitions/back_forward_transition_animation_manager_android_browsertest.cc
@@ -3114,6 +3114,79 @@
   EXPECT_STATE_EQ(kAnimationAborted, destroyed.Get());
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardTransitionAnimationManagerBrowserTest,
+                       ScreenshotCompression) {
+  SkBitmap expected_pixels;
+  {
+    NavigationEntryScreenshot::SetDisableCompressionForTesting(true);
+    ASSERT_EQ(web_contents()->GetController().GetLastCommittedEntry()->GetURL(),
+              GreenURL());
+    GetAnimationManager()->OnGestureStarted(
+        ui::BackGestureEvent(0), SwipeEdge::LEFT, NavType::kBackward);
+    GetAnimationManager()->OnGestureProgressed(ui::BackGestureEvent(0.6));
+
+    TestFuture<gfx::Image> result;
+    auto* window = web_contents()->GetNativeView()->GetWindowAndroid();
+    ui::GrabWindowSnapshot(window, gfx::Rect(), result.GetCallback());
+    expected_pixels = result.Get().AsBitmap();
+    ASSERT_FALSE(expected_pixels.empty());
+
+    for (int col = 0.6 * expected_pixels.width() + 1;
+         col < expected_pixels.width(); col++) {
+      for (int row = 0; row < expected_pixels.height(); row++) {
+        ASSERT_EQ(expected_pixels.getColor(col, row), SK_ColorGREEN)
+            << col << "," << row << " and image "
+            << cc::GetPNGDataUrl(expected_pixels);
+      }
+    }
+
+    TestFuture<AnimatorState> destroyed;
+    GetAnimator()->set_on_impl_destroyed(destroyed.GetCallback());
+    ScopedScreenshotCapturedObserverForTesting observer(
+        web_contents()->GetController().GetLastCommittedEntryIndex());
+    GetAnimationManager()->OnGestureInvoked();
+    ASSERT_TRUE(destroyed.Wait());
+    ASSERT_EQ(web_contents()->GetController().GetLastCommittedEntry()->GetURL(),
+              RedURL());
+    observer.Wait();
+  }
+
+  SkBitmap actual_pixels;
+  {
+    NavigationEntryScreenshot::SetDisableCompressionForTesting(false);
+    ScopedScreenshotCapturedObserverForTesting observer(
+        web_contents()->GetController().GetLastCommittedEntryIndex());
+    ASSERT_TRUE(NavigateToURL(web_contents(), GreenURL()));
+    observer.Wait();
+    WaitForCopyableViewInWebContents(web_contents());
+    NavigationTransitionTestUtils::WaitForScreenshotCompressed(
+        web_contents()->GetController(),
+        web_contents()->GetController().GetLastCommittedEntryIndex() - 1);
+
+    GetAnimationManager()->OnGestureStarted(
+        ui::BackGestureEvent(0), SwipeEdge::LEFT, NavType::kBackward);
+    GetAnimationManager()->OnGestureProgressed(ui::BackGestureEvent(0.6));
+
+    TestFuture<gfx::Image> result;
+    auto* window = web_contents()->GetNativeView()->GetWindowAndroid();
+    ui::GrabWindowSnapshot(window, gfx::Rect(), result.GetCallback());
+    actual_pixels = result.Get().AsBitmap();
+    ASSERT_FALSE(actual_pixels.empty());
+
+    TestFuture<AnimatorState> destroyed;
+    GetAnimator()->set_on_impl_destroyed(destroyed.GetCallback());
+    GetAnimationManager()->OnGestureCancelled();
+    ASSERT_TRUE(destroyed.Wait());
+  }
+
+  // Allow all pixels to be off by 1.
+  auto comparator = cc::FuzzyPixelComparator()
+                        .SetErrorPixelsPercentageLimit(100.0f)
+                        .SetAbsErrorLimit(2);
+  EXPECT_TRUE(cc::MatchesBitmap(actual_pixels, expected_pixels, comparator));
+}
+
+namespace {
 class BackForwardTransitionAnimationManagerBrowserTestWithProgressBar
     : public BackForwardTransitionAnimationManagerBrowserTest {
  public:
@@ -3137,6 +3210,7 @@
       .color = SkColors::kBlue,
       .hairline_color = SkColors::kWhite};
 };
+}  // namespace
 
 // Tests that the progress bar is drawn at the correct position during the
 // invoke phase.
@@ -3485,78 +3559,6 @@
   EXPECT_TRUE(did_cross_fade.IsReady());
 }
 
-IN_PROC_BROWSER_TEST_F(BackForwardTransitionAnimationManagerBrowserTest,
-                       ScreenshotCompression) {
-  SkBitmap expected_pixels;
-  {
-    NavigationEntryScreenshot::SetDisableCompressionForTesting(true);
-    ASSERT_EQ(web_contents()->GetController().GetLastCommittedEntry()->GetURL(),
-              GreenURL());
-    GetAnimationManager()->OnGestureStarted(
-        ui::BackGestureEvent(0), SwipeEdge::LEFT, NavType::kBackward);
-    GetAnimationManager()->OnGestureProgressed(ui::BackGestureEvent(0.6));
-
-    TestFuture<gfx::Image> result;
-    auto* window = web_contents()->GetNativeView()->GetWindowAndroid();
-    ui::GrabWindowSnapshot(window, gfx::Rect(), result.GetCallback());
-    expected_pixels = result.Get().AsBitmap();
-    ASSERT_FALSE(expected_pixels.empty());
-
-    for (int col = 0.6 * expected_pixels.width() + 1;
-         col < expected_pixels.width(); col++) {
-      for (int row = 0; row < expected_pixels.height(); row++) {
-        ASSERT_EQ(expected_pixels.getColor(col, row), SK_ColorGREEN)
-            << col << "," << row << " and image "
-            << cc::GetPNGDataUrl(expected_pixels);
-      }
-    }
-
-    TestFuture<AnimatorState> destroyed;
-    GetAnimator()->set_on_impl_destroyed(destroyed.GetCallback());
-    ScopedScreenshotCapturedObserverForTesting observer(
-        web_contents()->GetController().GetLastCommittedEntryIndex());
-    GetAnimationManager()->OnGestureInvoked();
-    ASSERT_TRUE(destroyed.Wait());
-    ASSERT_EQ(web_contents()->GetController().GetLastCommittedEntry()->GetURL(),
-              RedURL());
-    observer.Wait();
-  }
-
-  SkBitmap actual_pixels;
-  {
-    NavigationEntryScreenshot::SetDisableCompressionForTesting(false);
-    ScopedScreenshotCapturedObserverForTesting observer(
-        web_contents()->GetController().GetLastCommittedEntryIndex());
-    ASSERT_TRUE(NavigateToURL(web_contents(), GreenURL()));
-    observer.Wait();
-    WaitForCopyableViewInWebContents(web_contents());
-    NavigationTransitionTestUtils::WaitForScreenshotCompressed(
-        web_contents()->GetController(),
-        web_contents()->GetController().GetLastCommittedEntryIndex() - 1);
-
-    GetAnimationManager()->OnGestureStarted(
-        ui::BackGestureEvent(0), SwipeEdge::LEFT, NavType::kBackward);
-    GetAnimationManager()->OnGestureProgressed(ui::BackGestureEvent(0.6));
-
-    TestFuture<gfx::Image> result;
-    auto* window = web_contents()->GetNativeView()->GetWindowAndroid();
-    ui::GrabWindowSnapshot(window, gfx::Rect(), result.GetCallback());
-    actual_pixels = result.Get().AsBitmap();
-    ASSERT_FALSE(actual_pixels.empty());
-
-    TestFuture<AnimatorState> destroyed;
-    GetAnimator()->set_on_impl_destroyed(destroyed.GetCallback());
-    GetAnimationManager()->OnGestureCancelled();
-    ASSERT_TRUE(destroyed.Wait());
-  }
-
-  // Allow all pixels to be off by 1.
-  auto comparator = cc::FuzzyPixelComparator()
-                        .SetErrorPixelsPercentageLimit(100.0f)
-                        .SetAbsErrorLimit(2);
-  EXPECT_TRUE(cc::MatchesBitmap(actual_pixels, expected_pixels, comparator));
-}
-
 namespace {
 class BackForwardTransitionAnimationManagerBrowserTestSubframeTransitions
     : public BackForwardTransitionAnimationManagerBrowserTest {
diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
index f3997f80..f733a8d6 100644
--- a/content/browser/renderer_host/pepper/pepper_file_io_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
@@ -482,7 +482,7 @@
     quarantine::mojom::Quarantine* raw_quarantine = quarantine_remote.get();
     raw_quarantine->QuarantineFile(
         path, browser_ppapi_host_->GetDocumentURLForInstance(pp_instance()),
-        GURL(), std::string(),
+        GURL(), /*request_initiator=*/std::nullopt, std::string(),
         mojo::WrapCallbackWithDefaultInvokeIfNotRun(
             base::BindOnce(&PepperFileIOHost::OnLocalFileQuarantined,
                            weak_ptr_factory_.GetWeakPtr(), reply_context, path,
diff --git a/content/browser/resources/indexed_db/indexeddb_internals.html b/content/browser/resources/indexed_db/indexeddb_internals.html
index 2267ce3e..fcae4da 100644
--- a/content/browser/resources/indexed_db/indexeddb_internals.html
+++ b/content/browser/resources/indexed_db/indexeddb_internals.html
@@ -67,7 +67,6 @@
                 <span class="control download">Download</span>
                 <span class="control start-record">Start Recording</span>
                 <span class="control stop-record" hidden>Stop Recording</span>
-                <a class="control" href="https://crbug.com/829141" target="_blank">?</a>
                 <span class="download-status" style="display: none">Loading...</span>
               </div>
 
diff --git a/content/browser/webauth/authenticator_common_impl.cc b/content/browser/webauth/authenticator_common_impl.cc
index dc55328..c9d0a6c6 100644
--- a/content/browser/webauth/authenticator_common_impl.cc
+++ b/content/browser/webauth/authenticator_common_impl.cc
@@ -29,6 +29,7 @@
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/webauth/authenticator_environment.h"
 #include "content/browser/webauth/client_data_json.h"
+#include "content/browser/webauth/virtual_authenticator.h"
 #include "content/browser/webauth/virtual_authenticator_manager_impl.h"
 #include "content/browser/webauth/virtual_fido_discovery_factory.h"
 #include "content/browser/webauth/webauth_request_security_checker.h"
@@ -648,6 +649,87 @@
   return capabilities;
 }
 
+void DeleteUnacceptedVirtualAuthenticatorCreds(
+    RenderFrameHost* render_frame_host,
+    std::string_view relying_party_id,
+    base::span<uint8_t> user_id,
+    base::span<std::vector<uint8_t>> all_accepted_credentials_ids) {
+  FrameTreeNode* frame_tree_node =
+      static_cast<RenderFrameHostImpl*>(render_frame_host)->frame_tree_node();
+  VirtualAuthenticatorManagerImpl* virtual_authenticator_manager =
+      AuthenticatorEnvironment::GetInstance()
+          ->MaybeGetVirtualAuthenticatorManager(frame_tree_node);
+  if (!virtual_authenticator_manager) {
+    return;
+  }
+  for (VirtualAuthenticator* authenticator :
+       virtual_authenticator_manager->GetAuthenticators()) {
+    std::vector<std::vector<uint8_t>> credential_ids_to_remove;
+    for (const auto& registration : authenticator->registrations()) {
+      if (registration.second.user && registration.second.rp &&
+          registration.second.rp->id == relying_party_id &&
+          registration.second.user->id == user_id &&
+          !base::Contains(all_accepted_credentials_ids, registration.first)) {
+        credential_ids_to_remove.push_back(registration.first);
+      }
+    }
+    for (const std::vector<uint8_t>& credential_id : credential_ids_to_remove) {
+      authenticator->RemoveRegistration(credential_id);
+    }
+  }
+}
+
+void UpdateVirtualAuthenticatorUserCreds(RenderFrameHost* render_frame_host,
+                                         std::string_view relying_party_id,
+                                         base::span<uint8_t> user_id,
+                                         std::string_view name,
+                                         std::string_view display_name) {
+  FrameTreeNode* frame_tree_node =
+      static_cast<RenderFrameHostImpl*>(render_frame_host)->frame_tree_node();
+  VirtualAuthenticatorManagerImpl* virtual_authenticator_manager =
+      AuthenticatorEnvironment::GetInstance()
+          ->MaybeGetVirtualAuthenticatorManager(frame_tree_node);
+  if (!virtual_authenticator_manager) {
+    return;
+  }
+  for (VirtualAuthenticator* authenticator :
+       virtual_authenticator_manager->GetAuthenticators()) {
+    for (auto& registration : authenticator->registrations()) {
+      if (registration.second.user && registration.second.rp &&
+          registration.second.rp->id == relying_party_id &&
+          registration.second.user->id == user_id) {
+        registration.second.user->name = name;
+        registration.second.user->display_name = display_name;
+      }
+    }
+  }
+}
+
+void DeleteVirtualAuthenticatorCreds(
+    RenderFrameHost* render_frame_host,
+    const std::vector<uint8_t>& passkey_credential_id,
+    std::string_view relying_party_id) {
+  FrameTreeNode* frame_tree_node =
+      static_cast<RenderFrameHostImpl*>(render_frame_host)->frame_tree_node();
+  VirtualAuthenticatorManagerImpl* virtual_authenticator_manager =
+      AuthenticatorEnvironment::GetInstance()
+          ->MaybeGetVirtualAuthenticatorManager(frame_tree_node);
+  if (!virtual_authenticator_manager) {
+    return;
+  }
+  for (VirtualAuthenticator* authenticator :
+       virtual_authenticator_manager->GetAuthenticators()) {
+    for (const auto& registration : authenticator->registrations()) {
+      if (registration.second.rp &&
+          registration.second.rp->id == relying_party_id &&
+          registration.first == passkey_credential_id) {
+        authenticator->RemoveRegistration(passkey_credential_id);
+        return;
+      }
+    }
+  }
+}
+
 }  // namespace
 
 // RequestState contains all state that is specific to a single WebAuthn call.
@@ -1808,21 +1890,34 @@
     CompleteReportRequest(rp_id_validation_result);
     return;
   }
+  RenderFrameHost* render_frame_host = GetRenderFrameHost();
   if (options->all_accepted_credentials) {
+    DeleteUnacceptedVirtualAuthenticatorCreds(
+        render_frame_host, req_state_->relying_party_id,
+        options->all_accepted_credentials->user_id,
+        options->all_accepted_credentials->all_accepted_credentials_ids);
     GetWebAuthenticationDelegate()->DeleteUnacceptedPasskeys(
-        WebContents::FromRenderFrameHost(GetRenderFrameHost()),
+        WebContents::FromRenderFrameHost(render_frame_host),
         req_state_->relying_party_id,
         options->all_accepted_credentials->user_id,
         options->all_accepted_credentials->all_accepted_credentials_ids);
   } else if (options->current_user_details) {
+    UpdateVirtualAuthenticatorUserCreds(
+        render_frame_host, req_state_->relying_party_id,
+        options->current_user_details->user_id,
+        options->current_user_details->name,
+        options->current_user_details->display_name);
     GetWebAuthenticationDelegate()->UpdateUserPasskeys(
-        WebContents::FromRenderFrameHost(GetRenderFrameHost()),
+        WebContents::FromRenderFrameHost(render_frame_host),
         req_state_->relying_party_id, options->current_user_details->user_id,
         options->current_user_details->name,
         options->current_user_details->display_name);
   } else if (options->unknown_credential_id) {
+    DeleteVirtualAuthenticatorCreds(render_frame_host,
+                                    *options->unknown_credential_id,
+                                    req_state_->relying_party_id);
     GetWebAuthenticationDelegate()->DeletePasskey(
-        WebContents::FromRenderFrameHost(GetRenderFrameHost()),
+        WebContents::FromRenderFrameHost(render_frame_host),
         *options->unknown_credential_id, req_state_->relying_party_id);
   }
   CompleteReportRequest(blink::mojom::AuthenticatorStatus::SUCCESS, nullptr);
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 71764b9..f8494d9 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -62,9 +62,12 @@
 #include "components/cbor/values.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "components/webauthn/content/browser/internal_authenticator_impl.h"
+#include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/webauth/authenticator_common_impl.h"
 #include "content/browser/webauth/authenticator_environment.h"
 #include "content/browser/webauth/client_data_json.h"
+#include "content/browser/webauth/virtual_authenticator.h"
+#include "content/browser/webauth/virtual_authenticator_manager_impl.h"
 #include "content/public/browser/authenticator_request_client_delegate.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_frame_host.h"
@@ -216,6 +219,7 @@
 constexpr char kTestOrigin1[] = "https://a.google.com";
 constexpr char kTestOrigin2[] = "https://acme.org";
 constexpr char kTestRelyingPartyId[] = "google.com";
+constexpr char kDifferentTestRelyingPartyId[] = "different-rp.com";
 constexpr char kExtensionScheme[] = "chrome-extension";
 static constexpr char kCorpCrdOrigin[] =
     "https://remotedesktop.corp.google.com";
@@ -472,8 +476,6 @@
 PublicKeyCredentialReportOptionsPtr GetTestPublicKeyCredentialReportOptions() {
   auto options = PublicKeyCredentialReportOptions::New();
   options->relying_party_id = std::string(kTestRelyingPartyId);
-  std::vector<uint8_t> id(32, 0x0A);
-  options->unknown_credential_id = id;
   return options;
 }
 
@@ -834,10 +836,6 @@
     return {status, std::move(response)};
   }
 
-  AuthenticatorStatus AuthenticatorReport() {
-    return AuthenticatorReport(GetTestPublicKeyCredentialReportOptions());
-  }
-
   AuthenticatorStatus AuthenticatorReport(
       PublicKeyCredentialReportOptionsPtr options) {
     mojo::Remote<blink::mojom::Authenticator> authenticator =
@@ -1223,6 +1221,7 @@
     PublicKeyCredentialReportOptionsPtr options =
         GetTestPublicKeyCredentialReportOptions();
     options->relying_party_id = test_case.claimed_authority;
+    options->unknown_credential_id = std::vector<uint8_t>(32, 0x0A);
 
     EXPECT_EQ(AuthenticatorReport(std::move(options)),
               test_case.expected_status);
@@ -5112,6 +5111,197 @@
   EXPECT_EQ(result.status, AuthenticatorStatus::NOT_ALLOWED_ERROR);
 }
 
+// These test verify that the virtual authenticator supports the Signal API.
+class VirtualAuthenticatorSignalTest : public AuthenticatorImplTest {
+ public:
+  static constexpr char kUsername[] = "reimu";
+  static constexpr char kDisplayName[] = "Reimu Hakurei";
+  const std::vector<uint8_t> kUserId = {2};
+
+  void SetUp() override {
+    AuthenticatorImplTest::SetUp();
+    NavigateAndCommit(GURL(kTestOrigin1));
+
+    // These tests need an AuthenticatorEnvironment set up.
+    virtual_device_factory_ = nullptr;
+    content::AuthenticatorEnvironment* authenticator_environment =
+        content::AuthenticatorEnvironment::GetInstance();
+    authenticator_environment->Reset();
+    FrameTreeNode* frame_tree_node =
+        static_cast<content::RenderFrameHostImpl*>(main_rfh())
+            ->frame_tree_node();
+    authenticator_environment->EnableVirtualAuthenticatorFor(
+        frame_tree_node,
+        /*enable_ui=*/false);
+    VirtualAuthenticatorManagerImpl* virtual_authenticator_manager =
+        authenticator_environment->MaybeGetVirtualAuthenticatorManager(
+            frame_tree_node);
+    auto virt_auth_options =
+        blink::test::mojom::VirtualAuthenticatorOptions::New();
+    virt_auth_options->protocol = device::ProtocolVersion::kCtap2;
+    virt_auth_options->transport = device::FidoTransportProtocol::kInternal;
+    virt_auth_options->has_resident_key = true;
+    authenticator_ =
+        virtual_authenticator_manager
+            ->AddAuthenticatorAndReturnNonOwningPointer(*virt_auth_options);
+
+    // Make a credential.
+    PublicKeyCredentialCreationOptionsPtr options =
+        GetTestPublicKeyCredentialCreationOptions();
+    options->user.id = kUserId;
+    options->user.name = kUsername;
+    options->user.display_name = kDisplayName;
+    options->authenticator_selection->resident_key =
+        device::ResidentKeyRequirement::kRequired;
+    MakeCredentialResult result =
+        AuthenticatorMakeCredential(std::move(options));
+    ASSERT_EQ(result.status, AuthenticatorStatus::SUCCESS);
+    credential_id_ = result.response->info->raw_id;
+  }
+
+  void TearDown() override {
+    authenticator_ = nullptr;
+    AuthenticatorImplTest::TearDown();
+  }
+
+ protected:
+  // The id of the credential created during test setup.
+  std::vector<uint8_t> credential_id_;
+
+  raw_ptr<VirtualAuthenticator> authenticator_;
+};
+
+TEST_F(VirtualAuthenticatorSignalTest, SignalUnknownCredentialId) {
+  {
+    // Verify that we do not remove passkeys that don't match the rp id.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kDifferentTestRelyingPartyId;
+    options->unknown_credential_id = credential_id_;
+    AuthenticatorReport(std::move(options));
+    EXPECT_TRUE(
+        base::Contains(authenticator_->registrations(), credential_id_));
+  }
+  {
+    // Verify that we do not remove passkeys that don't match the cred id.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kTestRelyingPartyId;
+    options->unknown_credential_id = std::vector<uint8_t>{4, 3, 2, 1};
+    AuthenticatorReport(std::move(options));
+    EXPECT_TRUE(
+        base::Contains(authenticator_->registrations(), credential_id_));
+  }
+  {
+    // Remove the passkey when the rp id and credential id match.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kTestRelyingPartyId;
+    options->unknown_credential_id = credential_id_;
+    AuthenticatorReport(std::move(options));
+    EXPECT_FALSE(
+        base::Contains(authenticator_->registrations(), credential_id_));
+  }
+}
+
+TEST_F(VirtualAuthenticatorSignalTest, SignalAllAcceptableCredentials) {
+  {
+    // Verify that we do not remove passkeys that don't match the rp id.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kDifferentTestRelyingPartyId;
+    options->all_accepted_credentials =
+        blink::mojom::AllAcceptedCredentialsOptions::New(
+            kUserId, std::vector<std::vector<uint8_t>>{});
+    AuthenticatorReport(std::move(options));
+    EXPECT_TRUE(
+        base::Contains(authenticator_->registrations(), credential_id_));
+  }
+  {
+    // Verify that we do not remove passkeys that don't match the user id.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kTestRelyingPartyId;
+    options->all_accepted_credentials =
+        blink::mojom::AllAcceptedCredentialsOptions::New(
+            std::vector<uint8_t>{99}, std::vector<std::vector<uint8_t>>{});
+    AuthenticatorReport(std::move(options));
+    EXPECT_TRUE(
+        base::Contains(authenticator_->registrations(), credential_id_));
+  }
+  {
+    // Verify that we do not remove passkeys that are present on the list.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kTestRelyingPartyId;
+    options->all_accepted_credentials =
+        blink::mojom::AllAcceptedCredentialsOptions::New(
+            kUserId, std::vector<std::vector<uint8_t>>{credential_id_});
+    AuthenticatorReport(std::move(options));
+    EXPECT_TRUE(
+        base::Contains(authenticator_->registrations(), credential_id_));
+  }
+  {
+    // Verify that we remove passkeys that are not present on the list.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kTestRelyingPartyId;
+    options->all_accepted_credentials =
+        blink::mojom::AllAcceptedCredentialsOptions::New(
+            kUserId, std::vector<std::vector<uint8_t>>{});
+    AuthenticatorReport(std::move(options));
+    EXPECT_FALSE(
+        base::Contains(authenticator_->registrations(), credential_id_));
+  }
+}
+
+TEST_F(VirtualAuthenticatorSignalTest, SignalCurrentUserDetails) {
+  constexpr char kNewUsername[] = "marisa";
+  constexpr char kNewDisplayName[] = "Marisa Kirisame";
+  {
+    // Verify that we do not update passkeys that don't match the rp id.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kDifferentTestRelyingPartyId;
+    options->current_user_details =
+        blink::mojom::CurrentUserDetailsOptions::New(kUserId, kNewUsername,
+                                                     kNewDisplayName);
+    AuthenticatorReport(std::move(options));
+    const auto& cred =
+        authenticator_->registrations().find(credential_id_)->second;
+    EXPECT_EQ(cred.user->name, kUsername);
+    EXPECT_EQ(cred.user->display_name, kDisplayName);
+  }
+  {
+    // Verify that we do not update passkeys that don't match the user id.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kTestRelyingPartyId;
+    options->current_user_details =
+        blink::mojom::CurrentUserDetailsOptions::New(
+            std::vector<uint8_t>{9}, kNewUsername, kNewDisplayName);
+    AuthenticatorReport(std::move(options));
+    const auto& cred =
+        authenticator_->registrations().find(credential_id_)->second;
+    EXPECT_EQ(cred.user->name, kUsername);
+    EXPECT_EQ(cred.user->display_name, kDisplayName);
+  }
+  {
+    // Verify that we do update passkeys that match.
+    PublicKeyCredentialReportOptionsPtr options =
+        GetTestPublicKeyCredentialReportOptions();
+    options->relying_party_id = kTestRelyingPartyId;
+    options->current_user_details =
+        blink::mojom::CurrentUserDetailsOptions::New(kUserId, kNewUsername,
+                                                     kNewDisplayName);
+    AuthenticatorReport(std::move(options));
+    const auto& cred =
+        authenticator_->registrations().find(credential_id_)->second;
+    EXPECT_EQ(cred.user->name, kNewUsername);
+    EXPECT_EQ(cred.user->display_name, kNewDisplayName);
+  }
+}
+
 static constexpr char kTestPIN[] = "1234";
 static constexpr char16_t kTestPIN16[] = u"1234";
 
diff --git a/content/browser/webauth/virtual_authenticator.h b/content/browser/webauth/virtual_authenticator.h
index 03102ae..81cf0e82 100644
--- a/content/browser/webauth/virtual_authenticator.h
+++ b/content/browser/webauth/virtual_authenticator.h
@@ -56,8 +56,7 @@
   void AddReceiver(
       mojo::PendingReceiver<blink::test::mojom::VirtualAuthenticator> receiver);
 
-  const device::VirtualFidoDevice::State::RegistrationsMap& registrations()
-      const {
+  device::VirtualFidoDevice::State::RegistrationsMap& registrations() const {
     return state_->registrations;
   }
 
diff --git a/content/public/android/java/src/org/chromium/content_public/app/ZygotePreload.java b/content/public/android/java/src/org/chromium/content_public/app/ZygotePreload.java
index 42bfa6949..9bc01e2 100644
--- a/content/public/android/java/src/org/chromium/content_public/app/ZygotePreload.java
+++ b/content/public/android/java/src/org/chromium/content_public/app/ZygotePreload.java
@@ -46,7 +46,7 @@
                 VersionConstants.PRODUCT_VERSION,
                 BuildConfig.VERSION_CODE,
                 BuildConfig.MIN_SDK_VERSION,
-                BuildConfig.BUNDLES_SUPPORTED);
+                BuildConfig.IS_BUNDLE);
         try {
             // The current thread time is the best approximation we have of the zygote start time
             // since Process.getStartUptimeMillis() is not reliable in the zygote process. This will
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
index a00ee0a..3b619a3 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
@@ -1493,6 +1493,30 @@
 
     @Test
     @SmallTest
+    public void test_customSelect() {
+        performHtmlTest("custom-select.html");
+    }
+
+    @Test
+    @SmallTest
+    public void test_customSelectOpen() {
+        performHtmlTest("custom-select-open.html");
+    }
+
+    @Test
+    @SmallTest
+    public void test_customSelectSimple() {
+        performHtmlTest("custom-select-simple.html");
+    }
+
+    @Test
+    @SmallTest
+    public void test_customSelectSimpleOpen() {
+        performHtmlTest("custom-select-simple-open.html");
+    }
+
+    @Test
+    @SmallTest
     public void test_dd() {
         performHtmlTest("dd.html");
     }
@@ -2150,6 +2174,18 @@
 
     @Test
     @SmallTest
+    public void test_optgroupMenulist() {
+        performHtmlTest("optgroup-menulist.html");
+    }
+
+    @Test
+    @SmallTest
+    public void test_optgroupCustomMenulist() {
+        performHtmlTest("optgroup-custom-menulist.html");
+    }
+
+    @Test
+    @SmallTest
     public void test_output() {
         performHtmlTest("output.html");
     }
diff --git a/content/public/test/test_file_error_injector.cc b/content/public/test/test_file_error_injector.cc
index a10744e..59420be 100644
--- a/content/public/test/test_file_error_injector.cc
+++ b/content/public/test/test_file_error_injector.cc
@@ -66,6 +66,7 @@
       const std::string& client_guid,
       const GURL& source_url,
       const GURL& referrer_url,
+      const std::optional<url::Origin>& request_initiator,
       mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
       RenameCompletionCallback callback) override;
 
@@ -247,6 +248,7 @@
     const std::string& client_guid,
     const GURL& source_url,
     const GURL& referrer_url,
+    const std::optional<url::Origin>& request_initiator,
     mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
     RenameCompletionCallback callback) {
   download::DownloadInterruptReason error_to_return =
@@ -275,7 +277,8 @@
     callback_to_use = std::move(callback);
 
   download::DownloadFileImpl::RenameAndAnnotate(
-      full_path, client_guid, source_url, referrer_url, mojo::NullRemote(),
+      full_path, client_guid, source_url, referrer_url,
+      /*request_initiator=*/std::nullopt, mojo::NullRemote(),
       std::move(callback_to_use));
 }
 
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc
index e189377..6ca4b4e 100644
--- a/content/services/auction_worklet/bidder_worklet.cc
+++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -42,6 +42,7 @@
 #include "content/services/auction_worklet/for_debugging_only_bindings.h"
 #include "content/services/auction_worklet/private_aggregation_bindings.h"
 #include "content/services/auction_worklet/public/cpp/auction_network_events_delegate.h"
+#include "content/services/auction_worklet/public/cpp/private_aggregation_reporting.h"
 #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h"
 #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom-shared.h"
 #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
@@ -137,26 +138,6 @@
   return subresource_bundle_result.GetSignals(v8_helper, context, errors);
 }
 
-bool HasKAnonFailureComponent(
-    const auction_worklet::mojom::PrivateAggregationRequestPtr& request) {
-  if (request->contribution->is_histogram_contribution()) {
-    return false;
-  }
-  const auction_worklet::mojom::AggregatableReportForEventContributionPtr&
-      event_contribution = request->contribution->get_for_event_contribution();
-  if (event_contribution->bucket->is_signal_bucket() &&
-      event_contribution->bucket->get_signal_bucket()->base_value ==
-          auction_worklet::mojom::BaseValue::kBidRejectReason) {
-    return true;
-  }
-  if (event_contribution->value->is_signal_value() &&
-      event_contribution->value->get_signal_value()->base_value ==
-          auction_worklet::mojom::BaseValue::kBidRejectReason) {
-    return true;
-  }
-  return false;
-}
-
 std::optional<base::TimeDelta> NullOptIfZero(base::TimeDelta delta) {
   if (delta.is_zero()) {
     return std::nullopt;
@@ -1282,7 +1263,7 @@
         std::erase_if(
             non_kanon_pa_requests,
             [](const auction_worklet::mojom::PrivateAggregationRequestPtr&
-                   request) { return !HasKAnonFailureComponent(request); });
+                   request) { return !HasKAnonFailureComponent(*request); });
 
         // We are enforcing the k-anonymity, so the restricted result is the one
         // to use for reporting, etc., and needs to succeed.
@@ -1979,6 +1960,7 @@
   base::UmaHistogramCounts100000(
       "Ads.InterestGroup.Net.RequestUrlSizeBytes.BiddingScriptJS",
       script_source_url_.spec().size());
+  code_download_start_ = base::TimeTicks::Now();
   worklet_loader_ = std::make_unique<WorkletLoader>(
       url_loader_factory_.get(),
       /*auction_network_events_handler=*/
@@ -2010,6 +1992,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
 
   DCHECK_EQ(worklet_scripts.size(), v8_helpers_.size());
+  js_fetch_latency_ = base::TimeTicks::Now() - code_download_start_;
 
   // Use `worklet_scripts[0]` for metrics and for the failure check. All the
   // results should be the same.
@@ -2050,6 +2033,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
 
   DCHECK_EQ(worklet_scripts.size(), v8_helpers_.size());
+  wasm_fetch_latency_ = base::TimeTicks::Now() - code_download_start_;
 
   // Use `worklet_scripts[0]` for metrics and for the failure check. All the
   // results should be the same.
@@ -2493,7 +2477,10 @@
       debug_win_report_url, set_priority,
       std::move(update_priority_signals_overrides), std::move(pa_requests),
       std::move(non_kanon_pa_requests), std::move(real_time_contributions),
-      bidding_latency,
+      mojom::BidderTimingMetrics::New(
+          /*js_fetch_latency=*/js_fetch_latency_,
+          /*wasm_fetch_latency=*/wasm_fetch_latency_,
+          /*script_latency=*/bidding_latency),
       mojom::GenerateBidDependencyLatencies::New(
           /*code_ready_latency=*/NullOptIfZero(task->wait_code),
           /*config_promises_latency=*/NullOptIfZero(task->wait_promises),
@@ -2533,7 +2520,11 @@
                 load_code_error_msgs_.end());
   std::move(task->callback)
       .Run(std::move(report_url), std::move(ad_beacon_map),
-           std::move(ad_macro_map), std::move(pa_requests), reporting_latency,
+           std::move(ad_macro_map), std::move(pa_requests),
+           mojom::BidderTimingMetrics::New(
+               /*js_fetch_latency=*/js_fetch_latency_,
+               /*wasm_fetch_latency=*/wasm_fetch_latency_,
+               /*script_latency=*/reporting_latency),
            std::move(errors));
   report_win_tasks_.erase(task);
 }
diff --git a/content/services/auction_worklet/bidder_worklet.h b/content/services/auction_worklet/bidder_worklet.h
index b610034..2931a32d 100644
--- a/content/services/auction_worklet/bidder_worklet.h
+++ b/content/services/auction_worklet/bidder_worklet.h
@@ -787,6 +787,9 @@
   // These are deleted once each resource is loaded.
   std::unique_ptr<WorkletLoader> worklet_loader_;
   std::unique_ptr<WorkletWasmLoader> wasm_loader_;
+  base::TimeTicks code_download_start_;
+  std::optional<base::TimeDelta> js_fetch_latency_;
+  std::optional<base::TimeDelta> wasm_fetch_latency_;
 
   // Lives on `v8_runners_`. Since it's deleted there via DeleteSoon, tasks can
   // be safely posted from main thread to it with an Unretained pointer.
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc
index 81c3770..5df26887 100644
--- a/content/services/auction_worklet/bidder_worklet_unittest.cc
+++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -159,7 +159,7 @@
       PrivateAggregationRequests pa_requests,
       PrivateAggregationRequests non_kanon_pa_requests,
       RealTimeReportingContributions real_time_contributions,
-      base::TimeDelta bidding_latency,
+      mojom::BidderTimingMetricsPtr generate_bid_metrics,
       mojom::GenerateBidDependencyLatenciesPtr
           generate_bid_dependency_latencies,
       mojom::RejectReason reject_reason,
@@ -212,7 +212,7 @@
            PrivateAggregationRequests pa_requests,
            PrivateAggregationRequests non_kanon_pa_requests,
            RealTimeReportingContributions real_time_contributions,
-           base::TimeDelta bidding_latency,
+           mojom::BidderTimingMetricsPtr generate_bid_metrics,
            mojom::GenerateBidDependencyLatenciesPtr
                generate_bid_dependency_latencies,
            mojom::RejectReason reject_reason,
@@ -253,7 +253,7 @@
       PrivateAggregationRequests pa_requests,
       PrivateAggregationRequests non_kanon_pa_requests,
       RealTimeReportingContributions real_time_contributions,
-      base::TimeDelta bidding_latency,
+      mojom::BidderTimingMetricsPtr generate_bid_metrics,
       mojom::GenerateBidDependencyLatenciesPtr
           generate_bid_dependency_latencies,
       mojom::RejectReason reject_reason,
@@ -266,7 +266,8 @@
              debug_win_report_url, set_priority,
              std::move(update_priority_signals_overrides),
              std::move(pa_requests), std::move(non_kanon_pa_requests),
-             std::move(real_time_contributions), bidding_latency,
+             std::move(real_time_contributions),
+             std::move(generate_bid_metrics),
              std::move(generate_bid_dependency_latencies), reject_reason,
              errors);
   }
@@ -627,7 +628,7 @@
                const base::flat_map<std::string, GURL>& ad_beacon_map,
                const base::flat_map<std::string, std::string>& ad_macro_map,
                PrivateAggregationRequests pa_requests,
-               base::TimeDelta reporting_latency,
+               auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
                const std::vector<std::string>& errors) {
               EXPECT_EQ(expected_report_url, report_url);
               EXPECT_EQ(expected_errors, errors);
@@ -637,7 +638,7 @@
               if (expected_reporting_latency_timeout) {
                 // We only know that about the time of the timeout should have
                 // elapsed, and there may also be some thread skew.
-                EXPECT_GE(reporting_latency,
+                EXPECT_GE(timing_metrics->script_latency,
                           (reporting_timeout.has_value()
                                ? reporting_timeout.value()
                                : AuctionV8Helper::kScriptTimeout) *
@@ -870,7 +871,7 @@
       PrivateAggregationRequests pa_requests,
       PrivateAggregationRequests non_kanon_pa_requests,
       RealTimeReportingContributions real_time_contributions,
-      base::TimeDelta bidding_latency,
+      mojom::BidderTimingMetricsPtr generate_bid_metrics,
       mojom::GenerateBidDependencyLatenciesPtr
           generate_bid_dependency_latencies,
       mojom::RejectReason reject_reason,
@@ -893,6 +894,7 @@
     pa_requests_ = std::move(pa_requests);
     non_kanon_pa_requests_ = std::move(non_kanon_pa_requests);
     real_time_contributions_ = std::move(real_time_contributions);
+    generate_bid_metrics_ = std::move(generate_bid_metrics);
     generate_bid_dependency_latencies_ =
         std::move(generate_bid_dependency_latencies);
     reject_reason_ = reject_reason;
@@ -1072,6 +1074,7 @@
   PrivateAggregationRequests pa_requests_;
   PrivateAggregationRequests non_kanon_pa_requests_;
   RealTimeReportingContributions real_time_contributions_;
+  mojom::BidderTimingMetricsPtr generate_bid_metrics_;
   mojom::GenerateBidDependencyLatenciesPtr generate_bid_dependency_latencies_;
   mojom::RejectReason reject_reason_ = mojom::RejectReason::kNotAvailable;
   std::vector<std::string> bid_errors_;
@@ -4553,7 +4556,7 @@
                   PrivateAggregationRequests pa_requests,
                   PrivateAggregationRequests non_kanon_pa_requests,
                   RealTimeReportingContributions real_time_contributions,
-                  base::TimeDelta bidding_latency,
+                  mojom::BidderTimingMetricsPtr generate_bid_metrics,
                   mojom::GenerateBidDependencyLatenciesPtr
                       generate_bid_dependency_latencies,
                   mojom::RejectReason reject_reason,
@@ -4674,7 +4677,7 @@
                 PrivateAggregationRequests pa_requests,
                 PrivateAggregationRequests non_kanon_pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta bidding_latency,
+                mojom::BidderTimingMetricsPtr generate_bid_metrics,
                 mojom::GenerateBidDependencyLatenciesPtr
                     generate_bid_dependency_latencies,
                 mojom::RejectReason reject_reason,
@@ -4804,7 +4807,7 @@
                 PrivateAggregationRequests pa_requests,
                 PrivateAggregationRequests non_kanon_pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta bidding_latency,
+                mojom::BidderTimingMetricsPtr generate_bid_metrics,
                 mojom::GenerateBidDependencyLatenciesPtr
                     generate_bid_dependency_latencies,
                 mojom::RejectReason reject_reason,
@@ -4940,7 +4943,7 @@
                 PrivateAggregationRequests pa_requests,
                 PrivateAggregationRequests non_kanon_pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta bidding_latency,
+                mojom::BidderTimingMetricsPtr generate_bid_metrics,
                 mojom::GenerateBidDependencyLatenciesPtr
                     generate_bid_dependency_latencies,
                 mojom::RejectReason reject_reason,
@@ -5055,7 +5058,7 @@
                 PrivateAggregationRequests pa_requests,
                 PrivateAggregationRequests non_kanon_pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta bidding_latency,
+                mojom::BidderTimingMetricsPtr generate_bid_metrics,
                 mojom::GenerateBidDependencyLatenciesPtr
                     generate_bid_dependency_latencies,
                 mojom::RejectReason reject_reason,
@@ -6016,7 +6019,7 @@
               const base::flat_map<std::string, GURL>& ad_beacon_map,
               const base::flat_map<std::string, std::string>& ad_macro_map,
               PrivateAggregationRequests pa_requests,
-              base::TimeDelta reporting_latency,
+              auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
               const std::vector<std::string>& errors) { run_loop.Quit(); }));
   base::RunLoop().RunUntilIdle();
   AddResponse(&url_loader_factory_, GURL(kWasmUrl), kWasmMimeType,
@@ -7815,7 +7818,7 @@
              const base::flat_map<std::string, GURL>& ad_beacon_map,
              const base::flat_map<std::string, std::string>& ad_macro_map,
              PrivateAggregationRequests pa_requests,
-             base::TimeDelta reporting_latency,
+             auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
              const std::vector<std::string>& errors) {
             ADD_FAILURE()
                 << "Callback should not be invoked since worklet deleted";
@@ -7874,7 +7877,7 @@
                   const base::flat_map<std::string, GURL>& ad_beacon_map,
                   const base::flat_map<std::string, std::string>& ad_macro_map,
                   PrivateAggregationRequests pa_requests,
-                  base::TimeDelta reporting_latency,
+                  auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
                   const std::vector<std::string>& errors) {
                 EXPECT_EQ(GURL(base::StringPrintf("https://foo.test/%zu", i)),
                           report_url);
@@ -7930,7 +7933,7 @@
                const base::flat_map<std::string, GURL>& ad_beacon_map,
                const base::flat_map<std::string, std::string>& ad_macro_map,
                PrivateAggregationRequests pa_requests,
-               base::TimeDelta reporting_latency,
+               auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
                const std::vector<std::string>& errors) {
               ADD_FAILURE() << "Callback should not be invoked.";
             }));
@@ -8527,7 +8530,7 @@
                 const base::flat_map<std::string, GURL>& ad_beacon_map,
                 const base::flat_map<std::string, std::string>& ad_macro_map,
                 PrivateAggregationRequests pa_requests,
-                base::TimeDelta reporting_latency,
+                auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
                 const std::vector<std::string>& errors) {
               EXPECT_EQ(GURL("https://23.test/"), report_url);
               EXPECT_TRUE(errors.empty());
@@ -9861,7 +9864,7 @@
              const base::flat_map<std::string, GURL>& ad_beacon_map,
              const base::flat_map<std::string, std::string>& ad_macro_map,
              PrivateAggregationRequests pa_requests,
-             base::TimeDelta reporting_latency,
+             auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
              const std::vector<std::string>& errors) {
             ADD_FAILURE() << "Callback should not be invoked.";
           }));
@@ -12483,6 +12486,130 @@
       *generate_bid_dependency_latencies_->trusted_bidding_signals_latency);
 }
 
+TEST_F(BidderWorkletLatenciesTest, GenerateBidFetchMetrics) {
+  interest_group_wasm_url_ = GURL(kWasmUrl);
+  mojo::Remote<mojom::BidderWorklet> bidder_worklet = CreateWorklet();
+  mojo::AssociatedRemote<auction_worklet::mojom::GenerateBidFinalizer>
+      bid_finalizer;
+  BeginGenerateBid(bidder_worklet.get(),
+                   bid_finalizer.BindNewEndpointAndPassReceiver());
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(bids_.empty());
+
+  task_environment_.FastForwardBy(base::Milliseconds(250));
+  AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_,
+                        CreateBasicGenerateBidScript());
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(bids_.empty());
+
+  task_environment_.FastForwardBy(base::Milliseconds(240));
+  AddResponse(&url_loader_factory_, GURL(kWasmUrl), kWasmMimeType,
+              /*charset=*/std::nullopt, ToyWasm());
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(bids_.empty());
+
+  task_environment_.FastForwardBy(base::Milliseconds(230));
+
+  // Now feed in the rest of the arguments.
+  bid_finalizer->FinishGenerateBid(
+      auction_signals_, per_buyer_signals_, per_buyer_timeout_,
+      per_buyer_currency_,
+      /*direct_from_seller_per_buyer_signals=*/std::nullopt,
+      /*direct_from_seller_per_buyer_signals_header_ad_slot=*/std::nullopt,
+      /*direct_from_seller_auction_signals=*/std::nullopt,
+      /*direct_from_seller_auction_signals_header_ad_slot=*/std::nullopt);
+  generate_bid_run_loop_ = std::make_unique<base::RunLoop>();
+  generate_bid_run_loop_->Run();
+  ASSERT_EQ(1u, bids_.size());
+  EXPECT_EQ("[\"ad\"]", bids_[0]->ad);
+  EXPECT_EQ(1, bids_[0]->bid);
+  EXPECT_THAT(bid_errors_, testing::ElementsAre());
+
+  ASSERT_TRUE(generate_bid_metrics_->js_fetch_latency.has_value());
+  EXPECT_EQ(base::Milliseconds(250), *generate_bid_metrics_->js_fetch_latency);
+  ASSERT_TRUE(generate_bid_metrics_->wasm_fetch_latency.has_value());
+  EXPECT_EQ(base::Milliseconds(490),
+            *generate_bid_metrics_->wasm_fetch_latency);
+
+  generate_bid_metrics_.reset();
+
+  // Do another call, metrics should be the same.
+  mojo::AssociatedRemote<auction_worklet::mojom::GenerateBidFinalizer>
+      bid_finalizer2;
+  BeginGenerateBid(bidder_worklet.get(),
+                   bid_finalizer2.BindNewEndpointAndPassReceiver());
+  bid_finalizer2->FinishGenerateBid(
+      auction_signals_, per_buyer_signals_, per_buyer_timeout_,
+      per_buyer_currency_,
+      /*direct_from_seller_per_buyer_signals=*/std::nullopt,
+      /*direct_from_seller_per_buyer_signals_header_ad_slot=*/std::nullopt,
+      /*direct_from_seller_auction_signals=*/std::nullopt,
+      /*direct_from_seller_auction_signals_header_ad_slot=*/std::nullopt);
+  generate_bid_run_loop_ = std::make_unique<base::RunLoop>();
+  generate_bid_run_loop_->Run();
+
+  ASSERT_TRUE(generate_bid_metrics_->js_fetch_latency.has_value());
+  EXPECT_EQ(base::Milliseconds(250), *generate_bid_metrics_->js_fetch_latency);
+  ASSERT_TRUE(generate_bid_metrics_->wasm_fetch_latency.has_value());
+  EXPECT_EQ(base::Milliseconds(490),
+            *generate_bid_metrics_->wasm_fetch_latency);
+}
+
+TEST_F(BidderWorkletLatenciesTest, ReportWinFetchMetrics) {
+  interest_group_wasm_url_ = GURL(kWasmUrl);
+  mojo::Remote<mojom::BidderWorklet> bidder_worklet = CreateWorklet();
+
+  base::RunLoop run_loop;
+  bidder_worklet->ReportWin(
+      is_for_additional_bid_, interest_group_name_reporting_id_,
+      buyer_reporting_id_, buyer_and_seller_reporting_id_,
+      selected_buyer_and_seller_reporting_id_, auction_signals_,
+      per_buyer_signals_, direct_from_seller_per_buyer_signals_,
+      direct_from_seller_per_buyer_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+      kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+      browser_signal_bid_, browser_signal_bid_currency_,
+      browser_signal_highest_scoring_other_bid_,
+      browser_signal_highest_scoring_other_bid_currency_,
+      browser_signal_made_highest_scoring_other_bid_, browser_signal_ad_cost_,
+      browser_signal_modeling_signals_, browser_signal_join_count_,
+      browser_signal_recency_report_win_, browser_signal_seller_origin_,
+      browser_signal_top_level_seller_origin_,
+      browser_signal_reporting_timeout_, data_version_,
+
+      /*trace_id=*/1,
+      base::BindOnce(
+          [](base::OnceClosure done_closure,
+             const std::optional<GURL>& report_url,
+             const base::flat_map<std::string, GURL>& ad_beacon_map,
+             const base::flat_map<std::string, std::string>& ad_macro_map,
+             PrivateAggregationRequests pa_requests,
+             auction_worklet::mojom::BidderTimingMetricsPtr timing_metrics,
+             const std::vector<std::string>& errors) {
+            ASSERT_TRUE(timing_metrics->js_fetch_latency.has_value());
+            EXPECT_EQ(base::Milliseconds(250),
+                      *timing_metrics->js_fetch_latency);
+            ASSERT_TRUE(timing_metrics->wasm_fetch_latency.has_value());
+            EXPECT_EQ(base::Milliseconds(490),
+                      *timing_metrics->wasm_fetch_latency);
+            std::move(done_closure).Run();
+          },
+          run_loop.QuitClosure()));
+
+  task_environment_.FastForwardBy(base::Milliseconds(250));
+  AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_,
+                        CreateBasicGenerateBidScript());
+  task_environment_.RunUntilIdle();
+
+  task_environment_.FastForwardBy(base::Milliseconds(240));
+  AddResponse(&url_loader_factory_, GURL(kWasmUrl), kWasmMimeType,
+              /*charset=*/std::nullopt, ToyWasm());
+  task_environment_.RunUntilIdle();
+  task_environment_.FastForwardBy(base::Milliseconds(230));
+  run_loop.Run();
+}
+
 // Tests both reporting latency, and default reporting timeout.
 TEST_F(BidderWorkletTest, ReportWinLatency) {
   // We use an infinite loop since we have some notion of how long a timeout
diff --git a/content/services/auction_worklet/private_aggregation_bindings.cc b/content/services/auction_worklet/private_aggregation_bindings.cc
index 6fdec98..64b51e1e 100644
--- a/content/services/auction_worklet/private_aggregation_bindings.cc
+++ b/content/services/auction_worklet/private_aggregation_bindings.cc
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include "base/check.h"
+#include "base/containers/fixed_flat_map.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/ranges/algorithm.h"
@@ -99,22 +100,34 @@
   }
 }
 
+constexpr auto kBaseValueNames =
+    base::MakeFixedFlatMap<std::string_view, mojom::BaseValue>({
+        {"winning-bid", mojom::BaseValue::kWinningBid},
+        {"highest-scoring-other-bid",
+         mojom::BaseValue::kHighestScoringOtherBid},
+        {"script-run-time", mojom::BaseValue::kScriptRunTime},
+        {"signals-fetch-time", mojom::BaseValue::kSignalsFetchTime},
+        {"bid-reject-reason", mojom::BaseValue::kBidRejectReason},
+        {"participating-ig-count",
+         mojom::BaseValue::kParticipatingInterestGroupCount},
+        {"average-code-fetch-time", mojom::BaseValue::kAverageCodeFetchTime},
+    });
+
 // Converts base value string to corresponding mojom enum.
 std::optional<auction_worklet::mojom::BaseValue> BaseValueStringToEnum(
-    const std::string& base_value) {
-  if (base_value == "winning-bid") {
-    return auction_worklet::mojom::BaseValue::kWinningBid;
-  } else if (base_value == "highest-scoring-other-bid") {
-    return auction_worklet::mojom::BaseValue::kHighestScoringOtherBid;
-  } else if (base_value == "script-run-time") {
-    return auction_worklet::mojom::BaseValue::kScriptRunTime;
-  } else if (base_value == "signals-fetch-time") {
-    return auction_worklet::mojom::BaseValue::kSignalsFetchTime;
-  } else if (base_value == "bid-reject-reason") {
-    return auction_worklet::mojom::BaseValue::kBidRejectReason;
+    const std::string& base_value,
+    bool additional_extensions_allowed) {
+  auto it = kBaseValueNames.find(base_value);
+  if (it == kBaseValueNames.end()) {
+    return std::nullopt;
   }
-  // Invalid (out of range) base_value.
-  return std::nullopt;
+  auction_worklet::mojom::BaseValue value_enum = it->second;
+  if (!additional_extensions_allowed &&
+      RequiresAdditionalExtensions(value_enum)) {
+    return std::nullopt;
+  }
+
+  return value_enum;
 }
 
 // If returns `std::nullopt`, will output an error to `error`.
@@ -163,9 +176,10 @@
 std::optional<auction_worklet::mojom::SignalBucketPtr> GetSignalBucket(
     v8::Isolate* isolate,
     const PASignalValue& input,
+    bool additional_extensions_allowed,
     std::string* error) {
   std::optional<auction_worklet::mojom::BaseValue> base_value_opt =
-      BaseValueStringToEnum(input.base_value);
+      BaseValueStringToEnum(input.base_value, additional_extensions_allowed);
   if (!base_value_opt.has_value()) {
     *error = "Bucket's 'baseValue' is invalid";
     return std::nullopt;
@@ -198,9 +212,10 @@
 std::optional<auction_worklet::mojom::SignalValuePtr> GetSignalValue(
     v8::Isolate* isolate,
     const PASignalValue& input,
+    bool additional_extensions_allowed,
     std::string* error) {
   std::optional<auction_worklet::mojom::BaseValue> base_value_opt =
-      BaseValueStringToEnum(input.base_value);
+      BaseValueStringToEnum(input.base_value, additional_extensions_allowed);
   if (!base_value_opt.has_value()) {
     *error = "Value's 'baseValue' is invalid";
     return std::nullopt;
@@ -228,6 +243,7 @@
 auction_worklet::mojom::ForEventSignalBucketPtr GetBucket(
     v8::Isolate* isolate,
     const absl::variant<PASignalValue, v8::Local<v8::BigInt>>& idl_bucket,
+    bool additional_extensions_allowed,
     std::string* error) {
   const v8::Local<v8::BigInt>* big_int =
       absl::get_if<v8::Local<v8::BigInt>>(&idl_bucket);
@@ -242,8 +258,9 @@
         *maybe_bucket);
   } else {
     std::optional<auction_worklet::mojom::SignalBucketPtr>
-        maybe_signal_bucket_ptr = GetSignalBucket(
-            isolate, absl::get<PASignalValue>(idl_bucket), error);
+        maybe_signal_bucket_ptr =
+            GetSignalBucket(isolate, absl::get<PASignalValue>(idl_bucket),
+                            additional_extensions_allowed, error);
     if (!maybe_signal_bucket_ptr.has_value()) {
       CHECK(base::IsStringUTF8(*error));
       return nullptr;
@@ -258,6 +275,7 @@
 auction_worklet::mojom::ForEventSignalValuePtr GetValue(
     v8::Isolate* isolate,
     const absl::variant<PASignalValue, int32_t>& idl_value,
+    bool additional_extensions_allowed,
     std::string* error) {
   const int32_t* int_value = absl::get_if<int32_t>(&idl_value);
   if (int_value) {
@@ -269,7 +287,8 @@
   } else {
     std::optional<auction_worklet::mojom::SignalValuePtr>
         maybe_signal_value_ptr =
-            GetSignalValue(isolate, absl::get<PASignalValue>(idl_value), error);
+            GetSignalValue(isolate, absl::get<PASignalValue>(idl_value),
+                           additional_extensions_allowed, error);
     if (!maybe_signal_value_ptr.has_value()) {
       CHECK(base::IsStringUTF8(*error));
       return nullptr;
@@ -310,14 +329,15 @@
     absl::variant<PASignalValue, v8::Local<v8::BigInt>> idl_bucket,
     absl::variant<PASignalValue, int32_t> idl_value,
     std::optional<v8::Local<v8::BigInt>> idl_filtering_id,
+    bool additional_extensions_allowed,
     std::string* error) {
-  auction_worklet::mojom::ForEventSignalBucketPtr bucket =
-      GetBucket(isolate, std::move(idl_bucket), error);
+  auction_worklet::mojom::ForEventSignalBucketPtr bucket = GetBucket(
+      isolate, std::move(idl_bucket), additional_extensions_allowed, error);
   if (!bucket) {
     return nullptr;
   }
-  auction_worklet::mojom::ForEventSignalValuePtr value =
-      GetValue(isolate, std::move(idl_value), error);
+  auction_worklet::mojom::ForEventSignalValuePtr value = GetValue(
+      isolate, std::move(idl_value), additional_extensions_allowed, error);
   if (!value) {
     return nullptr;
   }
@@ -642,7 +662,8 @@
   auction_worklet::mojom::AggregatableReportForEventContributionPtr
       contribution = ParseForEventContribution(
           isolate, std::move(event_type), std::move(bucket), std::move(value),
-          std::move(filtering_id), &error);
+          std::move(filtering_id), bindings->additional_extensions_allowed_,
+          &error);
 
   if (contribution.is_null()) {
     CHECK(base::IsStringUTF8(error));
diff --git a/content/services/auction_worklet/public/cpp/private_aggregation_reporting.cc b/content/services/auction_worklet/public/cpp/private_aggregation_reporting.cc
index f9ad9ff3..0485be0 100644
--- a/content/services/auction_worklet/public/cpp/private_aggregation_reporting.cc
+++ b/content/services/auction_worklet/public/cpp/private_aggregation_reporting.cc
@@ -27,7 +27,7 @@
          {"reserved.once",
           auction_worklet::mojom::ReservedEventType::kReservedOnce}});
 
-bool RequiresAdditionalExtensions(
+bool RequiresAdditionalExtensionsForReservedEventType(
     auction_worklet::mojom::ReservedEventType type) {
   return type == auction_worklet::mojom::ReservedEventType::kReservedOnce;
 }
@@ -42,7 +42,8 @@
     return std::nullopt;
   }
   auction_worklet::mojom::ReservedEventType keyword = it->second;
-  if (!additional_extensions_allowed && RequiresAdditionalExtensions(keyword)) {
+  if (!additional_extensions_allowed &&
+      RequiresAdditionalExtensionsForReservedEventType(keyword)) {
     return std::nullopt;
   }
   return keyword;
@@ -82,12 +83,42 @@
       *request.contribution->get_for_event_contribution();
 
   if (for_event_contrib.event_type->is_reserved() &&
-      RequiresAdditionalExtensions(
+      RequiresAdditionalExtensionsForReservedEventType(
           for_event_contrib.event_type->get_reserved())) {
     return false;
   }
 
+  if (for_event_contrib.bucket->is_signal_bucket() &&
+      RequiresAdditionalExtensions(
+          for_event_contrib.bucket->get_signal_bucket()->base_value)) {
+    return false;
+  }
+  if (for_event_contrib.value->is_signal_value() &&
+      RequiresAdditionalExtensions(
+          for_event_contrib.value->get_signal_value()->base_value)) {
+    return false;
+  }
+
   return true;
 }
 
+bool HasKAnonFailureComponent(const mojom::PrivateAggregationRequest& request) {
+  if (request.contribution->is_histogram_contribution()) {
+    return false;
+  }
+  const mojom::AggregatableReportForEventContributionPtr& event_contribution =
+      request.contribution->get_for_event_contribution();
+  if (event_contribution->bucket->is_signal_bucket() &&
+      event_contribution->bucket->get_signal_bucket()->base_value ==
+          mojom::BaseValue::kBidRejectReason) {
+    return true;
+  }
+  if (event_contribution->value->is_signal_value() &&
+      event_contribution->value->get_signal_value()->base_value ==
+          mojom::BaseValue::kBidRejectReason) {
+    return true;
+  }
+  return false;
+}
+
 }  // namespace auction_worklet
diff --git a/content/services/auction_worklet/public/cpp/private_aggregation_reporting.h b/content/services/auction_worklet/public/cpp/private_aggregation_reporting.h
index ac1c49b..9eb9db3 100644
--- a/content/services/auction_worklet/public/cpp/private_aggregation_reporting.h
+++ b/content/services/auction_worklet/public/cpp/private_aggregation_reporting.h
@@ -22,12 +22,25 @@
     const std::string& event_type_str,
     bool additional_extensions_allowed);
 
+// Returns true if `value` requires the feature
+// kPrivateAggregationApiProtectedAudienceAdditionalExtensions to be used.
+CONTENT_EXPORT inline bool RequiresAdditionalExtensions(
+    mojom::BaseValue value) {
+  return value > mojom::BaseValue::kBidRejectReason;
+}
+
 // Returns whether the request is valid or not, checking whether it uses
 // features enabled based on `additional_extensions_allowed`.
 CONTENT_EXPORT bool IsValidPrivateAggregationRequestForAdditionalExtensions(
     const auction_worklet::mojom::PrivateAggregationRequest& request,
     bool additional_extensions_allowed);
 
+// Returns true if `request` is asking to record reject-reason, and therefore
+// can be used to report kBelowKAnonThreshold for the bid that would have
+// won if not for k-anonymity.
+CONTENT_EXPORT bool HasKAnonFailureComponent(
+    const mojom::PrivateAggregationRequest& request);
+
 }  // namespace auction_worklet
 
 #endif  // CONTENT_SERVICES_AUCTION_WORKLET_PUBLIC_CPP_PRIVATE_AGGREGATION_REPORTING_H_
diff --git a/content/services/auction_worklet/public/cpp/private_aggregation_reporting_unittest.cc b/content/services/auction_worklet/public/cpp/private_aggregation_reporting_unittest.cc
index 8871e216..14cb296 100644
--- a/content/services/auction_worklet/public/cpp/private_aggregation_reporting_unittest.cc
+++ b/content/services/auction_worklet/public/cpp/private_aggregation_reporting_unittest.cc
@@ -62,6 +62,62 @@
           blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
+  // Using kWinningBid base_value for bucket and value.
+  const mojom::PrivateAggregationRequestPtr kWithOldBaseValues =
+      mojom::PrivateAggregationRequest::New(
+          mojom::AggregatableReportContribution::NewForEventContribution(
+              mojom::AggregatableReportForEventContribution::New(
+                  mojom::ForEventSignalBucket::NewSignalBucket(
+                      mojom::SignalBucket::New(mojom::BaseValue::kWinningBid,
+                                               1.0,
+                                               mojom::BucketOffsetPtr())),
+                  mojom::ForEventSignalValue::NewSignalValue(
+                      mojom::SignalValue::New(mojom::BaseValue::kWinningBid,
+                                              1.0,
+                                              0)),
+                  /*filtering_id=*/std::nullopt,
+                  mojom::EventType::NewNonReserved("event_type"))),
+          blink::mojom::AggregationServiceMode::kDefault,
+          blink::mojom::DebugModeDetails::New());
+
+  // Using kAverageCodeFetchTime for value.
+  const mojom::PrivateAggregationRequestPtr kWithNewValueBaseValue =
+      mojom::PrivateAggregationRequest::New(
+          mojom::AggregatableReportContribution::NewForEventContribution(
+              mojom::AggregatableReportForEventContribution::New(
+                  mojom::ForEventSignalBucket::NewSignalBucket(
+                      mojom::SignalBucket::New(mojom::BaseValue::kWinningBid,
+                                               1.0,
+                                               mojom::BucketOffsetPtr())),
+                  mojom::ForEventSignalValue::NewSignalValue(
+                      mojom::SignalValue::New(
+                          mojom::BaseValue::kAverageCodeFetchTime,
+                          1.0,
+                          0)),
+                  /*filtering_id=*/std::nullopt,
+                  mojom::EventType::NewNonReserved("event_type"))),
+          blink::mojom::AggregationServiceMode::kDefault,
+          blink::mojom::DebugModeDetails::New());
+
+  // Using kAverageCodeFetchTime for bucket.
+  const mojom::PrivateAggregationRequestPtr kWithNewBucketBaseValue =
+      mojom::PrivateAggregationRequest::New(
+          mojom::AggregatableReportContribution::NewForEventContribution(
+              mojom::AggregatableReportForEventContribution::New(
+                  mojom::ForEventSignalBucket::NewSignalBucket(
+                      mojom::SignalBucket::New(
+                          mojom::BaseValue::kAverageCodeFetchTime,
+                          1.0,
+                          mojom::BucketOffsetPtr())),
+                  mojom::ForEventSignalValue::NewSignalValue(
+                      mojom::SignalValue::New(mojom::BaseValue::kWinningBid,
+                                              1.0,
+                                              0)),
+                  /*filtering_id=*/std::nullopt,
+                  mojom::EventType::NewNonReserved("event_type"))),
+          blink::mojom::AggregationServiceMode::kDefault,
+          blink::mojom::DebugModeDetails::New());
+
   // Just a raw histogram, not conditional on an event.
   const mojom::PrivateAggregationRequestPtr kNonEvent =
       mojom::PrivateAggregationRequest::New(
@@ -72,6 +128,56 @@
                   /*filtering_id=*/std::nullopt)),
           blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
+
+  // Using kWinningBid base_value for bucket and value.
+  const mojom::PrivateAggregationRequestPtr kWinningBid =
+      mojom::PrivateAggregationRequest::New(
+          mojom::AggregatableReportContribution::NewForEventContribution(
+              mojom::AggregatableReportForEventContribution::New(
+                  mojom::ForEventSignalBucket::NewSignalBucket(
+                      mojom::SignalBucket::New(mojom::BaseValue::kWinningBid,
+                                               1.0,
+                                               mojom::BucketOffsetPtr())),
+                  mojom::ForEventSignalValue::NewSignalValue(
+                      mojom::SignalValue::New(mojom::BaseValue::kWinningBid,
+                                              1.0,
+                                              0)),
+                  /*filtering_id=*/std::nullopt,
+                  mojom::EventType::NewNonReserved("event_type"))),
+          blink::mojom::AggregationServiceMode::kDefault,
+          blink::mojom::DebugModeDetails::New());
+
+  // Using kRejectReason for value.
+  const mojom::PrivateAggregationRequestPtr kWithRejectReasonValue =
+      mojom::PrivateAggregationRequest::New(
+          mojom::AggregatableReportContribution::NewForEventContribution(
+              mojom::AggregatableReportForEventContribution::New(
+                  mojom::ForEventSignalBucket::NewIdBucket(1),
+                  mojom::ForEventSignalValue::NewSignalValue(
+                      mojom::SignalValue::New(
+                          mojom::BaseValue::kBidRejectReason,
+                          1.0,
+                          0)),
+                  /*filtering_id=*/std::nullopt,
+                  mojom::EventType::NewNonReserved("event_type"))),
+          blink::mojom::AggregationServiceMode::kDefault,
+          blink::mojom::DebugModeDetails::New());
+
+  // Using kRejectReason for bucket.
+  const mojom::PrivateAggregationRequestPtr kWithRejectReasonBucket =
+      mojom::PrivateAggregationRequest::New(
+          mojom::AggregatableReportContribution::NewForEventContribution(
+              mojom::AggregatableReportForEventContribution::New(
+                  mojom::ForEventSignalBucket::NewSignalBucket(
+                      mojom::SignalBucket::New(
+                          mojom::BaseValue::kBidRejectReason,
+                          1.0,
+                          mojom::BucketOffsetPtr())),
+                  mojom::ForEventSignalValue::NewIntValue(2),
+                  /*filtering_id=*/std::nullopt,
+                  mojom::EventType::NewNonReserved("event_type"))),
+          blink::mojom::AggregationServiceMode::kDefault,
+          blink::mojom::DebugModeDetails::New());
 };
 
 TEST_F(PaReportingTest,
@@ -95,6 +201,45 @@
       *kNonEvent, /*additional_extensions_allowed=*/true));
   EXPECT_TRUE(IsValidPrivateAggregationRequestForAdditionalExtensions(
       *kNonEvent, /*additional_extensions_allowed=*/false));
+
+  EXPECT_TRUE(IsValidPrivateAggregationRequestForAdditionalExtensions(
+      *kWithOldBaseValues, /*additional_extensions_allowed=*/true));
+  EXPECT_TRUE(IsValidPrivateAggregationRequestForAdditionalExtensions(
+      *kWithOldBaseValues, /*additional_extensions_allowed=*/false));
+
+  EXPECT_TRUE(IsValidPrivateAggregationRequestForAdditionalExtensions(
+      *kWithNewValueBaseValue, /*additional_extensions_allowed=*/true));
+  EXPECT_FALSE(IsValidPrivateAggregationRequestForAdditionalExtensions(
+      *kWithNewValueBaseValue, /*additional_extensions_allowed=*/false));
+
+  EXPECT_TRUE(IsValidPrivateAggregationRequestForAdditionalExtensions(
+      *kWithNewBucketBaseValue, /*additional_extensions_allowed=*/true));
+  EXPECT_FALSE(IsValidPrivateAggregationRequestForAdditionalExtensions(
+      *kWithNewBucketBaseValue, /*additional_extensions_allowed=*/false));
+}
+
+TEST_F(PaReportingTest, RequiresAdditionalExtensions) {
+  EXPECT_FALSE(RequiresAdditionalExtensions(mojom::BaseValue::kWinningBid));
+  EXPECT_FALSE(
+      RequiresAdditionalExtensions(mojom::BaseValue::kHighestScoringOtherBid));
+  EXPECT_FALSE(RequiresAdditionalExtensions(mojom::BaseValue::kScriptRunTime));
+  EXPECT_FALSE(
+      RequiresAdditionalExtensions(mojom::BaseValue::kSignalsFetchTime));
+  EXPECT_FALSE(
+      RequiresAdditionalExtensions(mojom::BaseValue::kBidRejectReason));
+  EXPECT_TRUE(RequiresAdditionalExtensions(
+      mojom::BaseValue::kParticipatingInterestGroupCount));
+  EXPECT_TRUE(
+      RequiresAdditionalExtensions(mojom::BaseValue::kAverageCodeFetchTime));
+}
+
+TEST_F(PaReportingTest, HasKAnonFailureComponent) {
+  EXPECT_FALSE(HasKAnonFailureComponent(*kNonEvent));
+  EXPECT_FALSE(HasKAnonFailureComponent(*kNonReserved));
+  EXPECT_FALSE(HasKAnonFailureComponent(*kWithReservedAlways));
+  EXPECT_FALSE(HasKAnonFailureComponent(*kWinningBid));
+  EXPECT_TRUE(HasKAnonFailureComponent(*kWithRejectReasonValue));
+  EXPECT_TRUE(HasKAnonFailureComponent(*kWithRejectReasonBucket));
 }
 
 }  // namespace
diff --git a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
index 297bc78..d92438b8 100644
--- a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
+++ b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
@@ -203,6 +203,21 @@
   mojo_base.mojom.TimeTicks generate_bid_finish_time;
 };
 
+// How long particular tasks took. Unlike GenerateBidDependencyLatencies this
+// doesn't denote how long things blocked for --- e.g. the fetch times are
+// how long the download took, even for later calls to generateBid() that
+// may not actually wait for the download since it's already in memory.
+struct BidderTimingMetrics {
+  mojo_base.mojom.TimeDelta? js_fetch_latency;
+  mojo_base.mojom.TimeDelta? wasm_fetch_latency;
+
+  // Time to run generateBid (including any k-anon re-run) or reportWin,
+  // respectively. For generateBid, this will also include any top-level
+  // execution which happened (which it might not have depending on the
+  // execution mode).
+  mojo_base.mojom.TimeDelta script_latency;
+};
+
 // Single use client for each GenerateBid() call. Allows deferring generating
 // bids until after a bidder's interest groups have all received priority
 // vectors, which allows for cancelling generate bid calls from lower priority
@@ -293,8 +308,8 @@
   //
   // `real_time_contributions` Real time reporting contributions.
   //
-  // `bidding_latency` The amount of time taken running all bids (note that
-  // there may be 2 bids if the first bid result was not k-anonymous).
+  // `generate_bid_timing_metrics` The amount of time some of the operations
+  // performed took.
   //
   // `generate_bid_dependency_latencies` The amount of time GenerateBid had to
   // wait for each of its dependencies to be fulfilled before it could be run.
@@ -318,7 +333,7 @@
       array<PrivateAggregationRequest> pa_requests,
       array<PrivateAggregationRequest> non_kanon_pa_requests,
       array<RealTimeReportingContribution> real_time_contributions,
-      mojo_base.mojom.TimeDelta bidding_latency,
+      BidderTimingMetrics generate_bid_timing_metrics,
       GenerateBidDependencyLatencies generate_bid_dependency_latencies,
       RejectReason reject_reason,
       array<string> errors);
@@ -668,7 +683,7 @@
           map<string, url.mojom.Url> ad_beacon_map,
           map<string, string> ad_macro_map,
           array<PrivateAggregationRequest> pa_requests,
-          mojo_base.mojom.TimeDelta reporting_latency,
+          BidderTimingMetrics timing_metrics,
           array<string> errors);
 
   // Establishes a debugger connection to the worklet thread.
diff --git a/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom b/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom
index ba255a6..97318c1b 100644
--- a/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom
+++ b/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom
@@ -16,6 +16,10 @@
   kScriptRunTime = 2,
   kSignalsFetchTime = 3,
   kBidRejectReason = 4,
+  // Values after this point require the feature
+  // kPrivateAggregationApiProtectedAudienceAdditionalExtensions to be on.
+  kParticipatingInterestGroupCount = 5,
+  kAverageCodeFetchTime = 6,
 };
 
 // Bucket's offset to add/subtract to the auction result value. Offset's `value`
diff --git a/content/services/auction_worklet/public/mojom/seller_worklet.mojom b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
index 12d19053..5ac3bc9e 100644
--- a/content/services/auction_worklet/public/mojom/seller_worklet.mojom
+++ b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
@@ -71,6 +71,18 @@
   mojo_base.mojom.TimeTicks score_ad_finish_time;
 };
 
+// How long particular tasks took. Unlike ScoreAdDependencyLatencies this
+// doesn't denote how long things blocked for --- e.g. the fetch times are
+// how long the download took, even for later calls to scoreAd() that may not
+// actually wait for the download since it's already in memory.
+struct SellerTimingMetrics {
+  mojo_base.mojom.TimeDelta? js_fetch_latency;
+
+  // How long it took to execute the script (including both the top-level
+  // and the function).
+  mojo_base.mojom.TimeDelta script_latency;
+};
+
 // Interface for returning ScoreAd results. The advantage of having an interface
 // is that it makes ScoreAd() calls cancellable, and allows callbacks passed
 // over the Mojo pipe to be deleted when the Mojo pipe is, to avoid setting off
@@ -114,11 +126,10 @@
   //
   // `real_time_contributions` Real time reporting contributions.
   //
-  // `scoring_latency` How long it took to execute the scoreAd() JavaScript,
-  //  (including the top-level).
+  // `score_ad_timing_metrics` Time metrics relevant to this call.
   //
-  // `trusted_signals_fetch_latency` How long it took to fetch the trusted
-  //  scoring signals, if any. 0 if there weren't any.
+  // `score_ad_dependency_latencies` How long various depedent-on operations
+  // were waited for on this particular call.
   //
   // `errors` are various error messages to be used for debugging. These are too
   //  sensitive for the renderers to see. `errors` should not be assumed to be
@@ -134,7 +145,7 @@
                     url.mojom.Url? debug_win_report_url,
                     array<PrivateAggregationRequest> pa_requests,
                     array<RealTimeReportingContribution> real_time_contributions,
-                    mojo_base.mojom.TimeDelta scoring_latency,
+                    SellerTimingMetrics score_ad_timing_metrics,
                     ScoreAdDependencyLatencies score_ad_dependency_latencies,
                     array<string> errors);
 };
@@ -410,7 +421,7 @@
            url.mojom.Url? report_url,
            map<string, url.mojom.Url> ad_beacon_map,
            array<PrivateAggregationRequest> pa_requests,
-           mojo_base.mojom.TimeDelta reporting_latency,
+           SellerTimingMetrics time_metrics,
            array<string> error_msgs);
 
   // Establishes a debugger connection to the worklet thread.
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc
index d532d24..e235dcc 100644
--- a/content/services/auction_worklet/seller_worklet.cc
+++ b/content/services/auction_worklet/seller_worklet.cc
@@ -1846,6 +1846,7 @@
       "Ads.InterestGroup.Net.RequestUrlSizeBytes.ScoringScriptJS",
       script_source_url_.spec().size());
 
+  code_download_start_ = base::TimeTicks::Now();
   worklet_loader_ = std::make_unique<WorkletLoader>(
       url_loader_factory_.get(), /*auction_network_events_handler=*/
       CreateNewAuctionNetworkEventsHandlerRemote(
@@ -1862,6 +1863,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
 
   DCHECK_EQ(worklet_scripts.size(), v8_helpers_.size());
+  js_fetch_latency_ = base::TimeTicks::Now() - code_download_start_;
 
   // Use `worklet_scripts[0]` for metrics and for the failure check. All the
   // results should be the same.
@@ -2180,7 +2182,10 @@
       score, reject_reason, std::move(component_auction_modified_bid_params),
       std::move(bid_in_seller_currency), scoring_signals_data_version,
       debug_loss_report_url, debug_win_report_url, std::move(pa_requests),
-      std::move(real_time_contributions), scoring_latency,
+      std::move(real_time_contributions),
+      mojom::SellerTimingMetrics::New(
+          /*js_fetch_latency=*/js_fetch_latency_,
+          /*script_latency=*/scoring_latency),
       mojom::ScoreAdDependencyLatencies::New(
           /*code_ready_latency=*/NullOptIfZero(task->wait_code),
           /*direct_from_seller_signals_latency=*/
@@ -2302,7 +2307,11 @@
 
   std::move(task->callback)
       .Run(signals_for_winner, report_url, ad_beacon_map,
-           std::move(pa_requests), reporting_latency, std::move(errors));
+           std::move(pa_requests),
+           mojom::SellerTimingMetrics::New(
+               /*js_fetch_latency=*/js_fetch_latency_,
+               /*script_latency=*/reporting_latency),
+           std::move(errors));
   report_result_tasks_.erase(task);
 }
 
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h
index 268253ad..b6ba0dd 100644
--- a/content/services/auction_worklet/seller_worklet.h
+++ b/content/services/auction_worklet/seller_worklet.h
@@ -633,6 +633,8 @@
 
   // Deleted once load has completed.
   std::unique_ptr<WorkletLoader> worklet_loader_;
+  base::TimeTicks code_download_start_;
+  std::optional<base::TimeDelta> js_fetch_latency_;
 
   // Lives on `v8_runners_`. Since it's deleted there, tasks can be safely
   // posted from main thread to it with an Unretained pointer.
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc
index 9d670d5..6313475 100644
--- a/content/services/auction_worklet/seller_worklet_unittest.cc
+++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -135,7 +135,7 @@
       const std::optional<GURL>& debug_win_report_url,
       PrivateAggregationRequests pa_requests,
       RealTimeReportingContributions real_time_contributions,
-      base::TimeDelta scoring_latency,
+      mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
       mojom::ScoreAdDependencyLatenciesPtr score_ad_dependency_latencies,
       const std::vector<std::string>& errors)>;
 
@@ -166,7 +166,7 @@
       const std::optional<GURL>& debug_win_report_url,
       PrivateAggregationRequests pa_requests,
       RealTimeReportingContributions real_time_contributions,
-      base::TimeDelta scoring_latency,
+      mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
       mojom::ScoreAdDependencyLatenciesPtr score_ad_dependency_latencies,
       const std::vector<std::string>& errors) override {
     std::move(score_ad_complete_callback_)
@@ -175,7 +175,8 @@
              std::move(bid_in_seller_currency),
              std::move(scoring_signals_data_version), debug_loss_report_url,
              debug_win_report_url, std::move(pa_requests),
-             std::move(real_time_contributions), scoring_latency,
+             std::move(real_time_contributions),
+             std::move(score_ad_timing_metrics),
              std::move(score_ad_dependency_latencies), errors);
   }
 
@@ -190,7 +191,7 @@
            const std::optional<GURL>& debug_win_report_url,
            PrivateAggregationRequests pa_requests,
            RealTimeReportingContributions real_time_contributions,
-           base::TimeDelta scoring_latency,
+           mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
            mojom::ScoreAdDependencyLatenciesPtr score_ad_dependency_latencies,
            const std::vector<std::string>& errors) {
           ADD_FAILURE() << "Callback should not be invoked";
@@ -441,7 +442,7 @@
                const std::optional<GURL>& debug_win_report_url,
                PrivateAggregationRequests pa_requests,
                RealTimeReportingContributions real_time_contributions,
-               base::TimeDelta scoring_latency,
+               mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                mojom::ScoreAdDependencyLatenciesPtr
                    score_ad_dependency_latencies,
                const std::vector<std::string>& errors) {
@@ -469,7 +470,7 @@
               if (expected_score_ad_timeout) {
                 // We only know that about the time of the timeout should have
                 // elapsed, and there may also be some thread skew.
-                EXPECT_GE(scoring_latency,
+                EXPECT_GE(score_ad_timing_metrics->script_latency,
                           expected_score_ad_timeout.value() * 0.9);
               }
               if (expected_signals_fetch_latency) {
@@ -662,7 +663,7 @@
                const std::optional<GURL>& report_url,
                const base::flat_map<std::string, GURL>& ad_beacon_map,
                PrivateAggregationRequests pa_requests,
-               base::TimeDelta reporting_latency,
+               auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
                const std::vector<std::string>& errors) {
               if (signals_for_winner && expected_signals_for_winner) {
                 // If neither is null, used fancy base::Value comparison, which
@@ -680,7 +681,7 @@
               if (expected_reporting_latency_timeout) {
                 // We only know that about the time of the timeout should have
                 // elapsed, and there may also be some thread skew.
-                EXPECT_GE(reporting_latency,
+                EXPECT_GE(timing_metrics->script_latency,
                           (reporting_timeout.has_value()
                                ? reporting_timeout.value()
                                : AuctionV8Helper::kScriptTimeout) *
@@ -720,7 +721,7 @@
                const std::optional<GURL>& report_url,
                const base::flat_map<std::string, GURL>& ad_beacon_map,
                PrivateAggregationRequests pa_requests,
-               base::TimeDelta reporting_latency,
+               auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
                const std::vector<std::string>& errors) {
               ADD_FAILURE() << "This should not be invoked";
             }));
@@ -2142,6 +2143,50 @@
   run_loop.Run();
 }
 
+TEST_F(SellerWorkletTest, ScoreAdJsFetchLatency) {
+  auto seller_worklet = CreateWorklet();
+  ASSERT_TRUE(seller_worklet);
+  base::RunLoop run_loop;
+  seller_worklet->ScoreAd(
+      ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
+      direct_from_seller_seller_signals_,
+      direct_from_seller_seller_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_,
+      browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
+      browser_signal_interest_group_owner_, browser_signal_render_url_,
+      browser_signal_selected_buyer_and_seller_reporting_id_,
+      browser_signal_buyer_and_seller_reporting_id_,
+      browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
+      browser_signal_render_size_,
+      browser_signal_for_debugging_only_in_cooldown_or_lockout_,
+      seller_timeout_,
+      /*trace_id=*/1,
+      TestScoreAdClient::Create(base::BindLambdaForTesting(
+          [&run_loop](double score, mojom::RejectReason reject_reason,
+                      mojom::ComponentAuctionModifiedBidParamsPtr
+                          component_auction_modified_bid_params,
+                      std::optional<double> bid_in_seller_currency,
+                      std::optional<uint32_t> scoring_signals_data_version,
+                      const std::optional<GURL>& debug_loss_report_url,
+                      const std::optional<GURL>& debug_win_report_url,
+                      PrivateAggregationRequests pa_requests,
+                      RealTimeReportingContributions real_time_contributions,
+                      mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
+                      mojom::ScoreAdDependencyLatenciesPtr
+                          score_ad_dependency_latencies,
+                      const std::vector<std::string>& errors) {
+            ASSERT_TRUE(score_ad_timing_metrics->js_fetch_latency.has_value());
+            EXPECT_EQ(base::Milliseconds(235),
+                      *score_ad_timing_metrics->js_fetch_latency);
+            run_loop.Quit();
+          })));
+  task_environment_.FastForwardBy(base::Milliseconds(235));
+  AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
+                        CreateScoreAdScript(/*raw_return_value=*/"1", ""));
+  run_loop.Run();
+}
+
 TEST_F(SellerWorkletTest, ScoreAdDataVersion) {
   trusted_scoring_signals_url_ =
       GURL("https://url.test/trusted_scoring_signals");
@@ -3875,6 +3920,45 @@
       /*expected_report_url=*/std::nullopt);
 }
 
+TEST_F(SellerWorkletTest, ReportResultJsFetchLatency) {
+  auto seller_worklet = CreateWorklet();
+  ASSERT_TRUE(seller_worklet);
+  base::RunLoop run_loop;
+  seller_worklet->ReportResult(
+      auction_ad_config_non_shared_params_, direct_from_seller_seller_signals_,
+      direct_from_seller_seller_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_,
+      browser_signals_other_seller_.Clone(),
+      browser_signal_interest_group_owner_,
+      browser_signal_buyer_and_seller_reporting_id_,
+      browser_signal_selected_buyer_and_seller_reporting_id_,
+      browser_signal_render_url_, bid_, bid_currency_,
+      browser_signal_desireability_, browser_signal_highest_scoring_other_bid_,
+      browser_signal_highest_scoring_other_bid_currency_,
+      browser_signals_component_auction_report_result_params_.Clone(),
+      browser_signal_data_version_,
+      /*trace_id=*/1,
+      base::BindOnce(
+          [](base::OnceClosure done_closure,
+             const std::optional<std::string>& signals_for_winner,
+             const std::optional<GURL>& report_url,
+             const base::flat_map<std::string, GURL>& ad_beacon_map,
+             PrivateAggregationRequests pa_requests,
+             auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
+             const std::vector<std::string>& errors) {
+            ASSERT_TRUE(timing_metrics->js_fetch_latency.has_value());
+            EXPECT_EQ(base::Milliseconds(235),
+                      *timing_metrics->js_fetch_latency);
+            std::move(done_closure).Run();
+          },
+          run_loop.QuitClosure()));
+  task_environment_.FastForwardBy(base::Milliseconds(235));
+  AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
+                        CreateScoreAdScript(/*raw_return_value=*/"1", ""));
+  run_loop.Run();
+}
+
 // It shouldn't matter the order in which network fetches complete. For each
 // required and optional reportResult() URL load prerequisite, ensure that
 // reportResult() completes when that URL is the last loaded URL.
@@ -4001,7 +4085,7 @@
                   const std::optional<GURL>& debug_win_report_url,
                   PrivateAggregationRequests pa_requests,
                   RealTimeReportingContributions real_time_contributions,
-                  base::TimeDelta scoring_latency,
+                  mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                   mojom::ScoreAdDependencyLatenciesPtr
                       score_ad_dependency_latencies,
                   const std::vector<std::string>& errors) {
@@ -4038,7 +4122,7 @@
                   const std::optional<GURL>& report_url,
                   const base::flat_map<std::string, GURL>& ad_beacon_map,
                   PrivateAggregationRequests pa_requests,
-                  base::TimeDelta reporting_latency,
+                  auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
                   const std::vector<std::string>& errors) {
                 EXPECT_EQ("2", signals_for_winner);
                 EXPECT_TRUE(errors.empty());
@@ -4103,7 +4187,7 @@
                 const std::optional<GURL>& debug_win_report_url,
                 PrivateAggregationRequests pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta scoring_latency,
+                mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                 mojom::ScoreAdDependencyLatenciesPtr
                     score_ad_dependency_latencies,
                 const std::vector<std::string>& errors) {
@@ -4133,12 +4217,13 @@
       browser_signal_data_version_,
       /*trace_id=*/1,
       base::BindLambdaForTesting(
-          [&run_loop](const std::optional<std::string>& signals_for_winner,
-                      const std::optional<GURL>& report_url,
-                      const base::flat_map<std::string, GURL>& ad_beacon_map,
-                      PrivateAggregationRequests pa_requests,
-                      base::TimeDelta reporting_latency,
-                      const std::vector<std::string>& errors) {
+          [&run_loop](
+              const std::optional<std::string>& signals_for_winner,
+              const std::optional<GURL>& report_url,
+              const base::flat_map<std::string, GURL>& ad_beacon_map,
+              PrivateAggregationRequests pa_requests,
+              auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
+              const std::vector<std::string>& errors) {
             EXPECT_EQ("2", signals_for_winner);
             EXPECT_TRUE(errors.empty());
             run_loop.Quit();
@@ -4207,7 +4292,7 @@
                 const std::optional<GURL>& debug_win_report_url,
                 PrivateAggregationRequests pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta scoring_latency,
+                mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                 mojom::ScoreAdDependencyLatenciesPtr
                     score_ad_dependency_latencies,
                 const std::vector<std::string>& errors) {
@@ -4237,12 +4322,13 @@
       browser_signal_data_version_,
       /*trace_id=*/1,
       base::BindLambdaForTesting(
-          [&run_loop](const std::optional<std::string>& signals_for_winner,
-                      const std::optional<GURL>& report_url,
-                      const base::flat_map<std::string, GURL>& ad_beacon_map,
-                      PrivateAggregationRequests pa_requests,
-                      base::TimeDelta reporting_latency,
-                      const std::vector<std::string>& errors) {
+          [&run_loop](
+              const std::optional<std::string>& signals_for_winner,
+              const std::optional<GURL>& report_url,
+              const base::flat_map<std::string, GURL>& ad_beacon_map,
+              PrivateAggregationRequests pa_requests,
+              auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
+              const std::vector<std::string>& errors) {
             EXPECT_EQ("2", signals_for_winner);
             EXPECT_TRUE(errors.empty());
             run_loop.Quit();
@@ -4319,7 +4405,7 @@
                     const std::optional<GURL>& debug_win_report_url,
                     PrivateAggregationRequests pa_requests,
                     RealTimeReportingContributions real_time_contributions,
-                    base::TimeDelta scoring_latency,
+                    mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                     mojom::ScoreAdDependencyLatenciesPtr
                         score_ad_dependency_latencies,
                     const std::vector<std::string>& errors) {
@@ -4358,7 +4444,8 @@
                     const std::optional<GURL>& report_url,
                     const base::flat_map<std::string, GURL>& ad_beacon_map,
                     PrivateAggregationRequests pa_requests,
-                    base::TimeDelta reporting_latency,
+                    auction_worklet::mojom::SellerTimingMetricsPtr
+                        timing_metrics,
                     const std::vector<std::string>& errors) {
                   EXPECT_EQ("2", signals_for_winner);
                   EXPECT_TRUE(errors.empty());
@@ -4435,7 +4522,7 @@
                 const std::optional<GURL>& debug_win_report_url,
                 PrivateAggregationRequests pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta scoring_latency,
+                mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                 mojom::ScoreAdDependencyLatenciesPtr
                     score_ad_dependency_latencies,
                 const std::vector<std::string>& errors) {
@@ -4497,7 +4584,7 @@
                 const std::optional<GURL>& debug_win_report_url,
                 PrivateAggregationRequests pa_requests,
                 RealTimeReportingContributions real_time_contributions,
-                base::TimeDelta scoring_latency,
+                mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                 mojom::ScoreAdDependencyLatenciesPtr
                     score_ad_dependency_latencies,
                 const std::vector<std::string>& errors) {
@@ -4565,14 +4652,16 @@
       browser_signals_component_auction_report_result_params_.Clone(),
       browser_signal_data_version_,
       /*trace_id=*/1,
-      base::BindOnce([](const std::optional<std::string>& signals_for_winner,
-                        const std::optional<GURL>& report_url,
-                        const base::flat_map<std::string, GURL>& ad_beacon_map,
-                        PrivateAggregationRequests pa_requests,
-                        base::TimeDelta reporting_latency,
-                        const std::vector<std::string>& errors) {
-        ADD_FAILURE() << "Callback should not be invoked since worklet deleted";
-      }));
+      base::BindOnce(
+          [](const std::optional<std::string>& signals_for_winner,
+             const std::optional<GURL>& report_url,
+             const base::flat_map<std::string, GURL>& ad_beacon_map,
+             PrivateAggregationRequests pa_requests,
+             auction_worklet::mojom::SellerTimingMetricsPtr timing_metrics,
+             const std::vector<std::string>& errors) {
+            ADD_FAILURE()
+                << "Callback should not be invoked since worklet deleted";
+          }));
   base::RunLoop().RunUntilIdle();
   seller_worklet.reset();
   event_handle->Signal();
@@ -6449,7 +6538,7 @@
                         const std::optional<GURL>& debug_win_report_url,
                         PrivateAggregationRequests pa_requests,
                         RealTimeReportingContributions real_time_contributions,
-                        base::TimeDelta scoring_latency,
+                        mojom::SellerTimingMetricsPtr score_ad_timing_metrics,
                         mojom::ScoreAdDependencyLatenciesPtr
                             score_ad_dependency_latencies,
                         const std::vector<std::string>& errors) {
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist
index 890106d..58b4b47 100644
--- a/content/test/content_test_bundle_data.filelist
+++ b/content/test/content_test_bundle_data.filelist
@@ -3238,11 +3238,39 @@
 data/accessibility/html/custom-element-with-aria-owns-outside-expected-blink.txt
 data/accessibility/html/custom-element-with-aria-owns-outside.html
 data/accessibility/html/custom-element.html
+data/accessibility/html/custom-select-expected-android-assist-data.txt
+data/accessibility/html/custom-select-expected-android-external.txt
+data/accessibility/html/custom-select-expected-android.txt
+data/accessibility/html/custom-select-expected-auralinux.txt
 data/accessibility/html/custom-select-expected-blink.txt
+data/accessibility/html/custom-select-expected-mac.txt
+data/accessibility/html/custom-select-expected-uia-win.txt
+data/accessibility/html/custom-select-expected-win.txt
+data/accessibility/html/custom-select-open-expected-android-assist-data.txt
+data/accessibility/html/custom-select-open-expected-android-external.txt
+data/accessibility/html/custom-select-open-expected-android.txt
+data/accessibility/html/custom-select-open-expected-auralinux.txt
 data/accessibility/html/custom-select-open-expected-blink.txt
+data/accessibility/html/custom-select-open-expected-mac.txt
+data/accessibility/html/custom-select-open-expected-uia-win.txt
+data/accessibility/html/custom-select-open-expected-win.txt
 data/accessibility/html/custom-select-open.html
+data/accessibility/html/custom-select-simple-expected-android-assist-data.txt
+data/accessibility/html/custom-select-simple-expected-android-external.txt
+data/accessibility/html/custom-select-simple-expected-android.txt
+data/accessibility/html/custom-select-simple-expected-auralinux.txt
 data/accessibility/html/custom-select-simple-expected-blink.txt
+data/accessibility/html/custom-select-simple-expected-mac.txt
+data/accessibility/html/custom-select-simple-expected-uia-win.txt
+data/accessibility/html/custom-select-simple-expected-win.txt
+data/accessibility/html/custom-select-simple-open-expected-android-assist-data.txt
+data/accessibility/html/custom-select-simple-open-expected-android-external.txt
+data/accessibility/html/custom-select-simple-open-expected-android.txt
+data/accessibility/html/custom-select-simple-open-expected-auralinux.txt
 data/accessibility/html/custom-select-simple-open-expected-blink.txt
+data/accessibility/html/custom-select-simple-open-expected-mac.txt
+data/accessibility/html/custom-select-simple-open-expected-uia-win.txt
+data/accessibility/html/custom-select-simple-open-expected-win.txt
 data/accessibility/html/custom-select-simple-open.html
 data/accessibility/html/custom-select-simple.html
 data/accessibility/html/custom-select.html
@@ -4542,6 +4570,15 @@
 data/accessibility/html/ol.html
 data/accessibility/html/open-modal-expected-blink.txt
 data/accessibility/html/open-modal.html
+data/accessibility/html/optgroup-custom-menulist-expected-android-assist-data.txt
+data/accessibility/html/optgroup-custom-menulist-expected-android-external.txt
+data/accessibility/html/optgroup-custom-menulist-expected-android.txt
+data/accessibility/html/optgroup-custom-menulist-expected-auralinux.txt
+data/accessibility/html/optgroup-custom-menulist-expected-blink.txt
+data/accessibility/html/optgroup-custom-menulist-expected-mac.txt
+data/accessibility/html/optgroup-custom-menulist-expected-uia-win.txt
+data/accessibility/html/optgroup-custom-menulist-expected-win.txt
+data/accessibility/html/optgroup-custom-menulist.html
 data/accessibility/html/optgroup-expected-android-assist-data.txt
 data/accessibility/html/optgroup-expected-android-external.txt
 data/accessibility/html/optgroup-expected-android.txt
@@ -4551,6 +4588,14 @@
 data/accessibility/html/optgroup-expected-mac.txt
 data/accessibility/html/optgroup-expected-uia-win.txt
 data/accessibility/html/optgroup-expected-win.txt
+data/accessibility/html/optgroup-menulist-expected-android-assist-data.txt
+data/accessibility/html/optgroup-menulist-expected-android-external.txt
+data/accessibility/html/optgroup-menulist-expected-android.txt
+data/accessibility/html/optgroup-menulist-expected-auralinux.txt
+data/accessibility/html/optgroup-menulist-expected-blink.txt
+data/accessibility/html/optgroup-menulist-expected-uia-win.txt
+data/accessibility/html/optgroup-menulist-expected-win.txt
+data/accessibility/html/optgroup-menulist.html
 data/accessibility/html/optgroup.html
 data/accessibility/html/option-in-datalist-expected-auralinux.txt
 data/accessibility/html/option-in-datalist-expected-blink.txt
@@ -5881,6 +5926,7 @@
 data/attribution_reporting/interop/attribution_scopes_navigation_limit.json
 data/attribution_reporting/interop/attribution_scopes_null_scopes_removes_data.json
 data/attribution_reporting/interop/attribution_scopes_older_scopes_removed.json
+data/attribution_reporting/interop/attribution_scopes_older_scopes_removed_2.json
 data/attribution_reporting/interop/attribution_scopes_parsing_failures.json
 data/attribution_reporting/interop/attribution_scopes_smaller_scope_limit.json
 data/attribution_reporting/interop/basic.json
@@ -6766,6 +6812,8 @@
 data/gpu/webcodecs/frame-qp-encoding.html
 data/gpu/webcodecs/frame-size-change.html
 data/gpu/webcodecs/frame-size-change.js
+data/gpu/webcodecs/manual-svc.html
+data/gpu/webcodecs/manual-svc.js
 data/gpu/webcodecs/svc.html
 data/gpu/webcodecs/terminate-worker-worker.js
 data/gpu/webcodecs/terminate-worker.html
diff --git a/content/test/data/accessibility/event/aria-hidden-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-hidden-changed-expected-uia-win.txt
index 0c8e8de..8b13789 100644
--- a/content/test/data/accessibility/event/aria-hidden-changed-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/aria-hidden-changed-expected-uia-win.txt
@@ -1,3 +1 @@
-AriaProperties changed on role=document
-AriaProperties changed on role=heading, name=Item1
-AriaProperties changed on role=heading, name=Item2
+
diff --git a/content/test/data/accessibility/event/aria-hidden-descendants-expected-uia-win.txt b/content/test/data/accessibility/event/aria-hidden-descendants-expected-uia-win.txt
index 9a41d99..f853f13 100644
--- a/content/test/data/accessibility/event/aria-hidden-descendants-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/aria-hidden-descendants-expected-uia-win.txt
@@ -1,5 +1,3 @@
-AriaProperties changed on role=banner, name=Banner
-AriaProperties changed on role=toolbar
 StructureChanged/ChildAdded on role=banner, name=Banner
 StructureChanged/ChildRemoved on role=toolbar
 StructureChanged/ChildrenReordered on role=toolbar
diff --git a/content/test/data/accessibility/event/aria-hidden-single-descendant-expected-uia-win.txt b/content/test/data/accessibility/event/aria-hidden-single-descendant-expected-uia-win.txt
index d2429eb..b402772a 100644
--- a/content/test/data/accessibility/event/aria-hidden-single-descendant-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/aria-hidden-single-descendant-expected-uia-win.txt
@@ -1,5 +1,3 @@
-AriaProperties changed on role=document
 StructureChanged/ChildRemoved on role=document
 === Start Continuation ===
-AriaProperties changed on role=group
 StructureChanged/ChildAdded on role=group
diff --git a/content/test/data/accessibility/event/aria-hidden-single-descendant-visibility-hidden-expected-uia-win.txt b/content/test/data/accessibility/event/aria-hidden-single-descendant-visibility-hidden-expected-uia-win.txt
index 09eb22e6..edd2c78 100644
--- a/content/test/data/accessibility/event/aria-hidden-single-descendant-visibility-hidden-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/aria-hidden-single-descendant-visibility-hidden-expected-uia-win.txt
@@ -1,11 +1,5 @@
-AriaProperties changed on role=document
+=== Start Continuation ===
+=== Start Continuation ===
 StructureChanged/ChildRemoved on role=document
 === Start Continuation ===
-AriaProperties changed on role=document
-StructureChanged/ChildAdded on role=document
-=== Start Continuation ===
-AriaProperties changed on role=document
-StructureChanged/ChildRemoved on role=document
-=== Start Continuation ===
-AriaProperties changed on role=group
 StructureChanged/ChildAdded on role=group
diff --git a/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-uia-win.txt b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-uia-win.txt
index 96e67c874..670016f 100644
--- a/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-uia-win.txt
@@ -1,19 +1,5 @@
-AriaProperties changed on role=tree
-Name changed on role=tree
-Name changed on role=tree
-Name changed on role=tree
 StructureChanged/ChildRemoved on role=tree
 StructureChanged/ChildrenReordered on role=tree
-StructureChanged/ChildrenReordered on role=tree
-StructureChanged/ChildrenReordered on role=tree
-StructureChanged/ChildrenReordered on role=tree
 === Start Continuation ===
-AriaProperties changed on role=article
-Name changed on role=treeitem, name=grandchild1
-Name changed on role=treeitem, name=grandchild2
-Name changed on role=treeitem, name=grandchild3
 StructureChanged/ChildAdded on role=article
 StructureChanged/ChildrenReordered on role=tree
-StructureChanged/ChildrenReordered on role=treeitem, name=grandchild1
-StructureChanged/ChildrenReordered on role=treeitem, name=grandchild2
-StructureChanged/ChildrenReordered on role=treeitem, name=grandchild3
diff --git a/content/test/data/accessibility/event/iframe-src-changed-expected-auralinux.txt b/content/test/data/accessibility/event/iframe-src-changed-expected-auralinux.txt
index 3e9d0e58..26887c1 100644
--- a/content/test/data/accessibility/event/iframe-src-changed-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/iframe-src-changed-expected-auralinux.txt
@@ -3,4 +3,3 @@
 === Start Continuation ===
 LOAD-COMPLETE role=ROLE_DOCUMENT_WEB name='Inner Document 2' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
 STATE-CHANGE:BUSY:FALSE role=ROLE_DOCUMENT_WEB name='Inner Document 2' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:BUSY:TRUE role=ROLE_DOCUMENT_WEB name='(null)' BUSY,ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/iframe-src-changed.html b/content/test/data/accessibility/event/iframe-src-changed.html
index e7f4f2c..c63a3080 100644
--- a/content/test/data/accessibility/event/iframe-src-changed.html
+++ b/content/test/data/accessibility/event/iframe-src-changed.html
@@ -1,6 +1,11 @@
 <!--
 @AURALINUX-DENY:STATE-CHANGE:DEFUNCT:TRUE*
 @AURALINUX-DENY:CHILDREN-CHANGED:*
+# Deflake -- load start can be in same serialization as the load complete.
+# The load start is fired as a state-change:busy:true. However, if it occurs
+# in the same serialization as load complete, busy will already be false.
+# In any case, the load-complete event is the important event for Linux/ATK.
+@AURALINUX-DENY:STATE-CHANGE:BUSY:TRUE*
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/custom-select-expected-android-assist-data.txt b/content/test/data/accessibility/html/custom-select-expected-android-assist-data.txt
new file mode 100644
index 0000000..e4376926
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-expected-android-assist-data.txt
@@ -0,0 +1 @@
+test to see if this fails
diff --git a/content/test/data/accessibility/html/custom-select-expected-android-external.txt b/content/test/data/accessibility/html/custom-select-expected-android-external.txt
new file mode 100644
index 0000000..7f7e112
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-expected-android-external.txt
@@ -0,0 +1,4 @@
+WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++View text:"Currency for purchase" canOpenPopUp clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"]
+++++++View viewIdResName:"select-options" notVisibleToUser actions:[AX_FOCUS] bundle:[chromeRole="menuListPopup"]
diff --git a/content/test/data/accessibility/html/custom-select-expected-android.txt b/content/test/data/accessibility/html/custom-select-expected-android.txt
new file mode 100644
index 0000000..a5b2646
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-expected-android.txt
@@ -0,0 +1,10 @@
+android.webkit.WebView focusable
+++android.view.View
+++++android.view.View role_description='menu pop up button' clickable collapsed focusable focused name='Currency for purchase'
+++++++android.view.View invisible
+++++++++android.view.View invisible
+++++++++++android.view.View clickable focusable invisible name='EUR Euro'
+++++++++++android.view.View clickable focusable invisible name='GBP Great British Pound' item_index=1 row_index=1
+++++++++++android.view.View clickable focusable selected name='USD United States Dollar' item_index=2 row_index=2
+++++++++++android.view.View clickable focusable invisible name='JPY Japanese Yen' item_index=3 row_index=3
+++++++++++android.view.View clickable focusable invisible name='BTC Bitcoin' item_index=4 row_index=4
diff --git a/content/test/data/accessibility/html/custom-select-expected-auralinux.txt b/content/test/data/accessibility/html/custom-select-expected-auralinux.txt
new file mode 100644
index 0000000..d6f6bf1
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-expected-auralinux.txt
@@ -0,0 +1,45 @@
+[document web]
+++[section]
+++++[combo box] name='Currency for purchase' expandable haspopup:menu posinset:3 setsize:5
+++++++[menu] setsize:5
+++++++++[section]
+++++++++++[menu item] name='EUR Euro' selectable posinset:1 setsize:5
+++++++++++++[section]
+++++++++++++++[image] name=''
+++++++++++++++[section]
+++++++++++++++++[section]
+++++++++++++++++++[static] name='EUR'
+++++++++++++++++[section]
+++++++++++++++++++[static] name='Euro'
+++++++++++[menu item] name='GBP Great British Pound' selectable posinset:2 setsize:5
+++++++++++++[section]
+++++++++++++++[image] name=''
+++++++++++++++[section]
+++++++++++++++++[section]
+++++++++++++++++++[static] name='GBP'
+++++++++++++++++[section]
+++++++++++++++++++[static] name='Great British Pound'
+++++++++++[menu item] name='USD United States Dollar' selectable selected posinset:3 setsize:5
+++++++++++++[section]
+++++++++++++++[image] name=''
+++++++++++++++[section]
+++++++++++++++++[section]
+++++++++++++++++++[static] name='USD'
+++++++++++++++++[section]
+++++++++++++++++++[static] name='United States Dollar'
+++++++++++[menu item] name='JPY Japanese Yen' selectable posinset:4 setsize:5
+++++++++++++[section]
+++++++++++++++[image] name=''
+++++++++++++++[section]
+++++++++++++++++[section]
+++++++++++++++++++[static] name='JPY'
+++++++++++++++++[section]
+++++++++++++++++++[static] name='Japanese Yen'
+++++++++++[menu item] name='BTC Bitcoin' selectable posinset:5 setsize:5
+++++++++++++[section]
+++++++++++++++[image] name=''
+++++++++++++++[section]
+++++++++++++++++[section]
+++++++++++++++++++[static] name='BTC'
+++++++++++++++++[section]
+++++++++++++++++++[static] name='Bitcoin'
diff --git a/content/test/data/accessibility/html/custom-select-expected-mac.txt b/content/test/data/accessibility/html/custom-select-expected-mac.txt
new file mode 100644
index 0000000..e512239
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-expected-mac.txt
@@ -0,0 +1,10 @@
+AXWebArea AXRoleDescription='HTML content'
+++AXGroup AXRoleDescription='group'
+++++AXPopUpButton AXDescription='Currency for purchase' AXRoleDescription='pop up button' AXValue='USD United States Dollar $'
+++++++AXMenuItem AXRoleDescription='menu item' AXValue='USDUnited States Dollar'
+++++++++AXGroup AXRoleDescription='group'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXGroup AXRoleDescription='group'
+++++++++++++++AXStaticText AXRoleDescription='text' AXValue='USD'
+++++++++++++AXGroup AXRoleDescription='group'
+++++++++++++++AXStaticText AXRoleDescription='text' AXValue='United States Dollar'
diff --git a/content/test/data/accessibility/html/custom-select-expected-uia-win.txt b/content/test/data/accessibility/html/custom-select-expected-uia-win.txt
new file mode 100644
index 0000000..cd09681
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-expected-uia-win.txt
@@ -0,0 +1,3 @@
+Document
+++Group IsControlElement=false
+++++ComboBox Name='Currency for purchase' ExpandCollapse.ExpandCollapseState='Collapsed' Value.Value='USD United States Dollar $'
diff --git a/content/test/data/accessibility/html/custom-select-expected-win.txt b/content/test/data/accessibility/html/custom-select-expected-win.txt
new file mode 100644
index 0000000..2a84eec
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-expected-win.txt
@@ -0,0 +1,3 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_COMBOBOX name='Currency for purchase' value='USD United States Dollar $' COLLAPSED FOCUSABLE HASPOPUP haspopup:menu
diff --git a/content/test/data/accessibility/html/custom-select-open-expected-android-assist-data.txt b/content/test/data/accessibility/html/custom-select-open-expected-android-assist-data.txt
new file mode 100644
index 0000000..e4376926
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-open-expected-android-assist-data.txt
@@ -0,0 +1 @@
+test to see if this fails
diff --git a/content/test/data/accessibility/html/custom-select-open-expected-android-external.txt b/content/test/data/accessibility/html/custom-select-open-expected-android-external.txt
new file mode 100644
index 0000000..7f7e112
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-open-expected-android-external.txt
@@ -0,0 +1,4 @@
+WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++View text:"Currency for purchase" canOpenPopUp clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"]
+++++++View viewIdResName:"select-options" notVisibleToUser actions:[AX_FOCUS] bundle:[chromeRole="menuListPopup"]
diff --git a/content/test/data/accessibility/html/custom-select-open-expected-android.txt b/content/test/data/accessibility/html/custom-select-open-expected-android.txt
new file mode 100644
index 0000000..10b2262
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-open-expected-android.txt
@@ -0,0 +1,9 @@
+android.webkit.WebView focusable
+++android.view.View
+++++android.view.View role_description='menu pop up button' clickable expanded focusable name='Currency for purchase'
+++++++android.view.View
+++++++++android.view.View clickable focusable name='EUR Euro'
+++++++++android.view.View clickable focusable name='GBP Great British Pound' item_index=1 row_index=1
+++++++++android.view.View clickable focusable focused selected name='USD United States Dollar' item_index=2 row_index=2
+++++++++android.view.View clickable focusable name='JPY Japanese Yen' item_index=3 row_index=3
+++++++++android.view.View clickable focusable name='BTC Bitcoin' item_index=4 row_index=4
diff --git a/content/test/data/accessibility/html/custom-select-open-expected-auralinux.txt b/content/test/data/accessibility/html/custom-select-open-expected-auralinux.txt
new file mode 100644
index 0000000..2ce93fa
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-open-expected-auralinux.txt
@@ -0,0 +1,29 @@
+[document web]
+++[section]
+++++[combo box] name='Currency for purchase' expandable expanded haspopup:menu posinset:3 setsize:5
+++++++[menu] setsize:5
+++++++++[menu item] name='EUR Euro' selectable posinset:1 setsize:5
+++++++++++[section]
+++++++++++++[static] name='EUR'
+++++++++++[section]
+++++++++++++[static] name='Euro'
+++++++++[menu item] name='GBP Great British Pound' selectable posinset:2 setsize:5
+++++++++++[section]
+++++++++++++[static] name='GBP'
+++++++++++[section]
+++++++++++++[static] name='Great British Pound'
+++++++++[menu item] name='USD United States Dollar' selectable selected posinset:3 setsize:5
+++++++++++[section]
+++++++++++++[static] name='USD'
+++++++++++[section]
+++++++++++++[static] name='United States Dollar'
+++++++++[menu item] name='JPY Japanese Yen' selectable posinset:4 setsize:5
+++++++++++[section]
+++++++++++++[static] name='JPY'
+++++++++++[section]
+++++++++++++[static] name='Japanese Yen'
+++++++++[menu item] name='BTC Bitcoin' selectable posinset:5 setsize:5
+++++++++++[section]
+++++++++++++[static] name='BTC'
+++++++++++[section]
+++++++++++++[static] name='Bitcoin'
diff --git a/content/test/data/accessibility/html/custom-select-open-expected-mac.txt b/content/test/data/accessibility/html/custom-select-open-expected-mac.txt
new file mode 100644
index 0000000..fe251a64
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-open-expected-mac.txt
@@ -0,0 +1,29 @@
+AXWebArea AXRoleDescription='HTML content'
+++AXGroup AXRoleDescription='group'
+++++AXPopUpButton AXDescription='Currency for purchase' AXRoleDescription='pop up button' AXValue='USD United States Dollar $'
+++++++AXMenu AXRoleDescription='menu'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='EUREuro'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='EUR'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='Euro'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='GBPGreat British Pound'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='GBP'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='Great British Pound'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='USDUnited States Dollar'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='USD'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='United States Dollar'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='JPYJapanese Yen'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='JPY'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='Japanese Yen'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='BTCBitcoin'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='BTC'
+++++++++++AXGroup AXRoleDescription='group'
+++++++++++++AXStaticText AXRoleDescription='text' AXValue='Bitcoin'
diff --git a/content/test/data/accessibility/html/custom-select-open-expected-uia-win.txt b/content/test/data/accessibility/html/custom-select-open-expected-uia-win.txt
new file mode 100644
index 0000000..c806e4d
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-open-expected-uia-win.txt
@@ -0,0 +1,29 @@
+Document
+++Group IsControlElement=false
+++++ComboBox Name='Currency for purchase' ExpandCollapse.ExpandCollapseState='Expanded' Value.Value='USD United States Dollar $'
+++++++List IsControlElement=false Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false
+++++++++ListItem Name='EUR Euro' SelectionItem.IsSelected=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='EUR' IsControlElement=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='Euro' IsControlElement=false
+++++++++ListItem Name='GBP Great British Pound' SelectionItem.IsSelected=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='GBP' IsControlElement=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='Great British Pound' IsControlElement=false
+++++++++ListItem Name='USD United States Dollar' SelectionItem.IsSelected=true
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='USD' IsControlElement=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='United States Dollar' IsControlElement=false
+++++++++ListItem Name='JPY Japanese Yen' SelectionItem.IsSelected=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='JPY' IsControlElement=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='Japanese Yen' IsControlElement=false
+++++++++ListItem Name='BTC Bitcoin' SelectionItem.IsSelected=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='BTC' IsControlElement=false
+++++++++++Group IsControlElement=false
+++++++++++++Text Name='Bitcoin' IsControlElement=false
diff --git a/content/test/data/accessibility/html/custom-select-open-expected-win.txt b/content/test/data/accessibility/html/custom-select-open-expected-win.txt
new file mode 100644
index 0000000..471fb4f
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-open-expected-win.txt
@@ -0,0 +1,29 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_COMBOBOX name='Currency for purchase' value='USD United States Dollar $' EXPANDED FOCUSABLE HASPOPUP haspopup:menu
+++++++ROLE_SYSTEM_LIST ispopup:auto
+++++++++ROLE_SYSTEM_LISTITEM name='EUR Euro' FOCUSABLE SELECTABLE
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='EUR'
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='Euro'
+++++++++ROLE_SYSTEM_LISTITEM name='GBP Great British Pound' FOCUSABLE SELECTABLE
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='GBP'
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='Great British Pound'
+++++++++ROLE_SYSTEM_LISTITEM name='USD United States Dollar' SELECTED FOCUSABLE SELECTABLE
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='USD'
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='United States Dollar'
+++++++++ROLE_SYSTEM_LISTITEM name='JPY Japanese Yen' FOCUSABLE SELECTABLE
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='JPY'
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='Japanese Yen'
+++++++++ROLE_SYSTEM_LISTITEM name='BTC Bitcoin' FOCUSABLE SELECTABLE
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='BTC'
+++++++++++IA2_ROLE_SECTION
+++++++++++++ROLE_SYSTEM_STATICTEXT name='Bitcoin'
diff --git a/content/test/data/accessibility/html/custom-select-open.html b/content/test/data/accessibility/html/custom-select-open.html
index c01689d..1f12614 100644
--- a/content/test/data/accessibility/html/custom-select-open.html
+++ b/content/test/data/accessibility/html/custom-select-open.html
@@ -5,6 +5,20 @@
 @BLINK-ALLOW:posInSet*
 @BLINK-ALLOW:haspopup*
 @BLINK-ALLOW:expanded
+@MAC-ALLOW:AXRoleDescription=*
+@WIN-ALLOW:HASPOPUP
+@WIN-ALLOW:haspopup*
+@WIN-ALLOW:ispopup*
+@WIN-ALLOW:readonly*
+@WIN-ALLOW:MULTISELECTABLE
+@WIN-ALLOW:EXTSELECTABLE
+@WIN-ALLOW:SELECT*
+@AURALINUX-ALLOW:haspopup*
+@AURALINUX-ALLOW:isspopup*
+@AURALINUX-ALLOW:posinset*
+@AURALINUX-ALLOW:setsize*
+@AURALINUX-ALLOW:expand*
+@AURALINUX-ALLOW:required
 @DEFAULT-ACTION-ON:Currency for purchase
 -->
 <style>
diff --git a/content/test/data/accessibility/html/custom-select-simple-expected-android-assist-data.txt b/content/test/data/accessibility/html/custom-select-simple-expected-android-assist-data.txt
new file mode 100644
index 0000000..e4376926
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-expected-android-assist-data.txt
@@ -0,0 +1 @@
+test to see if this fails
diff --git a/content/test/data/accessibility/html/custom-select-simple-expected-android-external.txt b/content/test/data/accessibility/html/custom-select-simple-expected-android-external.txt
new file mode 100644
index 0000000..ed592033
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-expected-android-external.txt
@@ -0,0 +1,7 @@
+WebView focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++View text:"Fruit" canOpenPopUp clickable focusable focused actions:[CLEAR_FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"]
+++++++View viewIdResName:"select-options" notVisibleToUser actions:[AX_FOCUS] bundle:[chromeRole="menuListPopup"]
+++++++++View text:"Apple" clickable focusable selected actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"Orange" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"Banana" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/custom-select-simple-expected-android.txt b/content/test/data/accessibility/html/custom-select-simple-expected-android.txt
new file mode 100644
index 0000000..0808ae34
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-expected-android.txt
@@ -0,0 +1,7 @@
+android.webkit.WebView focusable
+++android.view.View
+++++android.view.View role_description='menu pop up button' clickable collapsed focusable focused name='Fruit'
+++++++android.view.View invisible
+++++++++android.view.View clickable focusable selected name='Apple'
+++++++++android.view.View clickable focusable invisible name='Orange' item_index=1 row_index=1
+++++++++android.view.View clickable focusable invisible name='Banana' item_index=2 row_index=2
diff --git a/content/test/data/accessibility/html/custom-select-simple-expected-auralinux.txt b/content/test/data/accessibility/html/custom-select-simple-expected-auralinux.txt
new file mode 100644
index 0000000..2a97e2f
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-expected-auralinux.txt
@@ -0,0 +1,7 @@
+[document web]
+++[section]
+++++[combo box] name='Fruit' expandable haspopup:menu posinset:1 setsize:3
+++++++[menu] setsize:3
+++++++++[menu item] name='Apple' selectable selected posinset:1 setsize:3
+++++++++[menu item] name='Orange' selectable posinset:2 setsize:3
+++++++++[menu item] name='Banana' selectable posinset:3 setsize:3
diff --git a/content/test/data/accessibility/html/custom-select-simple-expected-mac.txt b/content/test/data/accessibility/html/custom-select-simple-expected-mac.txt
new file mode 100644
index 0000000..0325c3c
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-expected-mac.txt
@@ -0,0 +1,4 @@
+AXWebArea AXRoleDescription='HTML content'
+++AXGroup AXRoleDescription='group'
+++++AXPopUpButton AXDescription='Fruit' AXRoleDescription='pop up button' AXValue='Apple'
+++++++AXMenuItem AXRoleDescription='menu item' AXValue='Apple'
diff --git a/content/test/data/accessibility/html/custom-select-simple-expected-uia-win.txt b/content/test/data/accessibility/html/custom-select-simple-expected-uia-win.txt
new file mode 100644
index 0000000..92897b2
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-expected-uia-win.txt
@@ -0,0 +1,3 @@
+Document
+++Group IsControlElement=false
+++++ComboBox Name='Fruit' ExpandCollapse.ExpandCollapseState='Collapsed' Value.Value='Apple'
diff --git a/content/test/data/accessibility/html/custom-select-simple-expected-win.txt b/content/test/data/accessibility/html/custom-select-simple-expected-win.txt
new file mode 100644
index 0000000..5bba709
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-expected-win.txt
@@ -0,0 +1,3 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_COMBOBOX name='Fruit' value='Apple' COLLAPSED FOCUSABLE HASPOPUP haspopup:menu
diff --git a/content/test/data/accessibility/html/custom-select-simple-open-expected-android-assist-data.txt b/content/test/data/accessibility/html/custom-select-simple-open-expected-android-assist-data.txt
new file mode 100644
index 0000000..e4376926
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-open-expected-android-assist-data.txt
@@ -0,0 +1 @@
+test to see if this fails
diff --git a/content/test/data/accessibility/html/custom-select-simple-open-expected-android-external.txt b/content/test/data/accessibility/html/custom-select-simple-open-expected-android-external.txt
new file mode 100644
index 0000000..ed592033
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-open-expected-android-external.txt
@@ -0,0 +1,7 @@
+WebView focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++View text:"Fruit" canOpenPopUp clickable focusable focused actions:[CLEAR_FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"]
+++++++View viewIdResName:"select-options" notVisibleToUser actions:[AX_FOCUS] bundle:[chromeRole="menuListPopup"]
+++++++++View text:"Apple" clickable focusable selected actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"Orange" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"Banana" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/custom-select-simple-open-expected-android.txt b/content/test/data/accessibility/html/custom-select-simple-open-expected-android.txt
new file mode 100644
index 0000000..8f4acaf
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-open-expected-android.txt
@@ -0,0 +1,7 @@
+android.webkit.WebView focusable
+++android.view.View
+++++android.view.View role_description='menu pop up button' clickable expanded focusable name='Fruit'
+++++++android.view.View
+++++++++android.view.View clickable focusable focused selected name='Apple'
+++++++++android.view.View clickable focusable name='Orange' item_index=1 row_index=1
+++++++++android.view.View clickable focusable name='Banana' item_index=2 row_index=2
diff --git a/content/test/data/accessibility/html/custom-select-simple-open-expected-auralinux.txt b/content/test/data/accessibility/html/custom-select-simple-open-expected-auralinux.txt
new file mode 100644
index 0000000..5e24c1a
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-open-expected-auralinux.txt
@@ -0,0 +1,7 @@
+[document web]
+++[section]
+++++[combo box] name='Fruit' expandable expanded haspopup:menu posinset:1 setsize:3
+++++++[menu] setsize:3
+++++++++[menu item] name='Apple' selectable selected posinset:1 setsize:3
+++++++++[menu item] name='Orange' selectable posinset:2 setsize:3
+++++++++[menu item] name='Banana' selectable posinset:3 setsize:3
diff --git a/content/test/data/accessibility/html/custom-select-simple-open-expected-mac.txt b/content/test/data/accessibility/html/custom-select-simple-open-expected-mac.txt
new file mode 100644
index 0000000..9a2a4d5
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-open-expected-mac.txt
@@ -0,0 +1,7 @@
+AXWebArea AXRoleDescription='HTML content'
+++AXGroup AXRoleDescription='group'
+++++AXPopUpButton AXDescription='Fruit' AXRoleDescription='pop up button' AXValue='Apple'
+++++++AXMenu AXRoleDescription='menu'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Apple'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Orange'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Banana'
diff --git a/content/test/data/accessibility/html/custom-select-simple-open-expected-uia-win.txt b/content/test/data/accessibility/html/custom-select-simple-open-expected-uia-win.txt
new file mode 100644
index 0000000..775b4c0a
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-open-expected-uia-win.txt
@@ -0,0 +1,7 @@
+Document
+++Group IsControlElement=false
+++++ComboBox Name='Fruit' ExpandCollapse.ExpandCollapseState='Expanded' Value.Value='Apple'
+++++++List IsControlElement=false Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false
+++++++++ListItem Name='Apple' SelectionItem.IsSelected=true
+++++++++ListItem Name='Orange' SelectionItem.IsSelected=false
+++++++++ListItem Name='Banana' SelectionItem.IsSelected=false
diff --git a/content/test/data/accessibility/html/custom-select-simple-open-expected-win.txt b/content/test/data/accessibility/html/custom-select-simple-open-expected-win.txt
new file mode 100644
index 0000000..8b03a1a0
--- /dev/null
+++ b/content/test/data/accessibility/html/custom-select-simple-open-expected-win.txt
@@ -0,0 +1,7 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_COMBOBOX name='Fruit' value='Apple' EXPANDED FOCUSABLE HASPOPUP haspopup:menu
+++++++ROLE_SYSTEM_LIST ispopup:auto
+++++++++ROLE_SYSTEM_LISTITEM name='Apple' SELECTED FOCUSABLE SELECTABLE
+++++++++ROLE_SYSTEM_LISTITEM name='Orange' FOCUSABLE SELECTABLE
+++++++++ROLE_SYSTEM_LISTITEM name='Banana' FOCUSABLE SELECTABLE
diff --git a/content/test/data/accessibility/html/custom-select-simple-open.html b/content/test/data/accessibility/html/custom-select-simple-open.html
index c56586b..c8d4bac 100644
--- a/content/test/data/accessibility/html/custom-select-simple-open.html
+++ b/content/test/data/accessibility/html/custom-select-simple-open.html
@@ -7,6 +7,20 @@
 @BLINK-ALLOW:expanded
 @BLINK-ALLOW:htmlTag*
 @BLINK-ALLOW:class*
+@MAC-ALLOW:AXRoleDescription=*
+@WIN-ALLOW:HASPOPUP
+@WIN-ALLOW:haspopup*
+@WIN-ALLOW:ispopup*
+@WIN-ALLOW:readonly*
+@WIN-ALLOW:MULTISELECTABLE
+@WIN-ALLOW:EXTSELECTABLE
+@WIN-ALLOW:SELECT*
+@AURALINUX-ALLOW:haspopup*
+@AURALINUX-ALLOW:isspopup*
+@AURALINUX-ALLOW:posinset*
+@AURALINUX-ALLOW:setsize*
+@AURALINUX-ALLOW:expand*
+@AURALINUX-ALLOW:required
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/custom-select-simple.html b/content/test/data/accessibility/html/custom-select-simple.html
index b43e94ee..291d2807 100644
--- a/content/test/data/accessibility/html/custom-select-simple.html
+++ b/content/test/data/accessibility/html/custom-select-simple.html
@@ -6,6 +6,20 @@
 @BLINK-ALLOW:expanded
 @BLINK-ALLOW:htmlTag*
 @BLINK-ALLOW:class*
+@MAC-ALLOW:AXRoleDescription=*
+@WIN-ALLOW:HASPOPUP
+@WIN-ALLOW:haspopup*
+@WIN-ALLOW:ispopup*
+@WIN-ALLOW:readonly*
+@WIN-ALLOW:MULTISELECTABLE
+@WIN-ALLOW:EXTSELECTABLE
+@WIN-ALLOW:SELECT*
+@AURALINUX-ALLOW:haspopup*
+@AURALINUX-ALLOW:isspopup*
+@AURALINUX-ALLOW:posinset*
+@AURALINUX-ALLOW:setsize*
+@AURALINUX-ALLOW:expand*
+@AURALINUX-ALLOW:required
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/custom-select.html b/content/test/data/accessibility/html/custom-select.html
index 769df96..92aa942d 100644
--- a/content/test/data/accessibility/html/custom-select.html
+++ b/content/test/data/accessibility/html/custom-select.html
@@ -7,6 +7,20 @@
 @BLINK-ALLOW:expanded
 @BLINK-ALLOW:htmlTag*
 @BLINK-ALLOW:class*
+@MAC-ALLOW:AXRoleDescription=*
+@WIN-ALLOW:HASPOPUP
+@WIN-ALLOW:haspopup*
+@WIN-ALLOW:ispopup*
+@WIN-ALLOW:readonly*
+@WIN-ALLOW:MULTISELECTABLE
+@WIN-ALLOW:EXTSELECTABLE
+@WIN-ALLOW:SELECT*
+@AURALINUX-ALLOW:haspopup*
+@AURALINUX-ALLOW:isspopup*
+@AURALINUX-ALLOW:posinset*
+@AURALINUX-ALLOW:setsize*
+@AURALINUX-ALLOW:expand*
+@AURALINUX-ALLOW:required
 -->
 <style>
 /* Enter into custom mode */
diff --git a/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected-expected-blink.txt b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected-expected-blink.txt
index 145f200..1172a7f0 100644
--- a/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected-expected-blink.txt
+++ b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected-expected-blink.txt
@@ -1,4 +1,4 @@
-rootWebArea
+rootWebArea name='done'
 ++genericContainer ignored
 ++++genericContainer ignored
 ++++++sectionWithoutName
diff --git a/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected.html b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected.html
index e7fa740..53ad52a 100644
--- a/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected.html
+++ b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected.html
@@ -3,7 +3,7 @@
 # filled, but does. This only occurs in the test, not in a real browser.
 # For now, don't check invalid state in this test.
 @BLINK-DENY:invalidState*
-@WAIT-FOR:ready
+@WAIT-FOR:done
 -->
 <!-- Ensure that alert is removed after form is made valid-->
 <!DOCTYPE html>
@@ -17,5 +17,6 @@
   setTimeout(() => {
     in1.blur();
     in1.value = 'ready';
+    document.title = 'done';
   }, 100);
 </script>
diff --git a/content/test/data/accessibility/html/iframe-aria-hidden.html b/content/test/data/accessibility/html/iframe-aria-hidden.html
index 1152990..78c5ecb 100644
--- a/content/test/data/accessibility/html/iframe-aria-hidden.html
+++ b/content/test/data/accessibility/html/iframe-aria-hidden.html
@@ -1,5 +1,7 @@
 <!--
 @WIN-ALLOW:ia2_hypertext=*
+@NO-LOAD-EXPECTED:frame/empty.html
+@NO-LOAD-EXPECTED:frame/empty.html#2
 -->
 <iframe tabindex="0" aria-hidden="true" src="frame/empty.html"
         style="position: absolute; width: 9em; height: 9em; top: -99em;">
diff --git a/content/test/data/accessibility/html/open-modal.html b/content/test/data/accessibility/html/open-modal.html
index b5cc9fe3..bec2da9 100644
--- a/content/test/data/accessibility/html/open-modal.html
+++ b/content/test/data/accessibility/html/open-modal.html
@@ -20,7 +20,7 @@
 <script>
   function open_modal() {
     document.querySelector("dialog").showModal();
-    return "dialog";
+    return "Some Text";
   }
   function remove_span() {
     // Cause the root to be updated.
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android-assist-data.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android-assist-data.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android-assist-data.txt
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android-external.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android-external.txt
new file mode 100644
index 0000000..17f77ec
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android-external.txt
@@ -0,0 +1,13 @@
+WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++View text:"Transformer" viewIdResName:"menulist" canOpenPopUp clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"]
+++++++View viewIdResName:"select-options" notVisibleToUser actions:[AX_FOCUS] bundle:[chromeRole="menuListPopup"]
+++++++++View text:"Random Transformer" clickable focusable selected actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"group 1" notVisibleToUser actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="group", clickableScore="100"]
+++++++++++View text:"Optimus Prime" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Bumblebee" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Jazz" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"group 2" notVisibleToUser actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="group", clickableScore="100"]
+++++++++++View text:"Megatron" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Starscream" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Brawl" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android.txt
new file mode 100644
index 0000000..3d962e5
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-android.txt
@@ -0,0 +1,14 @@
+android.webkit.WebView focusable
+++android.view.View
+++++android.view.View role_description='menu pop up button' clickable expanded focusable name='Transformer'
+++++++android.view.View
+++++++++android.view.View clickable focusable focused selected name='Random Transformer'
+++++++++android.view.View name='group 1'
+++++++++++android.view.View clickable focusable name='Optimus Prime' item_index=1 row_index=1
+++++++++++android.view.View clickable focusable name='Bumblebee' item_index=2 row_index=2
+++++++++++android.view.View clickable focusable name='Jazz' item_index=3 row_index=3
+++++++++android.view.View name='group 2'
+++++++++++android.view.View clickable focusable name='Megatron' item_index=4 row_index=4
+++++++++++android.view.View clickable focusable name='Starscream' item_index=5 row_index=5
+++++++++++android.view.View clickable focusable name='Brawl' item_index=6 row_index=6
+++++++android.view.View
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-auralinux.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-auralinux.txt
new file mode 100644
index 0000000..34b92cc
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-auralinux.txt
@@ -0,0 +1,14 @@
+[document web] enabled
+++[section] enabled
+++++[combo box] name='Transformer' enabled has-popup haspopup:menu posinset:1 setsize:7
+++++++[menu] enabled setsize:7
+++++++++[menu item] name='Random Transformer' enabled selectable selected posinset:1 setsize:7
+++++++++[panel] name='group 1' enabled
+++++++++++[menu item] name='Optimus Prime' enabled selectable posinset:2 setsize:7
+++++++++++[menu item] name='Bumblebee' enabled selectable posinset:3 setsize:7
+++++++++++[menu item] name='Jazz' enabled selectable posinset:4 setsize:7
+++++++++[panel] name='group 2' enabled
+++++++++++[menu item] name='Megatron' enabled selectable posinset:5 setsize:7
+++++++++++[menu item] name='Starscream' enabled selectable posinset:6 setsize:7
+++++++++++[menu item] name='Brawl' enabled selectable posinset:7 setsize:7
+++++++[menu] enabled setsize:7
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-blink.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-blink.txt
new file mode 100644
index 0000000..a3dec72
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-blink.txt
@@ -0,0 +1,17 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer
+++++++comboBoxSelect name='Transformer' value='Random Transformer' setSize=7 posInSet=1
+++++++++menuListPopup activedescendantId=menuListOption setSize=7 ispopup=auto
+++++++++++menuListOption name='Random Transformer' setSize=7 posInSet=1 selected=true
+++++++++++group name='group 1'
+++++++++++++genericContainer ignored
+++++++++++++++menuListOption name='Optimus Prime' setSize=7 posInSet=2 selected=false
+++++++++++++++menuListOption name='Bumblebee' setSize=7 posInSet=3 selected=false
+++++++++++++++menuListOption name='Jazz' setSize=7 posInSet=4 selected=false
+++++++++++group name='group 2'
+++++++++++++genericContainer ignored
+++++++++++++++menuListOption name='Megatron' setSize=7 posInSet=5 selected=false
+++++++++++++++menuListOption name='Starscream' setSize=7 posInSet=6 selected=false
+++++++++++++++menuListOption name='Brawl' setSize=7 posInSet=7 selected=false
+++++++++menuListPopup activedescendantId=menuListOption setSize=7 ispopup=auto
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-mac.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-mac.txt
new file mode 100644
index 0000000..869a273
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-mac.txt
@@ -0,0 +1,13 @@
+AXWebArea AXRoleDescription='HTML content'
+++AXGroup AXRoleDescription='group'
+++++AXPopUpButton AXDescription='Transformer' AXRoleDescription='pop up button' AXValue='Random Transformer'
+++++++AXMenu AXRoleDescription='menu'
+++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Random Transformer'
+++++++++AXGroup AXSubrole=AXApplicationGroup AXDescription='group 1' AXRoleDescription='group'
+++++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Optimus Prime'
+++++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Bumblebee'
+++++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Jazz'
+++++++++AXGroup AXSubrole=AXApplicationGroup AXDescription='group 2' AXRoleDescription='group'
+++++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Megatron'
+++++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Starscream'
+++++++++++AXMenuItem AXRoleDescription='menu item' AXValue='Brawl'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-uia-win.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-uia-win.txt
new file mode 100644
index 0000000..32c42c4d
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-uia-win.txt
@@ -0,0 +1,14 @@
+#<skip -- sometimes showing up empty -- crbug.com/364508153>
+Document Value.IsReadOnly=true
+++Group IsControlElement=false
+++++ComboBox Name='Transformer' ExpandCollapse.ExpandCollapseState='Expanded' Value.IsReadOnly=false Value.Value='Random Transformer'
+++++++List IsControlElement=false Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false Value.IsReadOnly=false
+++++++++ListItem Name='Random Transformer' SelectionItem.IsSelected=true
+++++++++Group Name='group 1'
+++++++++++ListItem Name='Optimus Prime' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Bumblebee' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Jazz' SelectionItem.IsSelected=false
+++++++++Group Name='group 2'
+++++++++++ListItem Name='Megatron' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Starscream' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Brawl' SelectionItem.IsSelected=false
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist-expected-win.txt b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-win.txt
new file mode 100644
index 0000000..d0c0094
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist-expected-win.txt
@@ -0,0 +1,14 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_COMBOBOX name='Transformer' value='Random Transformer' EXPANDED FOCUSABLE HASPOPUP haspopup:menu
+++++++ROLE_SYSTEM_LIST ispopup:auto
+++++++++ROLE_SYSTEM_LISTITEM name='Random Transformer' SELECTED FOCUSABLE SELECTABLE
+++++++++ROLE_SYSTEM_GROUPING name='group 1'
+++++++++++ROLE_SYSTEM_LISTITEM name='Optimus Prime' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Bumblebee' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Jazz' FOCUSABLE SELECTABLE
+++++++++ROLE_SYSTEM_GROUPING name='group 2'
+++++++++++ROLE_SYSTEM_LISTITEM name='Megatron' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Starscream' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Brawl' FOCUSABLE SELECTABLE
+++++++ROLE_SYSTEM_LIST ispopup:auto
diff --git a/content/test/data/accessibility/html/optgroup-custom-menulist.html b/content/test/data/accessibility/html/optgroup-custom-menulist.html
new file mode 100644
index 0000000..36f6350
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-custom-menulist.html
@@ -0,0 +1,37 @@
+<!--
+@MAC-ALLOW:AXRoleDescription
+@WIN-ALLOW:xml-roles*
+@WIN-ALLOW:IA2_STATE_VERTICAL
+@WIN-ALLOW:SELECTABLE
+@WIN-ALLOW:*popup*
+@UIA-WIN-ALLOW:Value.IsReadOnly*
+@BLINK-ALLOW:setSize*
+@BLINK-ALLOW:posInSet*
+@AURALINUX-ALLOW:xml-roles*
+@AURALINUX-ALLOW:posinset*
+@AURALINUX-ALLOW:setsize*
+@AURALINUX-ALLOW:enabled
+@AURALINUX-ALLOW:*popup*
+@DEFAULT-ACTION-ON:Transformer
+-->
+<!DOCTYPE html>
+<html>
+<style>
+  select { appearance: base-select; }
+</style>
+<body>
+<select id="menulist" aria-label="Transformer">
+  <option>Random Transformer</option>
+  <optgroup label="group 1">
+    <option>Optimus Prime</option>
+    <option>Bumblebee</option>
+    <option>Jazz</option>
+  </optgroup>
+  <optgroup label="group 2">
+    <option>Megatron</option>
+    <option>Starscream</option>
+    <option>Brawl</option>
+  </optgroup>
+</select>
+</body>
+</html>
diff --git a/content/test/data/accessibility/html/optgroup-expected-auralinux.txt b/content/test/data/accessibility/html/optgroup-expected-auralinux.txt
index fe652f7..27e050f3 100644
--- a/content/test/data/accessibility/html/optgroup-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/optgroup-expected-auralinux.txt
@@ -11,7 +11,7 @@
 ++++++++[list item] name='Two' posinset:6 setsize:8
 ++++++++[list item] name='Three' posinset:7 setsize:8
 ++++++++[list item] name='Four' posinset:8 setsize:8
-++++[combo box] enabled posinset:1 setsize:7
+++++[combo box] enabled has-popup haspopup:menu posinset:1 setsize:7
 ++++++[menu] enabled setsize:7
 ++++++++[menu item] name='Random Transformer' enabled selectable selected posinset:1 setsize:7
 ++++++++[panel] name='group 1' enabled
diff --git a/content/test/data/accessibility/html/optgroup-expected-win.txt b/content/test/data/accessibility/html/optgroup-expected-win.txt
index 71d2359..d242994 100644
--- a/content/test/data/accessibility/html/optgroup-expected-win.txt
+++ b/content/test/data/accessibility/html/optgroup-expected-win.txt
@@ -11,4 +11,4 @@
 ++++++++ROLE_SYSTEM_LISTITEM name='Two' UNAVAILABLE
 ++++++++ROLE_SYSTEM_LISTITEM name='Three' UNAVAILABLE
 ++++++++ROLE_SYSTEM_LISTITEM name='Four' UNAVAILABLE
-++++ROLE_SYSTEM_COMBOBOX value='Random Transformer' COLLAPSED FOCUSABLE HASPOPUP
+++++ROLE_SYSTEM_COMBOBOX value='Random Transformer' COLLAPSED FOCUSABLE HASPOPUP haspopup:menu
diff --git a/content/test/data/accessibility/html/optgroup-menulist-expected-android-assist-data.txt b/content/test/data/accessibility/html/optgroup-menulist-expected-android-assist-data.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist-expected-android-assist-data.txt
diff --git a/content/test/data/accessibility/html/optgroup-menulist-expected-android-external.txt b/content/test/data/accessibility/html/optgroup-menulist-expected-android-external.txt
new file mode 100644
index 0000000..17f77ec
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist-expected-android-external.txt
@@ -0,0 +1,13 @@
+WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++View text:"Transformer" viewIdResName:"menulist" canOpenPopUp clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"]
+++++++View viewIdResName:"select-options" notVisibleToUser actions:[AX_FOCUS] bundle:[chromeRole="menuListPopup"]
+++++++++View text:"Random Transformer" clickable focusable selected actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"group 1" notVisibleToUser actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="group", clickableScore="100"]
+++++++++++View text:"Optimus Prime" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Bumblebee" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Jazz" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++View text:"group 2" notVisibleToUser actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="group", clickableScore="100"]
+++++++++++View text:"Megatron" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Starscream" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
+++++++++++View text:"Brawl" clickable focusable notVisibleToUser actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/optgroup-menulist-expected-android.txt b/content/test/data/accessibility/html/optgroup-menulist-expected-android.txt
new file mode 100644
index 0000000..63572471
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist-expected-android.txt
@@ -0,0 +1,13 @@
+android.webkit.WebView focusable
+++android.view.View
+++++android.view.View role_description='menu pop up button' clickable expanded focusable name='Transformer'
+++++++android.view.View
+++++++++android.view.View clickable focusable focused selected name='Random Transformer'
+++++++++android.view.View name='group 1'
+++++++++++android.view.View clickable focusable name='Optimus Prime' item_index=1 row_index=1
+++++++++++android.view.View clickable focusable name='Bumblebee' item_index=2 row_index=2
+++++++++++android.view.View clickable focusable name='Jazz' item_index=3 row_index=3
+++++++++android.view.View name='group 2'
+++++++++++android.view.View clickable focusable name='Megatron' item_index=4 row_index=4
+++++++++++android.view.View clickable focusable name='Starscream' item_index=5 row_index=5
+++++++++++android.view.View clickable focusable name='Brawl' item_index=6 row_index=6
diff --git a/content/test/data/accessibility/html/optgroup-menulist-expected-auralinux.txt b/content/test/data/accessibility/html/optgroup-menulist-expected-auralinux.txt
new file mode 100644
index 0000000..d69ab99
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist-expected-auralinux.txt
@@ -0,0 +1,13 @@
+[document web] enabled
+++[section] enabled
+++++[combo box] name='Transformer' enabled posinset:1 setsize:7
+++++++[menu] enabled setsize:7
+++++++++[menu item] name='Random Transformer' enabled selectable selected posinset:1 setsize:7
+++++++++[panel] name='group 1' enabled
+++++++++++[menu item] name='Optimus Prime' enabled selectable posinset:2 setsize:7
+++++++++++[menu item] name='Bumblebee' enabled selectable posinset:3 setsize:7
+++++++++++[menu item] name='Jazz' enabled selectable posinset:4 setsize:7
+++++++++[panel] name='group 2' enabled
+++++++++++[menu item] name='Megatron' enabled selectable posinset:5 setsize:7
+++++++++++[menu item] name='Starscream' enabled selectable posinset:6 setsize:7
+++++++++++[menu item] name='Brawl' enabled selectable posinset:7 setsize:7
diff --git a/content/test/data/accessibility/html/optgroup-menulist-expected-blink.txt b/content/test/data/accessibility/html/optgroup-menulist-expected-blink.txt
new file mode 100644
index 0000000..c4af927b
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist-expected-blink.txt
@@ -0,0 +1,16 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer
+++++++comboBoxSelect name='Transformer' value='Random Transformer' setSize=7 posInSet=1
+++++++++menuListPopup activedescendantId=menuListOption setSize=7 ispopup=auto
+++++++++++menuListOption name='Random Transformer' setSize=7 posInSet=1 selected=true
+++++++++++group name='group 1'
+++++++++++++genericContainer ignored
+++++++++++++++menuListOption name='Optimus Prime' setSize=7 posInSet=2 selected=false
+++++++++++++++menuListOption name='Bumblebee' setSize=7 posInSet=3 selected=false
+++++++++++++++menuListOption name='Jazz' setSize=7 posInSet=4 selected=false
+++++++++++group name='group 2'
+++++++++++++genericContainer ignored
+++++++++++++++menuListOption name='Megatron' setSize=7 posInSet=5 selected=false
+++++++++++++++menuListOption name='Starscream' setSize=7 posInSet=6 selected=false
+++++++++++++++menuListOption name='Brawl' setSize=7 posInSet=7 selected=false
diff --git a/content/test/data/accessibility/html/optgroup-menulist-expected-uia-win.txt b/content/test/data/accessibility/html/optgroup-menulist-expected-uia-win.txt
new file mode 100644
index 0000000..32c42c4d
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist-expected-uia-win.txt
@@ -0,0 +1,14 @@
+#<skip -- sometimes showing up empty -- crbug.com/364508153>
+Document Value.IsReadOnly=true
+++Group IsControlElement=false
+++++ComboBox Name='Transformer' ExpandCollapse.ExpandCollapseState='Expanded' Value.IsReadOnly=false Value.Value='Random Transformer'
+++++++List IsControlElement=false Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false Value.IsReadOnly=false
+++++++++ListItem Name='Random Transformer' SelectionItem.IsSelected=true
+++++++++Group Name='group 1'
+++++++++++ListItem Name='Optimus Prime' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Bumblebee' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Jazz' SelectionItem.IsSelected=false
+++++++++Group Name='group 2'
+++++++++++ListItem Name='Megatron' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Starscream' SelectionItem.IsSelected=false
+++++++++++ListItem Name='Brawl' SelectionItem.IsSelected=false
diff --git a/content/test/data/accessibility/html/optgroup-menulist-expected-win.txt b/content/test/data/accessibility/html/optgroup-menulist-expected-win.txt
new file mode 100644
index 0000000..e18df389
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist-expected-win.txt
@@ -0,0 +1,13 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_COMBOBOX name='Transformer' value='Random Transformer' EXPANDED FOCUSABLE HASPOPUP
+++++++ROLE_SYSTEM_LIST ispopup:auto
+++++++++ROLE_SYSTEM_LISTITEM name='Random Transformer' SELECTED FOCUSABLE SELECTABLE
+++++++++ROLE_SYSTEM_GROUPING name='group 1'
+++++++++++ROLE_SYSTEM_LISTITEM name='Optimus Prime' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Bumblebee' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Jazz' FOCUSABLE SELECTABLE
+++++++++ROLE_SYSTEM_GROUPING name='group 2'
+++++++++++ROLE_SYSTEM_LISTITEM name='Megatron' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Starscream' FOCUSABLE SELECTABLE
+++++++++++ROLE_SYSTEM_LISTITEM name='Brawl' FOCUSABLE SELECTABLE
diff --git a/content/test/data/accessibility/html/optgroup-menulist.html b/content/test/data/accessibility/html/optgroup-menulist.html
new file mode 100644
index 0000000..81cb590
--- /dev/null
+++ b/content/test/data/accessibility/html/optgroup-menulist.html
@@ -0,0 +1,32 @@
+<!--
+@MAC-ALLOW:AXRoleDescription
+@WIN-ALLOW:xml-roles*
+@WIN-ALLOW:IA2_STATE_VERTICAL
+@WIN-ALLOW:SELECTABLE
+@UIA-WIN-ALLOW:Value.IsReadOnly*
+@BLINK-ALLOW:setSize*
+@BLINK-ALLOW:posInSet*
+@AURALINUX-ALLOW:xml-roles*
+@AURALINUX-ALLOW:posinset*
+@AURALINUX-ALLOW:setsize*
+@AURALINUX-ALLOW:enabled
+@DEFAULT-ACTION-ON:Transformer
+-->
+<!DOCTYPE html>
+<html>
+<body>
+<select id="menulist" aria-label="Transformer">
+  <option>Random Transformer</option>
+  <optgroup label="group 1">
+    <option>Optimus Prime</option>
+    <option>Bumblebee</option>
+    <option>Jazz</option>
+  </optgroup>
+  <optgroup label="group 2">
+    <option>Megatron</option>
+    <option>Starscream</option>
+    <option>Brawl</option>
+  </optgroup>
+</select>
+</body>
+</html>
diff --git a/content/test/data/accessibility/html/optgroup.html b/content/test/data/accessibility/html/optgroup.html
index 035d50d..59e9622 100644
--- a/content/test/data/accessibility/html/optgroup.html
+++ b/content/test/data/accessibility/html/optgroup.html
@@ -3,6 +3,7 @@
 @WIN-ALLOW:xml-roles*
 @WIN-ALLOW:IA2_STATE_VERTICAL
 @WIN-ALLOW:SELECTABLE
+@WIN-ALLOW:*popup*
 @UIA-WIN-ALLOW:Value.IsReadOnly*
 @BLINK-ALLOW:setSize*
 @BLINK-ALLOW:posInSet*
@@ -10,6 +11,7 @@
 @AURALINUX-ALLOW:posinset*
 @AURALINUX-ALLOW:setsize*
 @AURALINUX-ALLOW:enabled
+@AURALINUX-ALLOW:*popup*
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/select.html b/content/test/data/accessibility/html/select.html
index 9d8e5b5..a87aa6d 100644
--- a/content/test/data/accessibility/html/select.html
+++ b/content/test/data/accessibility/html/select.html
@@ -1,6 +1,8 @@
 <!--
 @MAC-ALLOW:AXRoleDescription=*
 @WIN-ALLOW:HASPOPUP
+@WIN-ALLOW:READONLY*
+@WIN-ALLOW:IA2_STATE_EDITABLE
 @WIN-ALLOW:haspopup*
 @WIN-ALLOW:ia2_hypertext=*
 @WIN-ALLOW:MULTISELECTABLE
diff --git a/content/test/data/attribution_reporting/interop/attribution_scopes_older_scopes_removed_2.json b/content/test/data/attribution_reporting/interop/attribution_scopes_older_scopes_removed_2.json
new file mode 100644
index 0000000..8066148f
--- /dev/null
+++ b/content/test/data/attribution_reporting/interop/attribution_scopes_older_scopes_removed_2.json
@@ -0,0 +1,202 @@
+{
+  "description": "Tests that sources with outdated scopes are deleted using expected scope ordering.",
+  "api_config": {
+    "needs_attribution_scopes": true
+  },
+  "input": {
+    "registrations": [
+      {
+        "timestamp": "0",
+        "registration_request": {
+          "context_origin": "https://source.test",
+          "Attribution-Reporting-Eligible": "navigation-source"
+        },
+        "responses": [
+          {
+            "url": "https://reporter.test/register-source",
+            "response": {
+              "Attribution-Reporting-Register-Source": {
+                "destination": "https://destination.test",
+                "source_event_id": "0",
+                "attribution_scopes": {
+                  "limit": 4,
+                  "values": [
+                    "2"
+                  ]
+                }
+              }
+            }
+          }
+        ]
+      },
+      {
+        "timestamp": "1",
+        "registration_request": {
+          "context_origin": "https://source.test",
+          "Attribution-Reporting-Eligible": "navigation-source"
+        },
+        "responses": [
+          {
+            "url": "https://reporter.test/register-source",
+            "response": {
+              "Attribution-Reporting-Register-Source": {
+                "destination": "https://destination.test",
+                "source_event_id": "1",
+                "attribution_scopes": {
+                  "limit": 4,
+                  "values": [
+                    "3"
+                  ]
+                }
+              }
+            }
+          }
+        ]
+      },
+      {
+        "timestamp": "2",
+        "registration_request": {
+          "context_origin": "https://source.test",
+          "Attribution-Reporting-Eligible": "navigation-source"
+        },
+        "responses": [
+          {
+            "url": "https://reporter.test/register-source",
+            "response": {
+              "Attribution-Reporting-Register-Source": {
+                "destination": "https://destination.test",
+                "source_event_id": "2",
+                "attribution_scopes": {
+                  "limit": 4,
+                  "values": [
+                    "1",
+                    "2",
+                    "3"
+                  ]
+                }
+              }
+            }
+          }
+        ]
+      },
+      {
+        "timestamp": "3",
+        "registration_request": {
+          "context_origin": "https://source.test",
+          "Attribution-Reporting-Eligible": "navigation-source"
+        },
+        "responses": [
+          {
+            "url": "https://reporter.test/register-source",
+            "response": {
+              "Attribution-Reporting-Register-Source": {
+                "destination": "https://destination.test",
+                "source_event_id": "3",
+                "attribution_scopes": {
+                  "limit": 4,
+                  "values": [
+                    "1"
+                  ]
+                }
+              }
+            }
+          }
+        ]
+      },
+      {
+        "timestamp": "4",
+        "registration_request": {
+          "context_origin": "https://source.test",
+          "Attribution-Reporting-Eligible": "navigation-source"
+        },
+        "responses": [
+          {
+            "url": "https://reporter.test/register-source",
+            "response": {
+              "Attribution-Reporting-Register-Source": {
+                "destination": "https://destination.test",
+                "source_event_id": "4",
+                // "4" and "5" should be stored, leaving room for 2 existing
+                // scopes to be retained. Of the existing ones, "1" comes from
+                // the most recent source, and "3" is greater than "2".
+                "attribution_scopes": {
+                  "limit": 4,
+                  "values": [
+                    "4",
+                    "5"
+                  ]
+                }
+              }
+            }
+          }
+        ]
+      },
+      {
+        "timestamp": "5",
+        "registration_request": {
+          "context_origin": "https://destination.test"
+        },
+        "responses": [
+          {
+            "url": "https://reporter.test/register-trigger",
+            "debug_permission": true,
+            "response": {
+              "Attribution-Reporting-Register-Trigger": {
+                // The sources associated with "2" should have been removed.
+                "attribution_scopes": ["2"],
+                "debug_reporting": true,
+                "event_trigger_data": [{}]
+              }
+            }
+          }
+        ]
+      },
+      {
+        "timestamp": "6",
+        "registration_request": {
+          "context_origin": "https://destination.test"
+        },
+        "responses": [
+          {
+            "url": "https://reporter.test/register-trigger",
+            "debug_permission": true,
+            "response": {
+              "Attribution-Reporting-Register-Trigger": {
+                // The sources associated with "3" should not have been removed.
+                "attribution_scopes": ["3"],
+                "debug_reporting": true,
+                "event_trigger_data": [{}]
+              }
+            }
+          }
+        ]
+      }
+    ]
+  },
+  "output": {
+    "reports": [
+      {
+        "payload": [{
+          "body": {
+            "attribution_destination": "https://destination.test"
+          },
+          "type": "trigger-no-matching-source"
+        }],
+        "report_time": "5",
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/debug/verbose"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024263,
+          "scheduled_report_time": "172800",
+          "source_event_id": "1",
+          "source_type": "navigation",
+          "trigger_data": "0"
+        },
+        "report_time": "172800001",
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution"
+      }
+    ]
+  }
+}
diff --git a/content/test/data/gpu/webcodecs/manual-svc.html b/content/test/data/gpu/webcodecs/manual-svc.html
new file mode 100644
index 0000000..f4169f5
--- /dev/null
+++ b/content/test/data/gpu/webcodecs/manual-svc.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<!--
+Test manual reference frame control:
+ - VideoEncoder.getAllFrameBuffers()
+ - VideoEncoderEncodeOptions.updateBuffer
+ - VideoEncoderEncodeOptions.referenceBuffers
+-->
+<html>
+
+<head>
+  <title>Manual SVC encoding test</title>
+  <script src="webcodecs_common.js"></script>
+  <script src="manual-svc.js"></script>
+  <script type="text/javascript">
+    'use strict';
+    addManualTestButton([
+    {
+      'codec': 'av01.0.04M.08',
+      'acceleration': 'prefer-software',
+      'layers': 0
+    },
+    {
+      'codec': 'av01.0.04M.08',
+      'acceleration': 'prefer-software',
+      'layers': 1
+    },
+    {
+      'codec': 'av01.0.04M.08',
+      'acceleration': 'prefer-software',
+      'layers': 2
+    },
+    {
+      'codec': 'av01.0.04M.08',
+      'acceleration': 'prefer-software',
+      'layers': 3
+    }]);
+  </script>
+</head>
+
+<body>
+  <canvas id="debug_cnv" width="640" height="480"></canvas>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/content/test/data/gpu/webcodecs/manual-svc.js b/content/test/data/gpu/webcodecs/manual-svc.js
new file mode 100644
index 0000000..bddabc1e
--- /dev/null
+++ b/content/test/data/gpu/webcodecs/manual-svc.js
@@ -0,0 +1,161 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+function showFrameForDebug(frame) {
+  const cnv = document.getElementById('debug_cnv');
+  var ctx = cnv.getContext('2d');
+  ctx.drawImage(frame, 0, 0);
+}
+
+async function main(arg) {
+  const width = 640;
+  const height = 480;
+  const frames_to_encode = 32;
+  let frames_encoded = 0;
+  let frames_decoded = 0;
+  let errors = 0;
+  const base_layer_decimator = ([1, 1, 2, 4])[arg.layers];
+  let expected_dot_count = [];
+
+  const encoder_config = {
+    codec: arg.codec,
+    hardwareAcceleration: arg.acceleration,
+    width: width,
+    height: height,
+    bitrateMode: 'quantizer',
+    scalabilityMode: 'manual',
+    latencyMode: 'realtime',
+  };
+
+  TEST.log('Starting test with arguments: ' + JSON.stringify(arg));
+  let supported = false;
+  try {
+    supported =
+        (await VideoEncoder.isConfigSupported(encoder_config)).supported;
+  } catch (e) {
+  }
+  if (!supported) {
+    TEST.skip('Unsupported codec: ' + arg.codec);
+    return;
+  }
+
+  let decoder = new VideoDecoder({
+    output(frame) {
+      frames_decoded++;
+      let dots = expected_dot_count.shift();
+      TEST.log(`Decoded frame ${frame.timestamp} ${frames_decoded} ${dots}`);
+      // Check that we have intended number of dots and no more.
+      // Completely black frame shouldn't pass the test.
+      if (!validateBlackDots(frame, dots) ||
+          validateBlackDots(frame, dots + 1)) {
+        showFrameForDebug(frame);
+        TEST.reportFailure(
+            `Unexpected dot count ts:${frame.timestamp} dots:${dots}`);
+      }
+
+      frame.close();
+    },
+    error(e) {
+      errors++;
+      TEST.log(e);
+    }
+  });
+
+  const encoder_init = {
+    output(chunk, metadata) {
+      let config = metadata.decoderConfig;
+      if (config) {
+        decoder.configure(config);
+      }
+
+      if (frames_encoded % base_layer_decimator == 0) {
+        decoder.decode(chunk);
+      }
+      frames_encoded++;
+    },
+    error(e) {
+      errors++;
+      TEST.log(e);
+    }
+  };
+
+  let encoder = new VideoEncoder(encoder_init);
+  encoder.configure(encoder_config);
+  const buffers = encoder.getAllFrameBuffers();
+  const last_base_layer_buffer = buffers[0];
+  TEST.assert(buffers.length == 3, 'expect 3 encoder buffers');
+
+  let source = new CanvasSource(width, height);
+
+  for (let i = 0; i < frames_to_encode; i++) {
+    let frame = await source.getNextFrame();
+    const encode_options = {keyFrame: false, av1: {quantizer: 5}};
+    switch (arg.layers) {
+      case 0:
+        // No layers. Each frame can be decoded on its own, no dependencies.
+        encode_options.updateBuffer = last_base_layer_buffer;
+        break;
+      case 1:
+        // Single layer, each frame depends on the previous one.
+        encode_options.updateBuffer = last_base_layer_buffer;
+        encode_options.referenceBuffers = [last_base_layer_buffer];
+        break;
+      case 2:
+        // Two temporal layers L1T2
+        // Layer Index 0: |0| |2| |4| |6|
+        // Layer Index 1: | |1| |3| |5| |7
+        if (i % 2 == 0) {
+          encode_options.updateBuffer = last_base_layer_buffer;
+        }
+        encode_options.referenceBuffers = [last_base_layer_buffer];
+        break;
+      case 3:
+        // Three temporal layers L1T3
+        // Layer Index 0: |0| | | |4| | | |8| |  |  |12|
+        // Layer Index 1: | | |2| | | |6| | | |10|  |  |
+        // Layer Index 2: | |1| |3| |5| |7| |9|  |11|  |
+        const middle_layer_buffer = buffers[1];
+        const index_in_cycle = i % 4;
+        encode_options.referenceBuffers = [last_base_layer_buffer];
+        if (index_in_cycle == 0) {
+          // Base layer frame.
+          encode_options.updateBuffer = last_base_layer_buffer;
+        } else if (index_in_cycle == 1) {
+          // First frame of the highest layer.
+        } else if (index_in_cycle == 2) {
+          // Middle layer.
+          encode_options.updateBuffer = middle_layer_buffer;
+        } else {
+          // Second frame of the highest layer.
+          encode_options.referenceBuffers.push(middle_layer_buffer);
+        }
+        break;
+    }
+    encoder.encode(frame, encode_options);
+    if (i % base_layer_decimator == 0)
+      expected_dot_count.push(i);
+    frame.close();
+
+    await waitForNextFrame();
+  }
+  await encoder.flush();
+  await decoder.flush();
+  encoder.close();
+  decoder.close();
+  source.close();
+
+  TEST.assert(
+      errors == 0, 'Decoding or encoding errors occurred during the test');
+  TEST.assert(
+      frames_encoded == frames_to_encode,
+      'frames_encoded mismatch: ' + frames_encoded);
+
+  let base_layer_frames = frames_encoded / base_layer_decimator;
+  TEST.assert(
+      frames_decoded == base_layer_frames,
+      'frames_decoded mismatch: ' + frames_decoded);
+  TEST.log('Test completed');
+}
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
index ab1e64e..c789fe9 100644
--- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -207,6 +207,9 @@
 # Flaky failure on Mac release NVIDIA - 3 GPU process crashes instead of 4
 crbug.com/355923591 [ mac release nvidia ] GpuCrash_InfoForDualHardwareGpus [ RetryOnFailure ]
 
+# Flaky failure on Mac Intel ASAN - DevTools Serialization Crash
+crbug.com/338574390 [ mac intel asan ] ContextLost_WebGLContextRestoredInHiddenTab [ RetryOnFailure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
index 6a3b28b..c0fcf87 100644
--- a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
@@ -119,8 +119,9 @@
 # Gardener 2024-03-18
 crbug.com/330132405 [ fuchsia fuchsia-board-qemu-x64 ] ExpectedColor_MediaRecorderFrom2DCanvas [ Failure ]
 
-# Gardener 2024-04-29 - page reported failure
+# Longstanding flaking test - page reported failure
 crbug.com/40877266 [ amd-0x7340 angle-d3d11 graphite-enabled passthrough release-x64 win10 ] ExpectedColor_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ]
+crbug.com/40877266 [ android android-shield-android-tv ] ExpectedColor_MediaRecorderFromVideoElement [ RetryOnFailure ]
 
 # Tests are hitting an assertion, root cause needs to be tracked down.
 crbug.com/41488897 [ android android-pixel-6 passthrough graphite-enabled ] ExpectedColor_MediaRecorderFromVideoElement [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index bb40897..33f10f3 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -129,9 +129,7 @@
 crbug.com/1470336 [ android-oreo android-nexus-5x ] WebCodecs_EncodingRateControl_vp8_prefer-hardware_constant_3000000 [ Failure ]
 crbug.com/1474916 [ android-nexus-5x ] WebCodecs_EncodeColorSpace_avc1.42001E_prefer-hardware [ Failure ]
 
-crbug.com/1486660 [ chromeos chromeos-board-jacuzzi ] WebCodecs_EncodeColorSpace_avc1.42001E_prefer-hardware [ Failure ]
-crbug.com/361615553 [ chromeos chromeos-board-jacuzzi ] WebCodecs_Encode_hw_decoder_avc1.42001E_prefer-hardware [ Failure ]
-
+crbug.com/361615553 [ chromeos chromeos-board-jacuzzi ] WebCodecs_* [ Failure ]
 
 crbug.com/1466102 [ nvidia-0x2184 nvidia_lt_31.0.15.4601 win ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_* [ Failure ]
 crbug.com/1517101 [ win amd-0x7340 ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_* [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index 1cdcc0ae..1e77e9dc 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -481,6 +481,13 @@
 crbug.com/1490427 [ fuchsia fuchsia-board-qemu-x64 ] conformance/textures/misc/texture-video-transparent.html [ Failure ]
 crbug.com/1490427 [ fuchsia fuchsia-board-qemu-x64 ] conformance/textures/misc/tex-video-using-tex-unit-non-zero.html [ Failure ]
 
+# flaky and worth retrying.
+crbug.com/1490427 [ fuchsia fuchsia-board-astro ] conformance/state/gl-object-get-calls.html [ RetryOnFailure ]
+crbug.com/1490427 [ fuchsia fuchsia-board-astro ] conformance/textures/misc/texture-size-limit.html [ RetryOnFailure ]
+crbug.com/1490427 [ fuchsia fuchsia-board-sherlock ] conformance/state/gl-object-get-calls.html [ RetryOnFailure ]
+crbug.com/1490427 [ fuchsia fuchsia-board-sherlock ] conformance/textures/misc/texture-size-limit.html [ RetryOnFailure ]
+crbug.com/1490427 [ fuchsia fuchsia-board-nelson ] conformance/state/gl-object-get-calls.html [ RetryOnFailure ]
+crbug.com/1490427 [ fuchsia fuchsia-board-nelson ] conformance/textures/misc/texture-size-limit.html [ RetryOnFailure ]
 
 
 ####################
diff --git a/content/test/gpu/gpu_tests/webcodecs_integration_test.py b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
index 870081cd..e2e580d 100644
--- a/content/test/gpu/gpu_tests/webcodecs_integration_test.py
+++ b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
@@ -162,6 +162,19 @@
                'acceleration': acc
            }])
 
+    codec = 'av01.0.04M.08'
+    acc = 'prefer-software'
+    for layers in range(4):
+      args = (codec, acc, layers)
+      yield ('WebCodecs_ManualSVC_%s_%s_layers_%d' % args, 'manual-svc.html', [{
+          'codec':
+          codec,
+          'acceleration':
+          acc,
+          'layers':
+          layers
+      }])
+
     for source_type in frame_sources:
       for codec in video_codecs:
         for acc in accelerations:
diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc
index d64d1e3..4cd593b9 100644
--- a/content/web_test/renderer/test_runner.cc
+++ b/content/web_test/renderer/test_runner.cc
@@ -3161,16 +3161,6 @@
   NotifyDone(source);
 }
 
-void TestRunner::ResetRendererAfterWebTest() {
-  WebFrameTestProxy* main_frame = FindInProcessMainWindowMainFrame();
-  // When the about:blank navigation happens in a new process, the new
-  // WebFrameTestProxy is not designated to be the "MainWindowMainFrame" one
-  // yet. It will be tracked later after receiving the SetTestConfiguration IPC.
-  if (main_frame)
-    main_frame->Reset();
-  Reset();
-}
-
 void TestRunner::AddMainFrame(WebFrameTestProxy& frame) {
   main_frames_.insert(&frame);
 }
diff --git a/content/web_test/renderer/test_runner.h b/content/web_test/renderer/test_runner.h
index 81bcdbc..23c13bb5 100644
--- a/content/web_test/renderer/test_runner.h
+++ b/content/web_test/renderer/test_runner.h
@@ -101,10 +101,6 @@
   // Notification that another renderer has explicitly asked the test to end.
   void TestFinishedFromSecondaryRenderer(WebFrameTestProxy& source);
 
-  // Performs a reset at the end of a test, in order to prepare for the next
-  // test.
-  void ResetRendererAfterWebTest();
-
   // Track the set of all main frames in the process, which is also the set of
   // windows rooted in this process.
   void AddMainFrame(WebFrameTestProxy& frame);
diff --git a/content/web_test/renderer/web_frame_test_proxy.cc b/content/web_test/renderer/web_frame_test_proxy.cc
index 5ce12fc9..146b566 100644
--- a/content/web_test/renderer/web_frame_test_proxy.cc
+++ b/content/web_test/renderer/web_frame_test_proxy.cc
@@ -269,11 +269,13 @@
   GetWebTestControlHostRemote();
 }
 
-void WebFrameTestProxy::Reset() {
-  // TODO(crbug.com/40615943): The RenderDocument project will cause us to
-  // replace the main frame on each navigation, including to about:blank and
-  // then to the next test. So resetting the frame or RenderWidget won't be
-  // meaningful then.
+void WebFrameTestProxy::ResetRendererAfterWebTest() {
+  // TODO(crbug.com/40615943): Some of this work is no longer needed if the
+  // RenderDocument project causes us to replace the main frame on each
+  // navigation. But some of it will continue to be necessary since it modifies
+  // process-global state, e.g. ResetMockOverlayScrollbars in internals.cc.
+  // The content::TestRunner object also persists for the life of the renderer.
+  // So the steps in this method need to be audited piecemeal for redundancy.
   CHECK(IsMainFrame());
 
   if (IsMainFrame()) {
@@ -297,6 +299,7 @@
 
   accessibility_controller_.Reset();
   spell_check_->Reset();
+  test_runner_->Reset();
 }
 
 std::string WebFrameTestProxy::GetFrameNameForWebTests() {
@@ -892,8 +895,4 @@
       std::move(changed_layout_test_runtime_flags));
 }
 
-void WebFrameTestProxy::ResetRendererAfterWebTest() {
-  test_runner_->ResetRendererAfterWebTest();
-}
-
 }  // namespace content
diff --git a/content/web_test/renderer/web_frame_test_proxy.h b/content/web_test/renderer/web_frame_test_proxy.h
index e3e1526..4ee473a 100644
--- a/content/web_test/renderer/web_frame_test_proxy.h
+++ b/content/web_test/renderer/web_frame_test_proxy.h
@@ -46,9 +46,6 @@
   // RenderFrameImpl overrides.
   void Initialize(blink::WebFrame* parent) override;
 
-  // Reset state between tests.
-  void Reset();
-
   // Returns a frame name that can be used in the output of web tests
   // (the name is derived from the frame's unique name).
   std::string GetFrameNameForWebTests();
diff --git a/docs/design/sandbox.md b/docs/design/sandbox.md
index b66a03a..226336c 100644
--- a/docs/design/sandbox.md
+++ b/docs/design/sandbox.md
@@ -17,8 +17,8 @@
 confidential. The architecture and exact assurances that the sandbox provides
 are dependent on the operating system. This document covers the Windows
 implementation as well as the general design. The Linux implementation is
-described [here](../linux/sandboxing.md), the OSX implementation
-[here](http://dev.chromium.org/developers/design-documents/sandbox/osx-sandboxing-design).
+described [here](../../linux/sandbox/linux/README.md), the OSX implementation
+[here](https://dev.chromium.org/developers/design-documents/sandbox/osx-sandboxing-design).
 
 If you don't feel like reading this whole document you can read the
 [Sandbox FAQ](sandbox_faq.md) instead. A description of what the sandbox does
diff --git a/docs/git_submodules.md b/docs/git_submodules.md
index 5f9ddac2..572e8ca0 100644
--- a/docs/git_submodules.md
+++ b/docs/git_submodules.md
@@ -167,6 +167,33 @@
 With the above, you can execute these commands by running `git s`, `git c`, etc.
 Or you may also use the pre-commit git hook detailed below.
 
+### Understanding diff.ignoreSubmodules
+
+`git config diff.ignoreSubmodules` sets a default behavior for `diff`, `status`,
+and several other git subcommands, using one of the [supported values of
+`--ignore-submodules`](https://www.git-scm.com/docs/git-diff/#Documentation/git-diff.txt---ignore-submodulesltwhengt).
+
+By default, `gclient sync` sets this to `dirty` as a local config in the
+chromium checkout. This elides submodule output for `git status` in a clean
+checkout, but will show submodules as modified when developers locally touch
+them.
+
+Manually setting this to `all` elides such output in all cases. This also omits
+submodule changes from `git commit -a`, which can decrease the likelihood of
+accidental submodule commits. However, it does not omit such changes from
+`git add -A`, meaning developers who use this flow are actually _more_ likely to
+commit accidental changes, since they'll be invisible beforehand unless
+developers manually set `--ignore-submodules=dirty` or use a lower-level command
+such as `git diff-tree`.
+
+Because `all` can result in misleading output and doesn't fully prevent
+accidental submodule commits, typical developers are likely better-served by
+leaving this configured to `dirty` and installing the
+[commit hook described below](#install-hook) to prevent such commits.
+Accordingly, `gclient sync` will warn if it detects a different setting locally;
+developers who understand the consequences can silence the warning via the
+`GCLIENT_SUPPRESS_SUBMODULE_WARNING` environment variable.
+
 ### Submodules during a 'git rebase-update'
 While resolving merge conflicts during a `git rebase-update` you may see
 submodules show up in unexpected places.
@@ -194,7 +221,7 @@
 resetting it:
 `gclient setdep -r {path}@{hash}`
 
-## Install a hook to help detect unintentional submodule commits
+## Install a hook to help detect unintentional submodule commits {#install-hook}
 
 depot_tools provides an opt-in pre-commit hook to detect unintentional submodule
  changes during `git commit` and remove them from the commit.
diff --git a/extensions/browser/extension_navigation_throttle.cc b/extensions/browser/extension_navigation_throttle.cc
index b33b4b9..419db867 100644
--- a/extensions/browser/extension_navigation_throttle.cc
+++ b/extensions/browser/extension_navigation_throttle.cc
@@ -8,6 +8,7 @@
 #include <string_view>
 
 #include "base/containers/contains.h"
+#include "base/metrics/histogram_functions.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -33,6 +34,7 @@
 #include "extensions/common/permissions/permissions_data.h"
 #include "services/network/public/cpp/web_sandbox_flags.h"
 #include "ui/base/page_transition_types.h"
+#include "url/origin.h"
 
 #if BUILDFLAG(ENABLE_GUEST_VIEW)
 #include "components/guest_view/browser/guest_view_base.h"
@@ -278,6 +280,28 @@
     return content::NavigationThrottle::BLOCK_REQUEST;
   }
 
+  // `redirect_chain` is the current page and each one before is an ancestor.
+  const auto& redirect_chain = navigation_handle()->GetRedirectChain();
+
+  // Record if the redirection is to an extension resource that isn't web
+  // accessible.
+  if (redirect_chain.size() > 1) {
+    // Looking back to the previous should be okay since this block is expected
+    // to be reached again if there are more redirects in the same navigation.
+    const GURL& upstream = redirect_chain[redirect_chain.size() - 2];
+    auto upstream_origin = url::Origin::Create(upstream);
+    // Cross-origin-redirects require that the resource is accessible in the
+    // "web_accessible_resources" section of the manifest.
+    if (!upstream_origin.opaque() && upstream_origin != target_origin) {
+      base::UmaHistogramBoolean(
+          target_extension->manifest_version() < 3
+              ? "Extensions.WAR.XOriginWebAccessible.MV2"
+              : "Extensions.WAR.XOriginWebAccessible.MV3",
+          WebAccessibleResourcesInfo::IsResourceWebAccessibleRedirect(
+              target_extension, url, target_origin, upstream));
+    }
+  }
+
   // Automatically trusted navigation:
   // * Browser-initiated navigations without an initiator origin happen when a
   //   user directly triggers a navigation (e.g. using the omnibox, or the
@@ -326,8 +350,6 @@
 
   // Cross-origin-initiator navigations require that the `url` is in the
   // manifest's "web_accessible_resources" section. The last GURL in
-  // `redirect_chain` is the current page and each one before is an ancestor.
-  auto redirect_chain = navigation_handle()->GetRedirectChain();
   GURL upstream_url = redirect_chain.size() > 1
                           ? redirect_chain[redirect_chain.size() - 2]
                           : GURL();
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index d99cedc..87f5901 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -184,7 +184,7 @@
 
 BASE_FEATURE(kIncludeJSCallStackInExtensionApiRequest,
              "IncludeJSCallStackInExtensionApiRequest",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kUseItemSnippetsAPI,
              "UseItemSnippetsAPI",
diff --git a/google_apis/google_api_keys.py b/google_apis/google_api_keys.py
index 17965ec..696f07c5 100755
--- a/google_apis/google_api_keys.py
+++ b/google_apis/google_api_keys.py
@@ -28,7 +28,7 @@
   if not os.path.isfile(official_path):
     return None
 
-  line_regexp = '^#define\s*%s\s*"([^"]+)"' % token_name
+  line_regexp = r'^#define\s*%s\s*"([^"]+)"' % token_name
   line_pattern = re.compile(line_regexp)
   def ParseLine(current_line):
     result = line_pattern.match(current_line)
diff --git a/infra/config/generated/builders/try/dawn-chromium-presubmit/properties.json b/infra/config/generated/builders/try/dawn-chromium-presubmit/properties.json
index 1e7cabb..5753e87b 100644
--- a/infra/config/generated/builders/try/dawn-chromium-presubmit/properties.json
+++ b/infra/config/generated/builders/try/dawn-chromium-presubmit/properties.json
@@ -4,6 +4,9 @@
       "additional_exclusions": [
         "infra/config/generated/builders/try/dawn-chromium-presubmit/gn-args.json"
       ],
+      "analyze_names": [
+        "dawn_chromium_presubmit"
+      ],
       "builder_db": {
         "entries": [
           {
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl
index 9c3e79b..d91b8d3 100644
--- a/infra/config/generated/testing/test_suites.pyl
+++ b/infra/config/generated/testing/test_suites.pyl
@@ -2621,6 +2621,21 @@
       },
     },
 
+    'gpu_dawn_gtests_use_tint_ir': {
+      'dawn_end2end_use_tint_ir_tests': {
+        'test': 'dawn_end2end_tests',
+        'mixins': [
+          'dawn_end2end_gpu_test',
+        ],
+        'args': [
+          '--enable-toggles=use_tint_ir',
+        ],
+        'swarming': {
+          'shards': 1,
+        },
+      },
+    },
+
     'gpu_dawn_gtests_with_validation': {
       'dawn_end2end_validation_layers_tests': {
         'test': 'dawn_end2end_tests',
@@ -6152,6 +6167,13 @@
       'gpu_dawn_gtests_with_validation',
     ],
 
+    'gpu_dawn_integration_gtests_passthrough_macos': [
+      'gpu_common_gtests_passthrough',
+      'gpu_dawn_gtests',
+      'gpu_dawn_gtests_use_tint_ir',
+      'gpu_dawn_gtests_with_validation',
+    ],
+
     'gpu_dawn_integration_gtests_passthrough_win_x64': [
       'gpu_common_gtests_passthrough',
       'gpu_dawn_gtests',
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
index 48915caa..740e971 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
@@ -44,6 +44,9 @@
         "ci/Dawn Chromium Presubmit",
     ],
     builder_config_settings = builder_config.try_settings(
+        analyze_names = [
+            "dawn_chromium_presubmit",
+        ],
         retry_failed_shards = False,
         retry_without_patch = False,
     ),
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star
index e17322c..589fb2d 100644
--- a/infra/config/targets/basic_suites.star
+++ b/infra/config/targets/basic_suites.star
@@ -2324,6 +2324,17 @@
     },
 )
 
+targets.legacy_basic_suite(
+    name = "gpu_dawn_gtests_use_tint_ir",
+    tests = {
+        "dawn_end2end_use_tint_ir_tests": targets.legacy_test_config(
+            swarming = targets.swarming(
+                shards = 1,
+            ),
+        ),
+    },
+)
+
 # GPU gtests that test only Dawn with backend validation layers
 targets.legacy_basic_suite(
     name = "gpu_dawn_gtests_with_validation",
diff --git a/infra/config/targets/compound_suites.star b/infra/config/targets/compound_suites.star
index 1201d86..91e6414 100644
--- a/infra/config/targets/compound_suites.star
+++ b/infra/config/targets/compound_suites.star
@@ -664,6 +664,17 @@
     ],
 )
 
+# TODO(crbug.com/364675466): Remove this when Tint IR is launched on macOS.
+targets.legacy_compound_suite(
+    name = "gpu_dawn_integration_gtests_passthrough_macos",
+    basic_suites = [
+        "gpu_dawn_gtests",
+        "gpu_dawn_gtests_with_validation",
+        "gpu_dawn_gtests_use_tint_ir",
+        "gpu_common_gtests_passthrough",
+    ],
+)
+
 targets.legacy_compound_suite(
     name = "gpu_dawn_isolated_scripts",
     basic_suites = [
diff --git a/infra/config/targets/tests.star b/infra/config/targets/tests.star
index f8e44d1..b7e1c20 100644
--- a/infra/config/targets/tests.star
+++ b/infra/config/targets/tests.star
@@ -1127,6 +1127,17 @@
 )
 
 targets.tests.gtest_test(
+    name = "dawn_end2end_use_tint_ir_tests",
+    mixins = [
+        "dawn_end2end_gpu_test",
+    ],
+    args = [
+        "--enable-toggles=use_tint_ir",
+    ],
+    binary = "dawn_end2end_tests",
+)
+
+targets.tests.gtest_test(
     name = "fuzzing_unittests",
 )
 
diff --git a/infra/inclusive_language_presubmit_exempt_dirs.txt b/infra/inclusive_language_presubmit_exempt_dirs.txt
index ba00926..1626c3f 100644
--- a/infra/inclusive_language_presubmit_exempt_dirs.txt
+++ b/infra/inclusive_language_presubmit_exempt_dirs.txt
@@ -306,7 +306,6 @@
 third_party/android_build_tools/compose_compiler 1 1
 third_party/android_build_tools/gradle_wrapper 1 1
 third_party/android_build_tools/json 1 1
-third_party/android_deps_autorolled 1 1
 third_party/android_deps/buildSrc/src/main/groovy 36 2
 third_party/android_deps/libs 1 1
 third_party/android_deps/libs/com_google_auto_auto_common 1 1
@@ -653,8 +652,8 @@
 third_party/rust/chromium_crates_io/vendor/adler2-2.0.0/.github/workflows 2 1
 third_party/rust/chromium_crates_io/vendor/aho-corasick-1.1.3/.github/workflows 5 1
 third_party/rust/chromium_crates_io/vendor/anstyle-1.0.8 1 1
-third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86 2 1
-third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.github/workflows 3 1
+third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87 2 1
+third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.github/workflows 3 1
 third_party/rust/chromium_crates_io/vendor/base64-0.13.1 1 1
 third_party/rust/chromium_crates_io/vendor/bytes-1.7.1/.github/workflows 3 1
 third_party/rust/chromium_crates_io/vendor/cfg-if-1.0.0/.github/workflows 4 1
@@ -716,9 +715,9 @@
 third_party/rust/chromium_crates_io/vendor/ryu-1.0.18/src 1 1
 third_party/rust/chromium_crates_io/vendor/semver-1.0.23 1 1
 third_party/rust/chromium_crates_io/vendor/semver-1.0.23/.github/workflows 2 1
-third_party/rust/chromium_crates_io/vendor/serde-1.0.209 1 1
-third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src 1 1
-third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209 1 1
+third_party/rust/chromium_crates_io/vendor/serde-1.0.210 1 1
+third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src 1 1
+third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210 1 1
 third_party/rust/chromium_crates_io/vendor/serde_json-1.0.128 6 1
 third_party/rust/chromium_crates_io/vendor/serde_json-1.0.128/.github/workflows 1 1
 third_party/rust/chromium_crates_io/vendor/serde_json_lenient-0.2.1 1 1
@@ -814,7 +813,6 @@
 tools/binary_size/libsupersize/testdata 4 1
 tools/checkperms 1 1
 tools/crates/gnrt 1 1
-tools/cygprofile 1 1
 tools/emacs 320 4
 tools/git 2 1
 tools/mac/power/protos/third_party/pprof 1 1
diff --git a/internal b/internal
index 2161c6c..619a026 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 2161c6c29e26dbbdcb8ed215a548e202b89f5cd7
+Subproject commit 619a026e7cb0711040338bb724d00e8420611336
diff --git a/ios/build/bots/scripts/result_sink_util.py b/ios/build/bots/scripts/result_sink_util.py
index 28a8c27a..3c152f2 100644
--- a/ios/build/bots/scripts/result_sink_util.py
+++ b/ios/build/bots/scripts/result_sink_util.py
@@ -17,9 +17,12 @@
 # import protos for exceptions reporting
 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 CHROMIUM_SRC_DIR = os.path.abspath(os.path.join(THIS_DIR, '../../../..'))
-sys.path.append(
-    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/lib/proto')))
-import exception_occurrences_pb2
+sys.path.extend([
+    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/lib/proto')),
+    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/'))
+])
+import measures
+import exception_recorder
 
 from google.protobuf import json_format
 from google.protobuf import any_pb2
@@ -30,6 +33,7 @@
 # https://source.chromium.org/chromium/infra/infra/+/main:go/src/go.chromium.org/luci/resultdb/proto/v1/test_result.proto;drc=ca12b9f52b27f064b0fa47c39baa3b011ffa5790;l=151-174
 VALID_STATUSES = {"PASS", "FAIL", "CRASH", "ABORT", "SKIP"}
 
+EXTENDED_PROPERTIES_KEY = 'extended_properties'
 
 def format_exception_stacktrace(e: Exception):
   exception_trace = traceback.format_exception(type(e), e, e.__traceback__)
@@ -122,32 +126,6 @@
   return test_result
 
 
-def _compose_exception_occurrence(exception):
-  """Composes the exception_occurrence item to be posted to result sink.
-
-  Args:
-    exception: (Exception) the exception to be posted to result sink.
-
-  Returns:
-    exception_occurrence: Conforming to protos defined in
-          //build/util/lib/proto/exception_occurrences.proto
-  """
-
-  occurrence = exception_occurrences_pb2.ExceptionOccurrence(
-      name=type(exception).__name__,
-      stacktrace=format_exception_stacktrace(exception),
-  )
-  occurrence.occurred_time.GetCurrentTime()
-  return occurrence
-
-
-class ExceptionResults:
-  results = []  # Static variable to hold exception results
-
-  @staticmethod
-  def add_result(exception):
-    ExceptionResults.results.append(exception)
-
 
 class ResultSinkClient(object):
   """Stores constants and handles posting to ResultSink."""
@@ -211,19 +189,6 @@
     self._post_test_result(
         _compose_test_result(test_id, status, expected, **kwargs))
 
-  def post_exceptions(self, exceptions):
-    """Composes and posts exception result to server.
-
-    Args:
-      exception: [Exception] list of exceptions to be posted to result sink.
-    """
-    if not self.sink:
-      return
-    exception_occurrences = []
-    for exception in exceptions:
-      exception_occurrences.append(_compose_exception_occurrence(exception))
-    self._post_exceptions(exception_occurrences)
-
   def _post_test_result(self, test_result):
     """Posts single test result to server.
 
@@ -240,35 +205,58 @@
     )
     res.raise_for_status()
 
-  def _post_exceptions(self, exception_occurrences):
-    """Posts exception result to server.
-
-    This method assumes |self.sink| is not None.
-
-    Args:
-        exception_occurrences: list of exception_occurrences,
-          conforming to protos defined in
-          //build/util/lib/proto/exception_occurrences.proto
+  def post_extended_properties(self):
+    """Posts extended properties to server with retry.
     """
+    if not self.sink:
+      return
+    try_count = 0
+    try_count_max = 2
+    while try_count < try_count_max:
+      try_count += 1
+      try:
+        self._post_extended_properties()
+        break
+      except Exception as e:
+        logging.error("Got error %s when uploading extended properties.", e)
+        if try_count < try_count_max:
+          # Upload can fail due to record size being too big. In this case,
+          # report just the upload failure.
+          exception_recorder.clear()
+          measures.clear()
+          exception_recorder.register(e)
+        else:
+          # Swallow the exception if the upload fails again and hit the max
+          # try so that it won't fail the test task (and it shouldn't).
+          logging.error("Hit max retry. Skip uploading extended properties.")
 
-    occurrences = exception_occurrences_pb2.ExceptionOccurrences()
-    occurrences.datapoints.extend(exception_occurrences)
-    any_msg = any_pb2.Any()
-    any_msg.Pack(occurrences)
-    inv_data = json.dumps(
-        {
-            'invocation': {
-                'extended_properties': {
-                    'exception_occurrences':
-                        json_format.MessageToDict(
-                            any_msg, preserving_proto_field_name=True)
-                }
-            },
-            'update_mask': {
-                'paths': ['extended_properties.exception_occurrences'],
-            }
-        },
-        sort_keys=True)
+  def _post_extended_properties(self):
+    """Posts extended properties to server.
+
+    Assumes self.sink has been initialized.
+
+    Packages exception_occurrences_pb2 and test_script_metrics_pb2 and sends an
+    UpdateInvocation post request to result sink.
+    """
+    invocation = {EXTENDED_PROPERTIES_KEY: {}}
+    paths = []
+
+    if exception_recorder.size() > 0:
+      invocation[EXTENDED_PROPERTIES_KEY][
+          exception_recorder.EXCEPTION_OCCURRENCES_KEY] = \
+            exception_recorder.to_dict()
+      paths.append('%s.%s' % EXTENDED_PROPERTIES_KEY,
+                   exception_recorder.EXCEPTION_OCCURRENCES_KEY)
+
+    if measures.size() > 0:
+      invocation[EXTENDED_PROPERTIES_KEY][measures.TEST_SCRIPT_METRICS_KEY] = \
+        measures.to_dict()
+      paths.append('%s.%s' %
+                   (EXTENDED_PROPERTIES_KEY, measures.TEST_SCRIPT_METRICS_KEY))
+
+    req = {'invocation': invocation, 'update_mask': {'paths': paths}}
+
+    inv_data = json.dumps(req, sort_keys=True)
 
     LOGGER.info(inv_data)
 
diff --git a/ios/build/bots/scripts/result_sink_util_test.py b/ios/build/bots/scripts/result_sink_util_test.py
index ef4111a..6e3ce1b 100755
--- a/ios/build/bots/scripts/result_sink_util_test.py
+++ b/ios/build/bots/scripts/result_sink_util_test.py
@@ -14,12 +14,11 @@
 import result_sink_util
 import test_runner
 
-# import protos for exceptions reporting
 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 CHROMIUM_SRC_DIR = os.path.abspath(os.path.join(THIS_DIR, '../../../..'))
 sys.path.append(
     os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/lib/proto')))
-import exception_occurrences_pb2
+import measures
 
 from google.protobuf import json_format
 from google.protobuf import any_pb2
@@ -100,14 +99,6 @@
     }
     self.assertEqual(test_result, expected)
 
-  def test_compose_exception_occurrence(self):
-    """Tests compose_exception_occurrence function."""
-    test_exception = test_runner.XcodeVersionNotFoundError("15abcd")
-
-    occurrence = result_sink_util._compose_exception_occurrence(test_exception)
-    self.assertEqual(occurrence.name, "XcodeVersionNotFoundError")
-    self.assertIn("Xcode version not found: 15abcd",
-                  '\n'.join(occurrence.stacktrace))
 
   def test_parsing_crash_message(self):
     """Tests parsing crash message from test log and setting it as the
@@ -263,35 +254,51 @@
   @mock.patch('%s.open' % 'result_sink_util',
               mock.mock_open(read_data=LUCI_CONTEXT_FILE_DATA))
   @mock.patch('os.environ.get', return_value='filename')
-  def test_post_exceptions(self, mock_open_file, mock_session_post):
-    test_exception = test_runner.XcodeVersionNotFoundError("15abcd")
-    occurrences = [
-        result_sink_util._compose_exception_occurrence(test_exception)
-    ]
-    exception_occurrences = exception_occurrences_pb2.ExceptionOccurrences()
-    exception_occurrences.datapoints.extend(occurrences)
-    any_msg = any_pb2.Any()
-    any_msg.Pack(exception_occurrences)
+  def test_post_extended_properties(self, mock_open_file, mock_session_post):
+    count = measures.count('test_count')
+    count.record()
+    count.record()
+
     inv_data = json.dumps(
         {
-            'invocation': {
-                'extended_properties': {
-                    'exception_occurrences':
-                        json_format.MessageToDict(
-                            any_msg, preserving_proto_field_name=True)
+            "invocation": {
+                "extended_properties": {
+                    "test_script_metrics": {
+                        "@type":
+                            "type.googleapis.com/build.util.lib.proto.TestScriptMetrics",
+                        "metrics": [{
+                            "name": "test_count",
+                            "value": 2.0
+                        }]
+                    }
                 }
             },
-            'update_mask': {
-                'paths': ['extended_properties.exception_occurrences'],
+            "update_mask": {
+                "paths": ["extended_properties.test_script_metrics"]
             }
         },
         sort_keys=True)
-    client = result_sink_util.ResultSinkClient()
 
-    client._post_exceptions(occurrences)
+    client = result_sink_util.ResultSinkClient()
+    client.post_extended_properties()
     mock_session_post.assert_called_with(
         url=UPATE_POST_URL, headers=HEADERS, data=inv_data)
 
+  @mock.patch('%s.open' % 'result_sink_util',
+              mock.mock_open(read_data=LUCI_CONTEXT_FILE_DATA))
+  @mock.patch('os.environ.get', return_value='filename')
+  @mock.patch(
+      'result_sink_util.ResultSinkClient._post_extended_properties',
+      side_effect=Exception())
+  def test_post_extended_properties_retries(self, mock_post_ext_props, _):
+    count = measures.count('test_count')
+    count.record()
+
+    client = result_sink_util.ResultSinkClient()
+    client.post_extended_properties()
+
+    self.assertEqual(mock_post_ext_props.call_count, 2)
+
   @mock.patch.object(requests.Session, 'close')
   @mock.patch.object(requests.Session, 'post')
   @mock.patch('%s.open' % 'result_sink_util',
diff --git a/ios/build/bots/scripts/run.py b/ios/build/bots/scripts/run.py
index cf046da..16a87e1 100755
--- a/ios/build/bots/scripts/run.py
+++ b/ios/build/bots/scripts/run.py
@@ -37,7 +37,16 @@
 import xcodebuild_runner
 import xcode_util as xcode
 
-from result_sink_util import ExceptionResults, ResultSinkClient
+THIS_DIR = os.path.abspath(os.path.dirname(__file__))
+CHROMIUM_SRC_DIR = os.path.abspath(os.path.join(THIS_DIR, '../../../..'))
+sys.path.extend([
+    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/lib/proto')),
+    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/'))
+])
+import measures
+import exception_recorder
+
+from result_sink_util import ResultSinkClient
 
 # if the current directory is in scripts, then we need to add plugin
 # path in order to import from that directory
@@ -98,13 +107,14 @@
     tr = None
     is_legacy_xcode = True
     self.parse_args(args)
+
     try:
-      # This logic is run by default before the otool command is invoked such
-      # that otool has the correct Xcode selected for command line dev tools.
-      install_success, is_legacy_xcode = xcode.install_xcode(
-          self.args.mac_toolchain_cmd, self.args.xcode_build_version,
-          self.args.xcode_path, self.args.runtime_cache_prefix,
-          self.args.version)
+      with measures.time_consumption(
+          'mac_toolchain', 'Download and Install', 'Xcode and Runtime'):
+        install_success, is_legacy_xcode = xcode.install_xcode(
+            self.args.mac_toolchain_cmd, self.args.xcode_build_version,
+            self.args.xcode_path, self.args.runtime_cache_prefix,
+            self.args.version)
       if not install_success:
         raise test_runner_errors.XcodeInstallFailedError(
             self.args.xcode_build_version)
@@ -223,7 +233,7 @@
       summary['step_text'] = format_exception_step_text(e)
       # Swarming infra marks device status unavailable for any device related
       # issue using this return code.
-      ExceptionResults.add_result(e)
+      exception_recorder.register(e)
       return 3
     except Exception as e:
       sys.stderr.write(traceback.format_exc())
@@ -231,7 +241,7 @@
       # test_runner.Launch returns 0 on success, 1 on failure, so return 2
       # on exception to distinguish between a test failure, and a failure
       # to launch the test at all.
-      ExceptionResults.add_result(e)
+      exception_recorder.register(e)
       return 2
     finally:
       if tr:
@@ -268,9 +278,9 @@
       test_runner.defaults_delete('com.apple.CoreSimulator',
                                   'FramebufferServerRendererPolicy')
 
-      if ExceptionResults.results:
+      if exception_recorder.size() > 0 or measures.size() > 0:
         result_sink_client = ResultSinkClient()
-        result_sink_client.post_exceptions(ExceptionResults.results)
+        result_sink_client.post_extended_properties()
 
   def parse_args(self, args):
     """Parse the args into args and test_args.
diff --git a/ios/build/bots/scripts/run_test.py b/ios/build/bots/scripts/run_test.py
index fd3fec8..3f845b19 100755
--- a/ios/build/bots/scripts/run_test.py
+++ b/ios/build/bots/scripts/run_test.py
@@ -6,15 +6,25 @@
 
 import json
 import mock
+import os
 import re
+import sys
 import unittest
 
 import run
+import result_sink_util
 from test_runner import SimulatorNotFoundError, TestRunner
 from xcodebuild_runner import SimulatorParallelTestRunner
 import test_runner_errors
 import test_runner_test
 
+THIS_DIR = os.path.abspath(os.path.dirname(__file__))
+CHROMIUM_SRC_DIR = os.path.abspath(os.path.join(THIS_DIR, '../../../..'))
+sys.path.extend([
+    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/lib/proto')),
+    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/'))
+])
+import exception_recorder
 
 class UnitTest(unittest.TestCase):
 
@@ -657,12 +667,9 @@
   @mock.patch(
       'xcode_util.install_xcode', autospec=True, return_value=(False, True))
   @mock.patch('xcode_util.move_runtime', autospec=True)
-  @mock.patch('run.ResultSinkClient')
-  def test_report_exception(self, mock_result_client, mock_move_runtime,
-                            mock_install, mock_construct_runtime_cache_folder,
-                            mock_tr, _1, _2, _3, _4):
-    mock_post_exceptions = mock.MagicMock()
-    mock_result_client.return_value.post_exceptions = mock_post_exceptions
+  def test_report_extended_properties(self, mock_move_runtime, mock_install,
+                                      mock_construct_runtime_cache_folder,
+                                      mock_tr, _1, _2, _3, _4):
     self.runner.args.version = None
     test_runner = mock_tr.return_value
     test_runner.launch.return_value = True
@@ -671,12 +678,12 @@
     with mock.patch('run.open', mock.mock_open()):
       self.runner.run(None)
 
-    expected_exception_str = str(
-        test_runner_errors.XcodeInstallFailedError(
-            self.runner.args.xcode_build_version))
-    actual_exceptions = mock_post_exceptions.call_args[0][0]
+    expected_exception_str = 'test_runner_errors.XcodeInstallFailedError: ' + \
+      str(test_runner_errors.XcodeInstallFailedError(
+        self.runner.args.xcode_build_version))
+    actual_exceptions = exception_recorder._records
     for exception in actual_exceptions:
-      exception_str = str(exception)
+      exception_str = str(exception.stacktrace[-1]).rstrip()
       if 'Xcode' in exception_str:
         self.assertEqual(expected_exception_str, exception_str)
 
diff --git a/ios/build/bots/scripts/xcodebuild_runner.py b/ios/build/bots/scripts/xcodebuild_runner.py
index 9369f78..fde4e8d 100644
--- a/ios/build/bots/scripts/xcodebuild_runner.py
+++ b/ios/build/bots/scripts/xcodebuild_runner.py
@@ -32,6 +32,12 @@
 from plugin_utils import init_plugins_from_args
 from test_plugin_service import TestPluginServicerWrapper, TestPluginServicer
 
+THIS_DIR = os.path.abspath(os.path.dirname(__file__))
+CHROMIUM_SRC_DIR = os.path.abspath(os.path.join(THIS_DIR, '../../../..'))
+sys.path.append(
+    os.path.abspath(os.path.join(CHROMIUM_SRC_DIR, 'build/util/lib/proto')))
+import measures
+
 LOGGER = logging.getLogger(__name__)
 MAXIMUM_TESTS_PER_SHARD_FOR_RERUN = 20
 XTDEVICE_FOLDER = os.path.expanduser('~/Library/Developer/XCTestDevices')
@@ -177,8 +183,10 @@
     overall_launch_command_result = ResultCollection()
     clones = self.clones
     running_tests = set(self.egtests_app.get_all_tests())
+    attempt_count = measures.count('test_attempts', 'eg')
     # total number of attempts is self.retries+1
     for attempt in range(self.retries + 1):
+      attempt_count.record()
       # Cleanup any running plugin process before each attempt
       if self.test_plugin_service:
         self.test_plugin_service.reset()
diff --git a/ios/build/chrome_build.gni b/ios/build/chrome_build.gni
index 207caa9..818fabd 100644
--- a/ios/build/chrome_build.gni
+++ b/ios/build/chrome_build.gni
@@ -47,6 +47,10 @@
   # Overridden when using the Google-internal repository to build Chrome on iOS.
   ios_account_verification_provider_target = "//ios/chrome/credential_provider_extension:account_verification_provider_implementation"
 
+  # Label of the target providing implementation for PasskeyKeychainProvider.
+  # Overridden when using the Google-internal repository to build Chrome on iOS.
+  ios_passkey_keychain_provider_target = "//ios/chrome/credential_provider_extension:passkey_keychain_provider_implementation"
+
   # Label of the target providing implementation for the PushNotificationServiceExtension.
   # Overridden when using the Google-internal repository to build Chrome on iOS.
   ios_push_notification_service_extension_target = "//ios/chrome/push_notification_service_extension:push_notification_service_extension_implementation"
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index b32498b..1b362bb 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -6375,6 +6375,9 @@
       <message name="IDS_IOS_MANUAL_FALLBACK_CVC_CHIP_ACCESSIBILITY_LABEL" desc="Accessibility label for the CVC chip button displayed in the payment method manual fallback screen and that's allowing the user to autofill a specific form field with their payment method's CVC.">
         Autofill the CVC
       </message>
+      <message name="IDS_IOS_CONTENT_CONTEXT_OPENMANAGEINNEWTAB" desc="The iOS menu item for managing a selected item. [iOS only]">
+        Manage
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_OPENMANAGEINNEWTAB.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_OPENMANAGEINNEWTAB.png.sha1
new file mode 100644
index 0000000..ed17170e
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_OPENMANAGEINNEWTAB.png.sha1
@@ -0,0 +1 @@
+422a432dc413c94d0c7ea69da1a685ccb8c863ba
\ No newline at end of file
diff --git a/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm b/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm
index f898868..a8a26c1e 100644
--- a/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm
+++ b/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm
@@ -95,6 +95,11 @@
 
 void AutofillBottomSheetTabHelper::SetAutofillBottomSheetHandler(
     id<AutofillCommands> commands_handler) {
+  if (!commands_handler) {
+    // Means that the web state has been destroyed therefore dismiss the edit
+    // address bottom sheet if it's shown.
+    [commands_handler_ dismissEditAddressBottomSheet];
+  }
   commands_handler_ = commands_handler;
 }
 
diff --git a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm
index d8bf2c0..b417d3e2 100644
--- a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm
@@ -474,7 +474,7 @@
 
   // Close the context menu.
   [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::NavigationBarCancelButton()]
+      selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
       performAction:grey_tap()];
 
   // Reopen the bottom sheet.
diff --git a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_view_controller.mm b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_view_controller.mm
index 5f0b898..448b9a1 100644
--- a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_view_controller.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_view_controller.mm
@@ -116,6 +116,12 @@
   [super viewDidLoad];
 
   [self adjustTransactionsPrimaryActionButtonHorizontalConstraints];
+
+  if (@available(iOS 17, *)) {
+    [self registerForTraitChanges:TraitCollectionSetForTraits(
+                                      @[ UITraitUserInterfaceStyle.self ])
+                       withAction:@selector(resizeLogoOnTraitChange)];
+  }
 }
 
 - (void)viewDidAppear:(BOOL)animated {
@@ -124,15 +130,19 @@
                                   self.imageViewAccessibilityLabel);
 }
 
+#if !defined(__IPHONE_17_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_17_0
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
   [super traitCollectionDidChange:previousTraitCollection];
+  if (@available(iOS 17, *)) {
+    return;
+  }
 
   if (self.traitCollection.userInterfaceStyle !=
       previousTraitCollection.userInterfaceStyle) {
-    // Make sure the GPay logo matches the new trait collection.
-    self.image = [self titleImage];
+    [self resizeLogoOnTraitChange];
   }
 }
+#endif
 
 - (void)viewDidDisappear:(BOOL)animated {
   [super viewDidDisappear:animated];
@@ -401,6 +411,11 @@
   return cell;
 }
 
+// Resizes the GPay logo to match the new trait collection.
+- (void)resizeLogoOnTraitChange {
+  self.image = [self titleImage];
+}
+
 #pragma mark - ConfirmationAlertViewController
 
 - (void)customizeSubtitle:(UITextView*)subtitle {
diff --git a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/DEPS b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/DEPS
index a8bd3a0b5..43bca6e 100644
--- a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/DEPS
+++ b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/DEPS
@@ -2,4 +2,4 @@
   "+ios/chrome/browser/default_browser/model/default_browser_interest_signals.h",
   "+ios/chrome/browser/feature_engagement/model/tracker_factory.h",
   "+ios/chrome/browser/ui/toolbar/public/toolbar_utils.h",
-]
\ No newline at end of file
+]
diff --git a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm
index a611961..d80a6cb 100644
--- a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm
@@ -30,6 +30,7 @@
 #import "components/password_manager/core/browser/ui/credential_ui_entry.h"
 #import "components/password_manager/core/common/password_manager_features.h"
 #import "components/password_manager/ios/password_generation_provider.h"
+#import "components/plus_addresses/features.h"
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.h"
 #import "ios/chrome/browser/autofill/model/personal_data_manager_factory.h"
@@ -563,6 +564,11 @@
   [self stopManualFillAllPlusAddressCoordinator];
 }
 
+- (void)dismissManualFillAllPlusAddressAndOpenManagePlusAddress {
+  [self stopManualFillAllPlusAddressCoordinator];
+  [self openManagePlusAddress];
+}
+
 #pragma mark - CardCoordinatorDelegate
 
 - (void)cardCoordinatorDidTriggerOpenCardSettings:
@@ -660,6 +666,16 @@
   [_allPlusAddressCoordinator start];
 }
 
+- (void)openManagePlusAddress {
+  OpenNewTabCommand* command = [OpenNewTabCommand
+      commandWithURLFromChrome:
+          GURL(plus_addresses::features::kPlusAddressManagementUrl.Get())];
+
+  id<ApplicationCommands> applicationHandler = HandlerForProtocol(
+      self.browser->GetCommandDispatcher(), ApplicationCommands);
+  [applicationHandler openURLInNewTab:command];
+}
+
 #pragma mark - ExpandedManualFillCoordinatorDelegate
 
 - (void)stopExpandedManualFillCoordinator:
diff --git a/ios/chrome/browser/autofill/ui_bundled/ios_chrome_payments_autofill_client_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/ios_chrome_payments_autofill_client_unittest.mm
index b497b94..7e0221b1 100644
--- a/ios/chrome/browser/autofill/ui_bundled/ios_chrome_payments_autofill_client_unittest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/ios_chrome_payments_autofill_client_unittest.mm
@@ -77,6 +77,9 @@
 - (void)showEditAddressBottomSheet {
 }
 
+- (void)dismissEditAddressBottomSheet {
+}
+
 - (void)showAutofillErrorDialog:
     (autofill::AutofillErrorDialogContext)errorContext {
   _errorContext = std::move(errorContext);
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_coordinator.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_coordinator.mm
index ed04dbf..88fe7a0 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_coordinator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_coordinator.mm
@@ -132,4 +132,11 @@
   }];
 }
 
+- (void)openManagePlusAddress {
+  __weak __typeof(self) weakSelf = self;
+  [self dismissIfNecessaryThenDoCompletion:^{
+    [weakSelf.delegate openManagePlusAddress];
+  }];
+}
+
 @end
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm
index b53172d..4181499 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm
@@ -651,8 +651,8 @@
       selectElementWithMatcher:manual_fill::ManagePaymentMethodsMatcher()]
       performAction:grey_tap()];
 
-  // Tap Cancel Button.
-  [[EarlGrey selectElementWithMatcher:NavigationBarCancelButton()]
+  // Tap the "Done" button to dismiss the view.
+  [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
       performAction:grey_tap()];
 
   // TODO(crbug.com/332956674): Keyboard and keyboard accessory are not present
@@ -1187,8 +1187,8 @@
                                           AutofillCreditCardEditTableView()]
       assertWithMatcher:grey_sufficientlyVisible()];
 
-  // Tap Cancel Button.
-  [[EarlGrey selectElementWithMatcher:NavigationBarCancelButton()]
+  // Tap the "Done" button to dismiss the view.
+  [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
       performAction:grey_tap()];
 
   [FormInputAccessoryAppInterface removeMockReauthenticationModule];
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.h b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.h
index 0161c03f..ef87526 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.h
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.h
@@ -16,6 +16,10 @@
 - (void)manualFillAllPlusAddressCoordinatorWantsToBeDismissed:
     (ManualFillAllPlusAddressCoordinator*)coordinator;
 
+// Requests the delegate to dismiss the coordinator and then open the manage
+// plus address view.
+- (void)dismissManualFillAllPlusAddressAndOpenManagePlusAddress;
+
 @end
 
 // Creates and manages a view controller to present all the plus addresses. The
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.mm
index fdabcc1..414ccd3 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_coordinator.mm
@@ -8,6 +8,7 @@
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_all_plus_address_view_controller.h"
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_injection_handler.h"
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_list_navigator.h"
 #import "ios/chrome/browser/favicon/model/favicon_loader.h"
 #import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
 #import "ios/chrome/browser/plus_addresses/model/plus_address_service_factory.h"
@@ -20,6 +21,7 @@
 @interface ManualFillAllPlusAddressCoordinator () <
     ManualFillAllPlusAddressViewControllerDelegate,
     ManualFillPlusAddressMediatorDelegate,
+    PlusAddressListNavigator,
     UIAdaptivePresentationControllerDelegate>
 @end
 
@@ -66,6 +68,7 @@
   _plusAddressMediator.delegate = self;
 
   _plusAddressMediator.consumer = _plusAddressViewController;
+  _plusAddressMediator.navigator = self;
 
   _plusAddressViewController.imageDataSource = _plusAddressMediator;
 
@@ -116,4 +119,19 @@
       manualFillAllPlusAddressCoordinatorWantsToBeDismissed:self];
 }
 
+#pragma mark - PlusAddressListNavigator
+
+- (void)openCreatePlusAddressSheet {
+  NOTREACHED_NORETURN();
+}
+
+- (void)openAllPlusAddressList {
+  NOTREACHED_NORETURN();
+}
+
+- (void)openManagePlusAddress {
+  [self.manualFillAllPlusAddressCoordinatorDelegate
+          dismissManualFillAllPlusAddressAndOpenManagePlusAddress];
+}
+
 @end
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h
index a111989..518ade9 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h
@@ -80,6 +80,9 @@
 // Accessibility identifier for the select plus address action.
 extern NSString* const kSelectPlusAddressAccessibilityIdentifier;
 
+// Accessibility identifier for the overflow menu in plus address cell.
+extern NSString* const kExpandedManualFillPlusAddressOverflowMenuID;
+
 // Accessibility Identifier for the done button in the select plus address
 // sheet.
 extern NSString* const kPlusAddressDoneButtonAccessibilityIdentifier;
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.mm
index b5feede..8d504fc 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.mm
@@ -72,6 +72,9 @@
 NSString* const kSelectPlusAddressAccessibilityIdentifier =
     @"SelectPlusAddressAccessibilityIdentifier";
 
+NSString* const kExpandedManualFillPlusAddressOverflowMenuID =
+    @"ExpandedManualFillPlusAddressOverflowMenuID";
+
 NSString* const kPlusAddressDoneButtonAccessibilityIdentifier =
     @"PlusAddressDoneButtonAccessibilityIdentifier";
 
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_password_coordinator.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_password_coordinator.mm
index 9c0506f..555936b8 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_password_coordinator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_password_coordinator.mm
@@ -175,4 +175,11 @@
   }];
 }
 
+- (void)openManagePlusAddress {
+  __weak __typeof(self) weakSelf = self;
+  [self dismissIfNecessaryThenDoCompletion:^{
+    [weakSelf.delegate openManagePlusAddress];
+  }];
+}
+
 @end
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_cell.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_cell.mm
index f8f19bcd..5db1e77 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_cell.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_cell.mm
@@ -7,6 +7,7 @@
 #import "base/metrics/user_metrics.h"
 #import "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_cell_utils.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h"
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_content_injector.h"
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address.h"
 #import "ios/chrome/browser/favicon/model/favicon_loader.h"
@@ -263,6 +264,12 @@
 
   self.siteNameLabel = CreateLabel();
   self.overflowMenuButton = CreateOverflowMenuButton();
+  // In the tests, the overflow menu of the chips for the other data types, can
+  // have the same accessibility identifier, therefore, override for the plus
+  // address ones to distinguish them.
+  self.overflowMenuButton.accessibilityIdentifier =
+      manual_fill::kExpandedManualFillPlusAddressOverflowMenuID;
+
   self.headerView = CreateHeaderView(self.faviconView, self.siteNameLabel,
                                      self.overflowMenuButton);
   [self.contentView addSubview:self.headerView];
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.mm
index 3586268..15061b7f 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.mm
@@ -19,6 +19,8 @@
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_list_navigator.h"
 #import "ios/chrome/browser/favicon/model/favicon_loader.h"
 #import "ios/chrome/browser/net/model/crurl.h"
+#import "ios/chrome/browser/shared/public/features/features.h"
+#import "ios/chrome/browser/ui/menu/browser_action_factory.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #import "ui/base/l10n/l10n_util.h"
@@ -199,6 +201,10 @@
   NSMutableArray* items =
       [[NSMutableArray alloc] initWithCapacity:plusAddressesCount];
 
+  NSArray<UIAction*>* menuActions = IsKeyboardAccessoryUpgradeEnabled()
+                                        ? @[ [self createManageMenuAction] ]
+                                        : @[];
+
   for (int i = 0; i < plusAddressesCount; i++) {
     NSString* cellIndexAccessibilityLabel = base::SysUTF16ToNSString(
         base::i18n::MessageFormatter::FormatWithNamedArgs(
@@ -208,7 +214,7 @@
     ManualFillPlusAddressItem* item = [[ManualFillPlusAddressItem alloc]
                 initWithPlusAddress:plusAddresses[i]
                     contentInjector:self
-                        menuActions:@[]
+                        menuActions:menuActions
         cellIndexAccessibilityLabel:cellIndexAccessibilityLabel];
     [items addObject:item];
   }
@@ -263,6 +269,8 @@
   NSMutableArray<ManualFillActionItem*>* actions =
       [[NSMutableArray alloc] init];
 
+  __weak __typeof(self) weakSelf = self;
+
   // Offer manage action if there are any plus addresses for the domain.
   if (hasPlusAddresses) {
     NSString* managePlusAddressesTitle = l10n_util::GetNSString(
@@ -272,13 +280,13 @@
                action:^{
                  base::RecordAction(base::UserMetricsAction(
                      "ManualFallback_PlusAddress_OpenManagePlusAddress"));
+                 [weakSelf.navigator openManagePlusAddress];
                }];
     managePlusAddressItem.accessibilityIdentifier =
         manual_fill::kManagePlusAddressAccessibilityIdentifier;
     [actions addObject:managePlusAddressItem];
   }
 
-  __weak __typeof(self) weakSelf = self;
   // Offer plus address creation if it's supported for the current user session
   // and if the user doesn't have any plus addresses created for the current
   // domain.
@@ -321,4 +329,19 @@
   }
 }
 
+// Creates a "Manage" UIAction to be used with a UIMenu. Tapping on it, would
+// open the manage view for the plus address.
+- (UIAction*)createManageMenuAction {
+  ActionFactory* actionFactory = [[ActionFactory alloc]
+      initWithScenario:
+          kMenuScenarioHistogramAutofillManualFallbackPlusAddressEntry];
+
+  __weak __typeof(self) weakSelf = self;
+  UIAction* manageAction = [actionFactory actionToManageLinkInNewTabWithBlock:^{
+    [weakSelf.navigator openManagePlusAddress];
+  }];
+
+  return manageAction;
+}
+
 @end
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_coordinator_delegate.h b/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_coordinator_delegate.h
index 2bf9d7a..7ce5aee 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_coordinator_delegate.h
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_coordinator_delegate.h
@@ -14,6 +14,9 @@
 // Opens the all plus addresses picker.
 - (void)openAllPlusAddressesPicker;
 
+// Opens the manage page address page in a new tab.
+- (void)openManagePlusAddress;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_AUTOFILL_UI_BUNDLED_MANUAL_FILL_PLUS_ADDRESS_COORDINATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_list_navigator.h b/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_list_navigator.h
index 3666ba8..4c499cb 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_list_navigator.h
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_list_navigator.h
@@ -14,6 +14,9 @@
 // Requests to open the list of all plus addresses.
 - (void)openAllPlusAddressList;
 
+// Requests to open the manage plus address page.
+- (void)openManagePlusAddress;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_AUTOFILL_UI_BUNDLED_MANUAL_FILL_PLUS_ADDRESS_LIST_NAVIGATOR_H_
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_manual_fill_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_manual_fill_egtest.mm
index 7397414..e08c60f3 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_manual_fill_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/plus_address_manual_fill_egtest.mm
@@ -19,6 +19,7 @@
 #import "ios/chrome/browser/signin/model/fake_system_identity.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h"
+#import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_actions.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
@@ -62,6 +63,22 @@
   [ChromeEarlGrey waitForWebStateContainingText:form_text];
 }
 
+// Matcher for the overflow menu button shown in the cells.
+id<GREYMatcher> OverflowMenuButton() {
+  return grey_allOf(
+      grey_accessibilityID(
+          manual_fill::kExpandedManualFillPlusAddressOverflowMenuID),
+      grey_interactable(), nullptr);
+}
+
+// Matcher for the "Manage" action made available by the overflow menu
+// button.
+id<GREYMatcher> OverflowMenuManageAction() {
+  return grey_allOf(chrome_test_util::ButtonWithAccessibilityLabelId(
+                        IDS_IOS_CONTENT_CONTEXT_OPENMANAGEINNEWTAB),
+                    grey_interactable(), nullptr);
+}
+
 // Returns a matcher for the button to dismiss select plus address in manual
 // fallback.
 id<GREYMatcher> PlusAddressSelectDoneMatcher() {
@@ -222,8 +239,18 @@
   [[EarlGrey
       selectElementWithMatcher:manual_fill::SegmentedControlPasswordTab()]
       performAction:grey_tap()];
+
+  // Take note of how many tabs are open before clicking the manage,
+  // which should simply open a new tab.
+  NSUInteger oldRegularTabCount = [ChromeEarlGrey mainTabCount];
+  NSUInteger oldIncognitoTabCount = [ChromeEarlGrey incognitoTabCount];
+
   [[EarlGrey selectElementWithMatcher:managePlusAddressMatcher]
-      assertWithMatcher:grey_sufficientlyVisible()];
+      performAction:grey_tap()];
+
+  // A new tab should open after tapping the manage action.
+  [ChromeEarlGrey waitForMainTabCount:oldRegularTabCount + 1];
+  [ChromeEarlGrey waitForIncognitoTabCount:oldIncognitoTabCount];
 }
 
 // Tests that tapping on the create plus address action in the address manual
@@ -387,4 +414,76 @@
   [self verifyFieldHasBeenFilledWithValue:u"plus+foo@plus.plus"];
 }
 
+// Tests that for the plus address manual fallback suggestion, in the overflow
+// menu, there is an option to manage the plus address.
+- (void)testOverflowMenuManageActionInAddressManualFillMenu {
+  if ([ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_SKIPPED(@"Test fails for iPad");
+  }
+
+  // Open the expanded manual fill view for an address field.
+  [self openExpandedManualFillViewForDataType:ManualFillDataType::kAddress
+                                  fieldToFill:kNameFieldID];
+
+  [[EarlGrey
+      selectElementWithMatcher:
+          manual_fill::ChipButton(
+              plus_addresses::FakePlusAddressService::kFakePlusAddress16)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Tap the overflow menu button.
+  [[EarlGrey selectElementWithMatcher:OverflowMenuButton()]
+      performAction:grey_tap()];
+
+  // Take note of how many tabs are open before clicking the manage,
+  // which should simply open a new tab.
+  NSUInteger oldRegularTabCount = [ChromeEarlGrey mainTabCount];
+  NSUInteger oldIncognitoTabCount = [ChromeEarlGrey incognitoTabCount];
+
+  [[EarlGrey selectElementWithMatcher:OverflowMenuManageAction()]
+      performAction:grey_tap()];
+
+  // A new tab should open after tapping the manage action.
+  [ChromeEarlGrey waitForMainTabCount:oldRegularTabCount + 1];
+  [ChromeEarlGrey waitForIncognitoTabCount:oldIncognitoTabCount];
+}
+
+// Tests that the "Manage" action in the overflow menu is displayed in the
+// select plus address view.
+- (void)testOverflowMenuManageActionInSelectPlusAddressView {
+  if ([ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_SKIPPED(@"Test fails for iPad");
+  }
+
+  [PlusAddressAppInterface setPlusAddressFillingEnabled:YES];
+  [PlusAddressAppInterface addPlusAddressProfile];
+
+  [self openExpandedManualFillViewForDataType:ManualFillDataType::kAddress
+                                  fieldToFill:kNameFieldID];
+  id<GREYMatcher> selectPlusAddressMatcher = grey_accessibilityID(
+      manual_fill::kSelectPlusAddressAccessibilityIdentifier);
+
+  [[EarlGrey selectElementWithMatcher:manual_fill::ProfilesTableViewMatcher()]
+      performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)];
+
+  [[EarlGrey selectElementWithMatcher:selectPlusAddressMatcher]
+      performAction:grey_tap()];
+
+  // Tap the overflow menu button.
+  [[EarlGrey selectElementWithMatcher:OverflowMenuButton()]
+      performAction:grey_tap()];
+
+  // Take note of how many tabs are open before clicking the manage,
+  // which should simply open a new tab.
+  NSUInteger oldRegularTabCount = [ChromeEarlGrey mainTabCount];
+  NSUInteger oldIncognitoTabCount = [ChromeEarlGrey incognitoTabCount];
+
+  [[EarlGrey selectElementWithMatcher:OverflowMenuManageAction()]
+      performAction:grey_tap()];
+
+  // A new tab should open after tapping the manage action.
+  [ChromeEarlGrey waitForMainTabCount:oldRegularTabCount + 1];
+  [ChromeEarlGrey waitForIncognitoTabCount:oldIncognitoTabCount];
+}
+
 @end
diff --git a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm
index 0a8640b..ae725ae 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm
+++ b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm
@@ -1519,9 +1519,8 @@
   _quickDeleteCoordinator = nil;
 
   [self hideDriveFilePicker];
-
   [self hideContextualSheet];
-
+  [self dismissEditAddressBottomSheet];
   [self dismissLensPromo];
 }
 
@@ -1847,6 +1846,14 @@
   [self.autofillEditProfileBottomSheetCoordinator start];
 }
 
+- (void)dismissEditAddressBottomSheet {
+  if (self.autofillEditProfileBottomSheetCoordinator) {
+    [self.autofillEditProfileBottomSheetCoordinator stop];
+  }
+
+  self.autofillEditProfileBottomSheetCoordinator = nil;
+}
+
 - (void)showAutofillErrorDialog:
     (autofill::AutofillErrorDialogContext)errorContext {
   if (self.autofillErrorDialogCoordinator) {
diff --git a/ios/chrome/browser/bubble/ui_bundled/gesture_iph/gesture_in_product_help_view.mm b/ios/chrome/browser/bubble/ui_bundled/gesture_iph/gesture_in_product_help_view.mm
index 9d750e16d..6309d60 100644
--- a/ios/chrome/browser/bubble/ui_bundled/gesture_iph/gesture_in_product_help_view.mm
+++ b/ios/chrome/browser/bubble/ui_bundled/gesture_iph/gesture_in_product_help_view.mm
@@ -342,6 +342,17 @@
     self.alpha = 0;
     self.isAccessibilityElement = YES;
     self.accessibilityViewIsModal = YES;
+
+    if (@available(iOS 17, *)) {
+      __weak __typeof(self) weakSelf = self;
+      NSArray<UITrait>* traits =
+          (@[ UITraitHorizontalSizeClass.self, UITraitVerticalSizeClass.self ]);
+      UITraitChangeHandler handler = ^(id<UITraitEnvironment> traitEnvironment,
+                                       UITraitCollection* previousCollection) {
+        [weakSelf pauseAnimationOnTraitChange:previousCollection];
+      };
+      [self registerForTraitChanges:traits withHandler:handler];
+    }
   }
   return self;
 }
@@ -402,14 +413,16 @@
                     MAX(min_height, targetSize.height));
 }
 
+#if !defined(__IPHONE_17_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_17_0
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
   [super traitCollectionDidChange:previousTraitCollection];
-  if (ShouldGestureIndicatorOffsetFromCenter(previousTraitCollection) !=
-      ShouldGestureIndicatorOffsetFromCenter(self.traitCollection)) {
-    [_animator pauseAnimation];
-    _needsRepositionBubbleAndGestureIndicator = YES;
+  if (@available(iOS 17, *)) {
+    return;
   }
+
+  [self pauseAnimationOnTraitChange:previousTraitCollection];
 }
+#endif
 
 - (void)layoutSubviews {
   [super layoutSubviews];
@@ -730,6 +743,17 @@
       }];
 }
 
+// Pauses the animation if there is a change to the gesture indicator's offset
+// position after a change to the view's trait collection.
+- (void)pauseAnimationOnTraitChange:
+    (UITraitCollection*)previousTraitCollection {
+  if (ShouldGestureIndicatorOffsetFromCenter(previousTraitCollection) !=
+      ShouldGestureIndicatorOffsetFromCenter(self.traitCollection)) {
+    [_animator pauseAnimation];
+    _needsRepositionBubbleAndGestureIndicator = YES;
+  }
+}
+
 @end
 
 @implementation GestureInProductHelpView (Subclassing)
diff --git a/ios/chrome/browser/drive/model/BUILD.gn b/ios/chrome/browser/drive/model/BUILD.gn
index 564ac6f..7b6b261 100644
--- a/ios/chrome/browser/drive/model/BUILD.gn
+++ b/ios/chrome/browser/drive/model/BUILD.gn
@@ -152,6 +152,8 @@
 source_set("test_support") {
   testonly = true
   sources = [
+    "test_drive_file_downloader.h",
+    "test_drive_file_downloader.mm",
     "test_drive_file_uploader.h",
     "test_drive_file_uploader.mm",
     "test_drive_list.h",
@@ -160,6 +162,7 @@
     "test_drive_service.mm",
   ]
   public_deps = [
+    ":drive_file_downloader",
     ":drive_file_uploader",
     ":drive_list",
     ":drive_service",
diff --git a/ios/chrome/browser/drive/model/test_drive_file_downloader.h b/ios/chrome/browser/drive/model/test_drive_file_downloader.h
new file mode 100644
index 0000000..669acb96
--- /dev/null
+++ b/ios/chrome/browser/drive/model/test_drive_file_downloader.h
@@ -0,0 +1,54 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DRIVE_MODEL_TEST_DRIVE_FILE_DOWNLOADER_H_
+#define IOS_CHROME_BROWSER_DRIVE_MODEL_TEST_DRIVE_FILE_DOWNLOADER_H_
+
+#import "base/functional/callback_helpers.h"
+#import "ios/chrome/browser/drive/model/drive_file_downloader.h"
+
+// Test implementation for `DriveFileDownloader`.
+class TestDriveFileDownloader final : public DriveFileDownloader {
+ public:
+  explicit TestDriveFileDownloader(id<SystemIdentity> identity);
+  ~TestDriveFileDownloader() final;
+
+  // Set quit closures.
+  void SetDownloadFileCompletionQuitClosure(
+      base::RepeatingClosure quit_closure);
+
+  // DriveFileDownloader implementation
+  id<SystemIdentity> GetIdentity() const final;
+  bool IsExecutingDownload(DriveFileDownloadID download_id) const final;
+  void CancelDownload(DriveFileDownloadID download_id) final;
+  DriveFileDownloadID DownloadFile(
+      const DriveItem& item_to_download,
+      NSURL* file_url,
+      DriveFileDownloadProgressCallback progress_callback,
+      DriveFileDownloadCompletionCallback completion_callback) final;
+
+ private:
+  // Calls `completion_callback` with `download_id`, `successful` and `error`.
+  void ReportDownloadFileResult(
+      DriveFileDownloadCompletionCallback completion_callback,
+      DriveFileDownloadID download_id,
+      BOOL successful,
+      NSError* error);
+
+  // Run quit closures.
+  void RunDownloadFileCompletionQuitClosure();
+
+  // Identity returned by `GetIdentity()`.
+  id<SystemIdentity> identity_;
+
+  // Quit closures.
+  base::RepeatingClosure download_file_quit_closure_ = base::DoNothing();
+
+  // Weak pointer factory, for callbacks. Can be used to cancel any pending
+  // tasks by invalidating all weak pointers.
+  base::WeakPtrFactory<TestDriveFileDownloader> callbacks_weak_ptr_factory_{
+      this};
+};
+
+#endif  // IOS_CHROME_BROWSER_DRIVE_MODEL_TEST_DRIVE_FILE_DOWNLOADER_H_
diff --git a/ios/chrome/browser/drive/model/test_drive_file_downloader.mm b/ios/chrome/browser/drive/model/test_drive_file_downloader.mm
new file mode 100644
index 0000000..8e4d074
--- /dev/null
+++ b/ios/chrome/browser/drive/model/test_drive_file_downloader.mm
@@ -0,0 +1,75 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/drive/model/test_drive_file_downloader.h"
+
+#import "base/task/single_thread_task_runner.h"
+
+namespace {
+
+// Time constant used to post delayed tasks and simulate Drive file downloads.
+constexpr base::TimeDelta kTestDriveFileDownloaderTimeConstant =
+    base::Milliseconds(100);
+
+}  // namespace
+
+TestDriveFileDownloader::TestDriveFileDownloader(id<SystemIdentity> identity)
+    : identity_(identity) {}
+
+TestDriveFileDownloader::~TestDriveFileDownloader() = default;
+
+void TestDriveFileDownloader::SetDownloadFileCompletionQuitClosure(
+    base::RepeatingClosure quit_closure) {
+  download_file_quit_closure_ = std::move(quit_closure);
+}
+
+#pragma mark - DriveFileDownloader
+
+id<SystemIdentity> TestDriveFileDownloader::GetIdentity() const {
+  return identity_;
+}
+
+bool TestDriveFileDownloader::IsExecutingDownload(
+    DriveFileDownloadID download_id) const {
+  return callbacks_weak_ptr_factory_.HasWeakPtrs();
+}
+
+void TestDriveFileDownloader::CancelDownload(DriveFileDownloadID download_id) {
+  callbacks_weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+DriveFileDownloadID TestDriveFileDownloader::DownloadFile(
+    const DriveItem& item_to_download,
+    NSURL* file_url,
+    DriveFileDownloadProgressCallback progress_callback,
+    DriveFileDownloadCompletionCallback completion_callback) {
+  // TODO(crbug.com/344812969): Report progress.
+  // Then report result.
+  const auto completion_quit_closure = base::BindRepeating(
+      &TestDriveFileDownloader::RunDownloadFileCompletionQuitClosure,
+      callbacks_weak_ptr_factory_.GetWeakPtr());
+  DriveFileDownloadID download_id = [[NSUUID UUID] UUIDString];
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&TestDriveFileDownloader::ReportDownloadFileResult,
+                     callbacks_weak_ptr_factory_.GetWeakPtr(),
+                     std::move(completion_callback), download_id, true, nil)
+          .Then(completion_quit_closure),
+      kTestDriveFileDownloaderTimeConstant);
+  return download_id;
+}
+
+#pragma mark - Private
+
+void TestDriveFileDownloader::ReportDownloadFileResult(
+    DriveFileDownloadCompletionCallback completion_callback,
+    DriveFileDownloadID download_id,
+    BOOL successful,
+    NSError* error) {
+  std::move(completion_callback).Run(download_id, successful, error);
+}
+
+void TestDriveFileDownloader::RunDownloadFileCompletionQuitClosure() {
+  download_file_quit_closure_.Run();
+}
diff --git a/ios/chrome/browser/drive/model/test_drive_list.h b/ios/chrome/browser/drive/model/test_drive_list.h
index c633168..c01f33b 100644
--- a/ios/chrome/browser/drive/model/test_drive_list.h
+++ b/ios/chrome/browser/drive/model/test_drive_list.h
@@ -17,6 +17,9 @@
   // Returns values reported by callbacks of `DriveList` methods.
   DriveListResult GetDriveListResult() const;
 
+  // Sets DriveListResult to be reported by `ListItems()`.
+  void SetDriveListResult(const DriveListResult& result);
+
   // Set quit closures.
   void SetListItemsCompletionQuitClosure(base::RepeatingClosure quit_closure);
 
diff --git a/ios/chrome/browser/drive/model/test_drive_list.mm b/ios/chrome/browser/drive/model/test_drive_list.mm
index daee589a..1ed160e2 100644
--- a/ios/chrome/browser/drive/model/test_drive_list.mm
+++ b/ios/chrome/browser/drive/model/test_drive_list.mm
@@ -33,6 +33,10 @@
   return result;
 }
 
+void TestDriveList::SetDriveListResult(const DriveListResult& result) {
+  drive_list_result_ = result;
+}
+
 void TestDriveList::SetListItemsCompletionQuitClosure(
     base::RepeatingClosure quit_closure) {
   list_items_completion_quit_closure_ = std::move(quit_closure);
diff --git a/ios/chrome/browser/drive/model/test_drive_service.h b/ios/chrome/browser/drive/model/test_drive_service.h
index c47233d..1ac6476 100644
--- a/ios/chrome/browser/drive/model/test_drive_service.h
+++ b/ios/chrome/browser/drive/model/test_drive_service.h
@@ -14,6 +14,8 @@
   TestDriveService();
   ~TestDriveService() final;
 
+  // Sets file downloader to be returned by `CreateFileDownloader(...)`.
+  void SetFileDownloader(std::unique_ptr<DriveFileDownloader> downloader);
   // Sets file uploader to be returned by `CreateFileUploader(...)`.
   void SetFileUploader(std::unique_ptr<DriveFileUploader> uploader);
   // Sets Drive list object to be returned by `CreateList(...)`.
@@ -29,6 +31,7 @@
   std::string GetSuggestedFolderName() const final;
 
  private:
+  std::unique_ptr<DriveFileDownloader> file_downloader_;
   std::unique_ptr<DriveFileUploader> file_uploader_;
   std::unique_ptr<DriveList> drive_list_;
 };
diff --git a/ios/chrome/browser/drive/model/test_drive_service.mm b/ios/chrome/browser/drive/model/test_drive_service.mm
index b6d7424..9690623 100644
--- a/ios/chrome/browser/drive/model/test_drive_service.mm
+++ b/ios/chrome/browser/drive/model/test_drive_service.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/drive/model/test_drive_service.h"
 
+#import "ios/chrome/browser/drive/model/test_drive_file_downloader.h"
 #import "ios/chrome/browser/drive/model/test_drive_file_uploader.h"
 #import "ios/chrome/browser/drive/model/test_drive_list.h"
 
@@ -14,6 +15,11 @@
 
 #pragma mark - Public
 
+void TestDriveService::SetFileDownloader(
+    std::unique_ptr<DriveFileDownloader> downloader) {
+  file_downloader_ = std::move(downloader);
+}
+
 void TestDriveService::SetFileUploader(
     std::unique_ptr<DriveFileUploader> uploader) {
   file_uploader_ = std::move(uploader);
@@ -40,9 +46,11 @@
 
 std::unique_ptr<DriveFileDownloader> TestDriveService::CreateFileDownloader(
     id<SystemIdentity> identity) {
-  // TODO(crbug.com/344812969): Return a TestDriveList which fakes API requests,
-  // similarly to TestDriveFileUploader.
-  return nullptr;
+  std::unique_ptr<DriveFileDownloader> result = std::move(file_downloader_);
+  if (!result) {
+    result = std::make_unique<TestDriveFileDownloader>(identity);
+  }
+  return result;
 }
 
 std::unique_ptr<DriveList> TestDriveService::CreateList(
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/BUILD.gn b/ios/chrome/browser/drive_file_picker/coordinator/BUILD.gn
index c2e5f3a..eb8bb68 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/BUILD.gn
+++ b/ios/chrome/browser/drive_file_picker/coordinator/BUILD.gn
@@ -6,6 +6,7 @@
   sources = [
     "browse_drive_file_picker_coordinator.h",
     "browse_drive_file_picker_coordinator.mm",
+    "browse_drive_file_picker_coordinator_delegate.h",
     "drive_file_picker_mediator.h",
     "drive_file_picker_mediator.mm",
     "drive_file_picker_mediator_delegate.h",
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.h b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.h
index 7d41d6f1..5e50bd81 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.h
+++ b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.h
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_constants.h"
 #import "ios/chrome/browser/shared/coordinator/chrome_coordinator/chrome_coordinator.h"
 
+@protocol BrowseDriveFilePickerCoordinatorDelegate;
 struct DriveListQuery;
 @protocol SystemIdentity;
 
@@ -19,6 +20,9 @@
 // Coordinator of the Browse Drive file picker.
 @interface BrowseDriveFilePickerCoordinator : ChromeCoordinator
 
+@property(nonatomic, weak) id<BrowseDriveFilePickerCoordinatorDelegate>
+    delegate;
+
 // Creates a coordinator that uses `viewController`, `browser`, `webState` and
 // `folder`.
 - (instancetype)
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.mm b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.mm
index 9af7d836..99b54c5 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.mm
@@ -9,10 +9,12 @@
 #import "ios/chrome/browser/drive/model/drive_list.h"
 #import "ios/chrome/browser/drive/model/drive_service.h"
 #import "ios/chrome/browser/drive/model/drive_service_factory.h"
+#import "ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_delegate.h"
 #import "ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.h"
 #import "ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_delegate.h"
 #import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_navigation_controller.h"
 #import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.h"
+#import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller_delegate.h"
 #import "ios/chrome/browser/drive_file_picker/ui/drive_item_identifier.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
@@ -24,7 +26,10 @@
 #import "ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.h"
 #import "services/network/public/cpp/shared_url_loader_factory.h"
 
-@interface BrowseDriveFilePickerCoordinator () <DriveFilePickerMediatorDelegate>
+@interface BrowseDriveFilePickerCoordinator () <
+    DriveFilePickerMediatorDelegate,
+    DriveFilePickerTableViewControllerDelegate,
+    BrowseDriveFilePickerCoordinatorDelegate>
 
 @end
 
@@ -111,6 +116,7 @@
   _viewController = [[DriveFilePickerTableViewController alloc] init];
   _mediator = [[DriveFilePickerMediator alloc]
            initWithWebState:_webState.get()
+                     isRoot:NO
                    identity:_identity
                       title:_title
                       query:_query
@@ -125,6 +131,7 @@
   id<DriveFilePickerCommands> driveFilePickerHandler = HandlerForProtocol(
       self.browser->GetCommandDispatcher(), DriveFilePickerCommands);
   _viewController.mutator = _mediator;
+  _viewController.delegate = self;
   _mediator.consumer = _viewController;
   _mediator.delegate = self;
   _mediator.driveFilePickerHandler = driveFilePickerHandler;
@@ -133,10 +140,15 @@
 
 - (void)stop {
   [_mediator disconnect];
+  if (![_viewController isMovingFromParentViewController]) {
+    [_viewController.navigationController popToViewController:_viewController
+                                                     animated:NO];
+  }
   [_childBrowseCoordinator stop];
   _childBrowseCoordinator = nil;
   _mediator = nil;
-  [_baseNavigationController popViewControllerAnimated:YES];
+  // The owner of this coordinator should use `popToViewController` to dismiss
+  // this `_viewController`.
   _viewController = nil;
 
   _identity = nil;
@@ -165,7 +177,37 @@
                            sortingCriteria:sortingCriteria
                           sortingDirection:sortingDirection
                                   identity:_identity];
+  _childBrowseCoordinator.delegate = self;
   [_childBrowseCoordinator start];
 }
 
+- (void)mediatorDidSubmitFileSelection:(DriveFilePickerMediator*)mediator {
+  __weak id<DriveFilePickerCommands> driveFilePickerHandler =
+      HandlerForProtocol(self.browser->GetCommandDispatcher(),
+                         DriveFilePickerCommands);
+  [self.baseNavigationController.presentingViewController
+      dismissViewControllerAnimated:YES
+                         completion:^{
+                           [driveFilePickerHandler hideDriveFilePicker];
+                         }];
+}
+
+#pragma mark - DriveFilePickerTableViewControllerDelegate
+
+- (void)viewControllerDidDisappear:(UIViewController*)viewController {
+  [self.delegate coordinatorShouldStop:self];
+}
+
+#pragma mark - BrowseDriveFilePickerCoordinatorDelegate
+
+- (void)coordinatorShouldStop:(ChromeCoordinator*)coordinator {
+  CHECK(coordinator == _childBrowseCoordinator);
+  if (![_viewController isMovingFromParentViewController]) {
+    [_viewController.navigationController popToViewController:_viewController
+                                                     animated:NO];
+  }
+  [_childBrowseCoordinator stop];
+  _childBrowseCoordinator = nil;
+}
+
 @end
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_delegate.h b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_delegate.h
new file mode 100644
index 0000000..d16017e
--- /dev/null
+++ b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_delegate.h
@@ -0,0 +1,17 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DRIVE_FILE_PICKER_COORDINATOR_BROWSE_DRIVE_FILE_PICKER_COORDINATOR_DELEGATE_H_
+#define IOS_CHROME_BROWSER_DRIVE_FILE_PICKER_COORDINATOR_BROWSE_DRIVE_FILE_PICKER_COORDINATOR_DELEGATE_H_
+
+// Protocol for the delegate of a `BrowseDriveFilePickerCoordinator`.
+@protocol BrowseDriveFilePickerCoordinatorDelegate
+
+// Called when the `BrowseDriveFilePickerCoordinator` should be stopped, usually
+// because the associated view controller was dismissed.
+- (void)coordinatorShouldStop:(ChromeCoordinator*)coordinator;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_DRIVE_FILE_PICKER_COORDINATOR_BROWSE_DRIVE_FILE_PICKER_COORDINATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.h b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.h
index a99b247..684675b 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.h
+++ b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.h
@@ -43,6 +43,7 @@
 // Initializes the mediator with a given `webState`.
 - (instancetype)
          initWithWebState:(web::WebState*)webState
+                   isRoot:(BOOL)isRoot
                  identity:(id<SystemIdentity>)identity
                     title:(NSString*)title
                     query:(DriveListQuery)query
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm
index c392fcb2..6364a1e 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm
@@ -299,10 +299,14 @@
   DriveItemsSortingOrder _sortingDirection;
   // The page token to use to continue the current list/search.
   NSString* _pageToken;
+  // Whether this mediator is the root mediator of the file picker, in which
+  // case file selection in the WebState should be stopped when disconnected.
+  BOOL _isRoot;
 }
 
 - (instancetype)
          initWithWebState:(web::WebState*)webState
+                   isRoot:(BOOL)isRoot
                  identity:(id<SystemIdentity>)identity
                     title:(NSString*)title
                     query:(DriveListQuery)query
@@ -320,6 +324,7 @@
     CHECK(identity);
     CHECK(accountManagerService);
     _webState = webState->GetWeakPtr();
+    _isRoot = isRoot;
     _identity = identity;
     _driveService = driveService;
     _accountManagerService = accountManagerService;
@@ -341,19 +346,19 @@
 }
 
 - (void)disconnect {
-  if (_webState) {
+  if (_isRoot && _webState && !_webState->IsBeingDestroyed()) {
     ChooseFileTabHelper* tab_helper =
         ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
     if (tab_helper->IsChoosingFiles()) {
       tab_helper->StopChoosingFiles();
     }
-    _webState = nullptr;
-    _driveService = nullptr;
-    _driveList = nullptr;
-    _driveDownloader = nullptr;
-    _accountManagerService = nullptr;
-    _imageFetcher = nullptr;
   }
+  _webState = nullptr;
+  _driveService = nullptr;
+  _driveList = nullptr;
+  _driveDownloader = nullptr;
+  _accountManagerService = nullptr;
+  _imageFetcher = nullptr;
 }
 
 - (void)setConsumer:(id<DriveFilePickerConsumer>)consumer {
@@ -481,18 +486,19 @@
 }
 
 - (void)submitFileSelection {
-  if (!_webState) {
+  if (!_webState || _webState->IsBeingDestroyed()) {
     [self.driveFilePickerHandler hideDriveFilePicker];
     return;
   }
-
   ChooseFileTabHelper* tab_helper =
       ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
-  if (tab_helper->IsChoosingFiles()) {
-    CHECK(_selectedFileDestinationURL);
-    tab_helper->StopChoosingFiles(@[ _selectedFileDestinationURL ], nil, nil);
+  if (!tab_helper->IsChoosingFiles()) {
+    [self.driveFilePickerHandler hideDriveFilePicker];
+    return;
   }
-  [self.driveFilePickerHandler hideDriveFilePicker];
+  CHECK(_selectedFileDestinationURL);
+  tab_helper->StopChoosingFiles(@[ _selectedFileDestinationURL ], nil, nil);
+  [self.delegate mediatorDidSubmitFileSelection:self];
 }
 
 - (void)setAcceptedTypesIgnored:(BOOL)ignoreAcceptedTypes {
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_delegate.h b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_delegate.h
index 397af04..e4fac695 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_delegate.h
+++ b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_delegate.h
@@ -24,6 +24,9 @@
                          sortingDirection:
                              (DriveItemsSortingOrder)sortingDirection;
 
+// Called when the mediator has submitted file selection to the web page.
+- (void)mediatorDidSubmitFileSelection:(DriveFilePickerMediator*)mediator;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_DRIVE_FILE_PICKER_COORDINATOR_DRIVE_FILE_PICKER_MEDIATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm
index 33b6d12..1977d1a 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm
@@ -10,6 +10,7 @@
 #import "components/image_fetcher/core/image_data_fetcher.h"
 #import "ios/chrome/browser/drive/model/drive_list.h"
 #import "ios/chrome/browser/drive/model/drive_service_factory.h"
+#import "ios/chrome/browser/drive/model/test_drive_file_downloader.h"
 #import "ios/chrome/browser/drive/model/test_drive_list.h"
 #import "ios/chrome/browser/drive/model/test_drive_service.h"
 #import "ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_delegate.h"
@@ -39,6 +40,8 @@
 @property(nonatomic, assign) DriveItemsSortingType sortingCriteria;
 @property(nonatomic, assign) DriveItemsSortingOrder sortingDirection;
 
+@property(nonatomic, assign) BOOL fileSelectionSubmitted;
+
 @end
 
 @implementation FakeDriveFilePickerMediatorDelegate
@@ -60,15 +63,18 @@
   self.sortingDirection = sortingDirection;
 }
 
+- (void)mediatorDidSubmitFileSelection:(DriveFilePickerMediator*)mediator {
+  self.fileSelectionSubmitted = YES;
+}
+
 @end
 
 // Fake consumer for `DriveFilePickerMediator`.
 @interface FakeDriveFilePickerConsumer : NSObject <DriveFilePickerConsumer>
 
+@property(nonatomic, assign) DriveFileDownloadStatus downloadStatus;
 @property(nonatomic, assign) DriveItemsSortingType sortingCriteria;
-
 @property(nonatomic, assign) DriveItemsSortingOrder sortingDirection;
-
 @property(nonatomic, strong) NSArray<DriveItemIdentifier*>* driveItems;
 
 @end
@@ -93,6 +99,7 @@
 }
 
 - (void)setDownloadStatus:(DriveFileDownloadStatus)downloadStatus {
+  _downloadStatus = downloadStatus;
 }
 
 - (void)setEnabledItems:(NSSet<NSString*>*)identifiers {
@@ -129,6 +136,7 @@
     StartChoosingFiles();
     mediator_ = [[DriveFilePickerMediator alloc]
              initWithWebState:web_state_.get()
+                       isRoot:YES
                      identity:[FakeSystemIdentity fakeIdentity1]
                         title:nil
                         query:{}
@@ -154,6 +162,11 @@
         std::make_unique<TestDriveList>([FakeSystemIdentity fakeIdentity1]);
     drive_list_ = drive_list.get();
     GetTestDriveService()->SetDriveList(std::move(drive_list));
+    std::unique_ptr<TestDriveFileDownloader> file_downloader =
+        std::make_unique<TestDriveFileDownloader>(
+            [FakeSystemIdentity fakeIdentity1]);
+    file_downloader_ = file_downloader.get();
+    GetTestDriveService()->SetFileDownloader(std::move(file_downloader));
   }
 
   // Starts file selection in the WebState.
@@ -191,9 +204,10 @@
   FakeDriveFilePickerMediatorDelegate* fake_delegate_;
   FakeDriveFilePickerConsumer* fake_consumer_;
   raw_ptr<TestDriveList> drive_list_;
+  raw_ptr<TestDriveFileDownloader> file_downloader_;
 };
 
-// Tests that disconnecting the mediator stops the file selection.
+// Tests that disconnecting the root mediator stops the file selection.
 TEST_F(DriveFilePickerMediatorTest, StopsChoosingFiles) {
   EXPECT_TRUE(choose_file_tab_helper_->IsChoosingFiles());
   // Disconnect the mediator.
@@ -269,3 +283,40 @@
   EXPECT_NE(nil, fake_consumer_.driveItems);
   fake_consumer_.driveItems = nil;
 }
+
+// Tests that selecting a file and submitting the selection works as expected.
+TEST_F(DriveFilePickerMediatorTest, SubmitFileSelection) {
+  // Set up Drive list to return a downloadable file.
+  DriveItem file_to_select;
+  file_to_select.is_folder = false;
+  file_to_select.can_download = true;
+  file_to_select.identifier = [[NSUUID UUID] UUIDString];
+  file_to_select.name = @"Fake File";
+  DriveListResult fake_result;
+  fake_result.items = {file_to_select};
+  drive_list_->SetDriveListResult(fake_result);
+
+  // Fetch items.
+  drive_list_->SetListItemsCompletionQuitClosure(
+      task_environment_.QuitClosure());
+  [mediator_ fetchNextPage];
+  task_environment_.RunUntilQuit();
+  EXPECT_NE(nil, fake_consumer_.driveItems);
+  EXPECT_EQ(1U, fake_consumer_.driveItems.count);
+  EXPECT_NSEQ(file_to_select.identifier,
+              fake_consumer_.driveItems[0].identifier);
+
+  // Download the file.
+  file_downloader_->SetDownloadFileCompletionQuitClosure(
+      task_environment_.QuitClosure());
+  EXPECT_EQ(DriveFileDownloadStatus::kNotStarted,
+            fake_consumer_.downloadStatus);
+  [mediator_ selectDriveItem:fake_consumer_.driveItems[0]];
+  EXPECT_EQ(DriveFileDownloadStatus::kInProgress,
+            fake_consumer_.downloadStatus);
+  task_environment_.RunUntilQuit();
+  EXPECT_EQ(DriveFileDownloadStatus::kSuccess, fake_consumer_.downloadStatus);
+  EXPECT_FALSE(fake_delegate_.fileSelectionSubmitted);
+  [mediator_ submitFileSelection];
+  EXPECT_TRUE(fake_delegate_.fileSelectionSubmitted);
+}
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator.mm b/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator.mm
index 3d02e60..d2f93db8 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator.mm
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/drive/model/drive_list.h"
 #import "ios/chrome/browser/drive/model/drive_service_factory.h"
 #import "ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator.h"
+#import "ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_delegate.h"
 #import "ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.h"
 #import "ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_delegate.h"
 #import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_navigation_controller.h"
@@ -29,7 +30,8 @@
 
 @interface RootDriveFilePickerCoordinator () <
     UIAdaptivePresentationControllerDelegate,
-    DriveFilePickerMediatorDelegate>
+    DriveFilePickerMediatorDelegate,
+    BrowseDriveFilePickerCoordinatorDelegate>
 
 @end
 
@@ -76,6 +78,7 @@
       initWithRootViewController:_viewController];
   _mediator = [[DriveFilePickerMediator alloc]
            initWithWebState:_webState.get()
+                     isRoot:YES
                    identity:_currentIdentity
                       title:nil
                       query:{}
@@ -116,18 +119,14 @@
 - (void)stop {
   [_mediator disconnect];
   _mediator = nil;
-  [_childBrowseCoordinator stop];
-  _childBrowseCoordinator = nil;
   [_navigationController.presentingViewController
       dismissViewControllerAnimated:NO
                          completion:nil];
+  [_childBrowseCoordinator stop];
+  _childBrowseCoordinator = nil;
   _navigationController = nil;
   _viewController = nil;
   _authenticationService = nil;
-  for (ChromeCoordinator* coordinator in self.childCoordinators) {
-    [coordinator stop];
-  }
-  [self.childCoordinators removeAllObjects];
 }
 
 - (void)setSelectedIdentity:(id<SystemIdentity>)selectedIdentity {
@@ -173,14 +172,31 @@
                            sortingCriteria:sortingCriteria
                           sortingDirection:sortingDirection
                                   identity:_currentIdentity];
+  _childBrowseCoordinator.delegate = self;
   [_childBrowseCoordinator start];
 }
 
-- (void)searchDriveFolderWithMediator:
-            (DriveFilePickerMediator*)driveFilePickerMediator
-                        driveFolderID:(DriveItemIdentifier*)driveFolderID {
-  // TODO(crbug.com/344812548): Start the `SearchDriveFilePickerCoordinator` and
-  // add it as child coordinator.
+- (void)mediatorDidSubmitFileSelection:(DriveFilePickerMediator*)mediator {
+  __weak id<DriveFilePickerCommands> driveFilePickerHandler =
+      HandlerForProtocol(self.browser->GetCommandDispatcher(),
+                         DriveFilePickerCommands);
+  [self.baseNavigationController.presentingViewController
+      dismissViewControllerAnimated:YES
+                         completion:^{
+                           [driveFilePickerHandler hideDriveFilePicker];
+                         }];
+}
+
+#pragma mark - BrowseDriveFilePickerCoordinatorDelegate
+
+- (void)coordinatorShouldStop:(ChromeCoordinator*)coordinator {
+  CHECK(coordinator == _childBrowseCoordinator);
+  if (![_viewController isMovingFromParentViewController]) {
+    [_viewController.navigationController popToViewController:_viewController
+                                                     animated:NO];
+  }
+  [_childBrowseCoordinator stop];
+  _childBrowseCoordinator = nil;
 }
 
 @end
diff --git a/ios/chrome/browser/drive_file_picker/ui/BUILD.gn b/ios/chrome/browser/drive_file_picker/ui/BUILD.gn
index 02bbe62c..d8c9a6b 100644
--- a/ios/chrome/browser/drive_file_picker/ui/BUILD.gn
+++ b/ios/chrome/browser/drive_file_picker/ui/BUILD.gn
@@ -10,6 +10,7 @@
     "drive_file_picker_navigation_controller.mm",
     "drive_file_picker_table_view_controller.h",
     "drive_file_picker_table_view_controller.mm",
+    "drive_file_picker_table_view_controller_delegate.h",
     "drive_item_identifier.h",
     "drive_item_identifier.mm",
     "root_drive_file_picker_table_view_controller.h",
diff --git a/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.h b/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.h
index 5b204cbd..bc9a154d 100644
--- a/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.h
+++ b/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.h
@@ -10,6 +10,7 @@
 
 @protocol DriveFilePickerCommands;
 @protocol DriveFilePickerMutator;
+@protocol DriveFilePickerTableViewControllerDelegate;
 @class DriveItemIdentifier;
 
 // TableViewController presenting a list of Drive files and folders. This should
@@ -21,6 +22,9 @@
 @property(nonatomic, weak) id<DriveFilePickerMutator> mutator;
 // Drive file picker handler.
 @property(nonatomic, weak) id<DriveFilePickerCommands> driveFilePickerHandler;
+// View controller delegate.
+@property(nonatomic, weak) id<DriveFilePickerTableViewControllerDelegate>
+    delegate;
 
 @end
 
diff --git a/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.mm b/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.mm
index a42fcd2..3946708 100644
--- a/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.mm
+++ b/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller.mm
@@ -8,6 +8,7 @@
 #import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_constants.h"
 #import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_mutator.h"
 #import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_navigation_controller.h"
+#import "ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller_delegate.h"
 #import "ios/chrome/browser/drive_file_picker/ui/drive_item_identifier.h"
 #import "ios/chrome/browser/shared/public/commands/drive_file_picker_commands.h"
 #import "ios/chrome/browser/shared/ui/list_model/list_model.h"
@@ -135,6 +136,13 @@
   self.tableView.tableFooterView = _loadingIndicator;
 }
 
+- (void)viewDidDisappear:(BOOL)animated {
+  [super viewDidDisappear:animated];
+  if ([self isMovingFromParentViewController]) {
+    [self.delegate viewControllerDidDisappear:self];
+  }
+}
+
 #pragma mark - DriveFilePickerConsumer
 
 - (void)setSelectedUserIdentityEmail:(NSString*)selectedUserIdentityEmail {
diff --git a/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller_delegate.h b/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller_delegate.h
new file mode 100644
index 0000000..744ae92
--- /dev/null
+++ b/ios/chrome/browser/drive_file_picker/ui/drive_file_picker_table_view_controller_delegate.h
@@ -0,0 +1,16 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DRIVE_FILE_PICKER_UI_DRIVE_FILE_PICKER_TABLE_VIEW_CONTROLLER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_DRIVE_FILE_PICKER_UI_DRIVE_FILE_PICKER_TABLE_VIEW_CONTROLLER_DELEGATE_H_
+
+// Delegate protocol for `DriveFilePickerTableViewController`.
+@protocol DriveFilePickerTableViewControllerDelegate
+
+// Called when the view associated with `viewController` did disappear.
+- (void)viewControllerDidDisappear:(UIViewController*)viewController;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_DRIVE_FILE_PICKER_UI_DRIVE_FILE_PICKER_TABLE_VIEW_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/lens_overlay/coordinator/fake_chrome_lens_overlay.mm b/ios/chrome/browser/lens_overlay/coordinator/fake_chrome_lens_overlay.mm
index 12cf8a3..95790de7 100644
--- a/ios/chrome/browser/lens_overlay/coordinator/fake_chrome_lens_overlay.mm
+++ b/ios/chrome/browser/lens_overlay/coordinator/fake_chrome_lens_overlay.mm
@@ -41,6 +41,10 @@
 
 #pragma mark - ChromeLensOverlay
 
+- (BOOL)isPanningSelectionUI {
+  return NO;
+}
+
 - (void)setQueryText:(NSString*)text clearSelection:(BOOL)clearSelection {
   _currentQueryText = text;
   [self sendNewResult];
diff --git a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm
index c856163..a8c0df1 100644
--- a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm
+++ b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm
@@ -345,9 +345,20 @@
   UISheetPresentationController* sheet =
       base::apple::ObjCCastStrict<UISheetPresentationController>(
           presentationController);
-  return (![sheet.selectedDetentIdentifier
-      isEqualToString:UISheetPresentationControllerDetent.largeDetent
-                          .identifier]);
+  BOOL isInLargestDetent = [sheet.selectedDetentIdentifier
+      isEqualToString:UISheetPresentationControllerDetentIdentifierLarge];
+
+  // If the user is actively adjusting a selection (by moving the selection
+  // frame), it means the sheet dismissal was incidental and shouldn't be
+  // processed. Only when the sheet is directly dragged downwards should the
+  // dismissal intent be considered.
+  BOOL isSelecting = _selectionViewController.isPanningSelectionUI;
+
+  if (isSelecting || isInLargestDetent) {
+    return NO;
+  }
+
+  return YES;
 }
 
 - (void)presentationControllerWillDismiss:
diff --git a/ios/chrome/browser/push_notification/model/push_notification_delegate.mm b/ios/chrome/browser/push_notification/model/push_notification_delegate.mm
index 9c51e87..875890cd 100644
--- a/ios/chrome/browser/push_notification/model/push_notification_delegate.mm
+++ b/ios/chrome/browser/push_notification/model/push_notification_delegate.mm
@@ -240,6 +240,12 @@
       id<SystemIdentity> identity =
           authService->GetPrimaryIdentity(signin::ConsentLevel::kSignin);
       config.primaryAccount = identity;
+      // Send an initial NAU to share the OS auth status and channel status with
+      // the server. Send an NAU on every foreground to report the OS Auth
+      // Settings.
+      ContentNotificationService* contentNotificationService =
+          ContentNotificationServiceFactory::GetForBrowserState(browserState);
+      [self sendSettingsChangeNAUWithService:contentNotificationService];
     }
   }
 
@@ -336,20 +342,7 @@
       }
     }
     // Send an NAU on every foreground to report the OS Auth Settings.
-    [PushNotificationUtil
-        getPermissionSettings:^(UNNotificationSettings* settings) {
-          UNAuthorizationStatus previousAuthStatus =
-              [PushNotificationUtil getSavedPermissionSettings];
-            ContentNotificationNAUConfiguration* config =
-                [[ContentNotificationNAUConfiguration alloc] init];
-            ContentNotificationSettingsAction* settingsAction =
-                [[ContentNotificationSettingsAction alloc] init];
-            settingsAction.previousAuthorizationStatus = previousAuthStatus;
-            settingsAction.currentAuthorizationStatus =
-                settings.authorizationStatus;
-            config.settingsAction = settingsAction;
-            contentNotificationService->SendNAUForConfiguration(config);
-        }];
+    [self sendSettingsChangeNAUWithService:contentNotificationService];
   }
   [PushNotificationUtil
       getPermissionSettings:^(UNNotificationSettings* settings) {
@@ -358,6 +351,24 @@
       }];
 }
 
+- (void)sendSettingsChangeNAUWithService:
+    (ContentNotificationService*)contentNotificationService {
+  [PushNotificationUtil
+      getPermissionSettings:^(UNNotificationSettings* settings) {
+        UNAuthorizationStatus previousAuthStatus =
+            [PushNotificationUtil getSavedPermissionSettings];
+        ContentNotificationNAUConfiguration* config =
+            [[ContentNotificationNAUConfiguration alloc] init];
+        ContentNotificationSettingsAction* settingsAction =
+            [[ContentNotificationSettingsAction alloc] init];
+        settingsAction.previousAuthorizationStatus = previousAuthStatus;
+        settingsAction.currentAuthorizationStatus =
+            settings.authorizationStatus;
+        config.settingsAction = settingsAction;
+        contentNotificationService->SendNAUForConfiguration(config);
+      }];
+}
+
 - (void)recordLifeCycleEvent:(PushNotificationLifecycleEvent)event {
   base::UmaHistogramEnumeration(kLifecycleEventsHistogram, event);
 }
diff --git a/ios/chrome/browser/shared/public/commands/autofill_commands.h b/ios/chrome/browser/shared/public/commands/autofill_commands.h
index 8df2d50..f7e5b9c3 100644
--- a/ios/chrome/browser/shared/public/commands/autofill_commands.h
+++ b/ios/chrome/browser/shared/public/commands/autofill_commands.h
@@ -41,6 +41,10 @@
 // Sends a command to show the bottom sheet to edit an address.
 - (void)showEditAddressBottomSheet;
 
+// Sends a command to stop showing the bottom sheet to edit an address provided
+// it's shown.
+- (void)dismissEditAddressBottomSheet;
+
 // Commands to manage the Autofill error dialog.
 - (void)showAutofillErrorDialog:
     (autofill::AutofillErrorDialogContext)errorContext;
diff --git a/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
index 45df5270..85ba5de 100644
--- a/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
@@ -30,7 +30,6 @@
 #import "components/plus_addresses/webdata/plus_address_webdata_service.h"
 #import "components/reading_list/core/dual_reading_list_model.h"
 #import "components/reading_list/core/reading_list_model.h"
-#import "components/saved_tab_groups/tab_group_sync_service.h"
 #import "components/send_tab_to_self/features.h"
 #import "components/supervised_user/core/browser/supervised_user_settings_service.h"
 #import "components/sync/base/features.h"
@@ -215,6 +214,11 @@
   builder.SetSupervisedUserSettingsService(
       SupervisedUserSettingsServiceFactory::GetForBrowserState(browser_state_));
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
+  builder.SetTabGroupSyncService(
+      IsTabGroupSyncEnabled()
+          ? tab_groups::TabGroupSyncServiceFactory::GetForBrowserState(
+                browser_state_)
+          : nullptr);
   builder.SetTemplateURLService(nullptr);
   builder.SetUserEventService(
       IOSUserEventServiceFactory::GetForBrowserState(browser_state_));
@@ -222,23 +226,6 @@
   syncer::DataTypeController::TypeVector controllers = builder.Build(
       /*disabled_types=*/{}, sync_service, ::GetChannel());
 
-  if (IsTabGroupSyncEnabled()) {
-    syncer::DataTypeControllerDelegate* delegate =
-        tab_groups::TabGroupSyncServiceFactory::GetForBrowserState(
-            browser_state_)
-            ->GetSavedTabGroupControllerDelegate()
-            .get();
-    // TODO(crbug.com/344893270): Move this controller to
-    // CreateCommonDataTypeControllers().
-    controllers.push_back(std::make_unique<syncer::DataTypeController>(
-        syncer::SAVED_TAB_GROUP, /*delegate_for_full_sync_mode=*/
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            delegate),
-        /*delegate_for_transport_mode=*/
-        std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
-            delegate)));
-  }
-
   return controllers;
 }
 
diff --git a/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_mediator.mm b/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_mediator.mm
index a4c0bc9f..f8a42800 100644
--- a/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_mediator.mm
@@ -104,6 +104,24 @@
   return nullptr;
 }
 
+// Helper function to extract history data from url aggregate.
+const visited_url_ranking::URLVisitAggregate::HistoryData* ExtractHistoryData(
+    visited_url_ranking::URLVisitAggregate& url_aggregate) {
+  const auto& history_iterator = url_aggregate.fetcher_data_map.find(
+      visited_url_ranking::Fetcher::kHistory);
+  if (history_iterator != url_aggregate.fetcher_data_map.end()) {
+    const visited_url_ranking::URLVisitAggregate::URLVisitVariant&
+        url_visit_variant = history_iterator->second;
+    const visited_url_ranking::URLVisitAggregate::HistoryData* history_data =
+        std::get_if<visited_url_ranking::URLVisitAggregate::HistoryData>(
+            &url_visit_variant);
+    if (history_data) {
+      return history_data;
+    }
+  }
+  return nullptr;
+}
+
 // Whether the item should be displayed immediately (before fetching an image).
 bool ShouldShowItemImmediately() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -738,7 +756,7 @@
   size_t index;
   // Select the first URL with tab data.
   for (index = 0; index < URLs.size(); index++) {
-    if (ExtractTabData(URLs[index])) {
+    if (ExtractTabData(URLs[index]) || ExtractHistoryData(URLs[index])) {
       break;
     }
   }
@@ -768,32 +786,44 @@
     return;
   }
   const visited_url_ranking::URLVisitAggregate::TabData* tabData = nullptr;
+  const visited_url_ranking::URLVisitAggregate::HistoryData* historyData =
+      nullptr;
+  const visited_url_ranking::URLVisit* visit = nullptr;
+
   const visited_url_ranking::URLVisitAggregate* URLAggregate = nullptr;
   for (auto& aggregate : URLs) {
     tabData = ExtractTabData(aggregate);
     if (tabData) {
       URLAggregate = &aggregate;
+      visit = &tabData->last_active_tab.visit;
+      break;
+    }
+    historyData = ExtractHistoryData(aggregate);
+    if (historyData) {
+      URLAggregate = &aggregate;
+      visit = &historyData->visit;
       break;
     }
   }
-  if (!tabData || !URLAggregate) {
+  if (!URLAggregate || !visit) {
     return;
   }
-  const visited_url_ranking::URLVisitAggregate::Tab& tab =
-      tabData->last_active_tab;
 
   bool isLocal =
-      tab.visit.source == visited_url_ranking::URLVisit::Source::kLocal;
+      visit->source != visited_url_ranking::URLVisit::Source::kForeign;
   TabResumptionItemType type =
       (isLocal ? TabResumptionItemType::kMostRecentTab
                : TabResumptionItemType::kLastSyncedTab);
   TabResumptionItem* item = [[TabResumptionItem alloc] initWithItemType:type];
-  item.tabTitle = base::SysUTF16ToNSString(tab.visit.title);
-  item.syncedTime = tab.visit.last_modified;
-  item.tabURL = tab.visit.url;
+  item.tabTitle = base::SysUTF16ToNSString(visit->title);
+  item.syncedTime = visit->last_modified;
+  item.tabURL = visit->url;
   item.shouldShowSeeMore = IsTabResumption1_5SeeMoreEnabled();
   item.URLKey = URLAggregate->url_key;
   item.requestID = URLAggregate->request_id;
+  if (visit->client_name) {
+    item.sessionName = base::SysUTF8ToNSString(visit->client_name.value());
+  }
   item.commandHandler = self;
   item.delegate = self;
   if (IsTabResumption2BubbleEnabled()) {
@@ -803,10 +833,14 @@
               .GetDisplayString());
     }
   }
-  if (tab.id > 0 && tab.session_tag && !isLocal) {
-    item.sessionName = base::SysUTF8ToNSString(tab.session_name.value());
-    _sessionTag = tab.session_tag.value();
-    _tabId = SessionID::FromSerializedValue(tab.id);
+  if (tabData) {
+    const visited_url_ranking::URLVisitAggregate::Tab& tab =
+        tabData->last_active_tab;
+    if (tab.id > 0 && tab.session_tag && !isLocal) {
+      item.sessionName = base::SysUTF8ToNSString(tab.session_name.value());
+      _sessionTag = tab.session_tag.value();
+      _tabId = SessionID::FromSerializedValue(tab.id);
+    }
   }
 
   // Fetch the favicon.
diff --git a/ios/chrome/browser/ui/menu/action_factory.h b/ios/chrome/browser/ui/menu/action_factory.h
index 6562522..08ab1eb 100644
--- a/ios/chrome/browser/ui/menu/action_factory.h
+++ b/ios/chrome/browser/ui/menu/action_factory.h
@@ -222,6 +222,10 @@
 // Creates a UIAction instance to add an account to choose drive files from.
 - (UIAction*)actionToAddAccountForDriveWithBlock:(ProceduralBlock)block;
 
+// Creates a UIAction instance whose title and icon are configured for showing
+// manage in a new tab, which will invoke the given `block` when executed.
+- (UIAction*)actionToManageLinkInNewTabWithBlock:(ProceduralBlock)block;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_ACTION_FACTORY_H_
diff --git a/ios/chrome/browser/ui/menu/action_factory.mm b/ios/chrome/browser/ui/menu/action_factory.mm
index b44befd..64235d5 100644
--- a/ios/chrome/browser/ui/menu/action_factory.mm
+++ b/ios/chrome/browser/ui/menu/action_factory.mm
@@ -735,4 +735,15 @@
                          block:block];
 }
 
+- (UIAction*)actionToManageLinkInNewTabWithBlock:(ProceduralBlock)block {
+  UIImage* image =
+      DefaultSymbolWithPointSize(kExternalLinkSymbol, kSymbolActionPointSize);
+
+  return [self actionWithTitle:l10n_util::GetNSString(
+                                   IDS_IOS_CONTENT_CONTEXT_OPENMANAGEINNEWTAB)
+                         image:image
+                          type:MenuActionType::ManageInNewTab
+                         block:block];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/menu/menu_action_type.h b/ios/chrome/browser/ui/menu/menu_action_type.h
index ed7433c..44a6a21 100644
--- a/ios/chrome/browser/ui/menu/menu_action_type.h
+++ b/ios/chrome/browser/ui/menu/menu_action_type.h
@@ -71,7 +71,8 @@
   SortDriveItemsByOpeningTime = 58,
   SelectDriveIdentity = 59,
   AddDriveAccount = 60,
-  kMaxValue = AddDriveAccount
+  ManageInNewTab = 61,
+  kMaxValue = ManageInNewTab
 };
 // LINT.ThenChange(/tools/metrics/histograms/metadata/mobile/enums.xml)
 
diff --git a/ios/chrome/browser/ui/menu/menu_histograms.h b/ios/chrome/browser/ui/menu/menu_histograms.h
index d206223..9a5b185 100644
--- a/ios/chrome/browser/ui/menu/menu_histograms.h
+++ b/ios/chrome/browser/ui/menu/menu_histograms.h
@@ -41,6 +41,7 @@
   kMenuScenarioHistogramSortDriveItemsEntry = 28,
   kMenuScenarioHistogramSelectDriveIdentityEntry = 29,
   kMenuScenarioHistogramTabGroupIndicatorEntry = 30,
+  kMenuScenarioHistogramAutofillManualFallbackPlusAddressEntry = 31,
   kMenuScenarioHistogramCount,
 };
 // LINT.ThenChange(/tools/metrics/histograms/metadata/mobile/enums.xml)
diff --git a/ios/chrome/browser/ui/menu/menu_histograms.mm b/ios/chrome/browser/ui/menu/menu_histograms.mm
index 06e19ed..edee9f94 100644
--- a/ios/chrome/browser/ui/menu/menu_histograms.mm
+++ b/ios/chrome/browser/ui/menu/menu_histograms.mm
@@ -70,6 +70,8 @@
     "Mobile.ContextMenu.SelectDriveIdentityEntry.Actions";
 const char kTabGroupIndicatorEntryActionsHistogram[] =
     "Mobile.ContextMenu.TabGroupIndicatorEntry.Actions";
+const char kAutofillManualFallbackPlusAddressEntryActionsHistogram[] =
+    "Mobile.ContextMenu.AutofillManualFallbackPlusAddressEntry.Actions";
 // LINT.ThenChange(/tools/metrics/histograms/metadata/mobile/histograms.xml)
 }  // namespace
 
@@ -140,6 +142,8 @@
       return kSelectDriveIdentityEntryActionsHistogram;
     case kMenuScenarioHistogramTabGroupIndicatorEntry:
       return kTabGroupIndicatorEntryActionsHistogram;
+    case kMenuScenarioHistogramAutofillManualFallbackPlusAddressEntry:
+      return kAutofillManualFallbackPlusAddressEntryActionsHistogram;
     case kMenuScenarioHistogramCount:
       NOTREACHED();
   }
diff --git a/ios/chrome/browser/ui/push_notification/notifications_opt_in_view_controller.mm b/ios/chrome/browser/ui/push_notification/notifications_opt_in_view_controller.mm
index 86ebeac3..af18200 100644
--- a/ios/chrome/browser/ui/push_notification/notifications_opt_in_view_controller.mm
+++ b/ios/chrome/browser/ui/push_notification/notifications_opt_in_view_controller.mm
@@ -108,6 +108,17 @@
   ]];
 
   self.view.backgroundColor = [UIColor colorNamed:kSecondaryBackgroundColor];
+
+  if (@available(iOS 17, *)) {
+    __weak __typeof(self) weakSelf = self;
+    UITraitChangeHandler handler = ^(id<UITraitEnvironment> traitEnvironment,
+                                     UITraitCollection* previousCollection) {
+      weakSelf.shouldHideBanner = IsCompactHeight(traitEnvironment);
+    };
+    NSArray<UITrait>* traits =
+        TraitCollectionSetForTraits(@[ UITraitVerticalSizeClass.self ]);
+    [self registerForTraitChanges:traits withHandler:handler];
+  }
 }
 
 - (void)viewWillLayoutSubviews {
@@ -116,10 +127,16 @@
   self.bannerName = BannerImageName(IsLandscape(self.view.window));
 }
 
+#if !defined(__IPHONE_17_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_17_0
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
   [super traitCollectionDidChange:previousTraitCollection];
+  if (@available(iOS 17, *)) {
+    return;
+  }
+
   self.shouldHideBanner = IsCompactHeight(self.traitCollection);
 }
+#endif
 
 #pragma mark - PromoStyleViewController
 
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_edit_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_edit_table_view_controller.mm
index 59279f3d..272f5d5 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_edit_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_edit_table_view_controller.mm
@@ -32,6 +32,7 @@
 #import "ios/chrome/browser/shared/ui/table_view/table_view_utils.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/settings/autofill/autofill_settings_constants.h"
+#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #import "ios/chrome/grit/ios_branded_strings.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
@@ -90,6 +91,36 @@
   [self loadModel];
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+  [super viewWillAppear:animated];
+
+  SettingsNavigationController* navigationController =
+      base::apple::ObjCCast<SettingsNavigationController>(
+          self.navigationController);
+  if (!navigationController) {
+    return;
+  }
+
+  // Add a "Done" button to the navigation bar if this view controller is the
+  // first in the navigation stack. This "Done" button's purpose being to
+  // dismiss the presented view.
+  if (navigationController.viewControllers.count > 0 &&
+      navigationController.viewControllers.firstObject == self) {
+    UIBarButtonItem* doneButton = [navigationController doneButton];
+
+    // If not in edit mode, set the newly created "Done" button as the left bar
+    // button item. Otherwise, don't override the "Cancel" button that's shown
+    // when in edit mode.
+    if (!self.tableView.editing) {
+      self.navigationItem.leftBarButtonItem = doneButton;
+    }
+
+    // Set `customLeftBarButtonItem` with the "Done" button, so that it'll be
+    // used as the left bar button item when exiting edit mode.
+    self.customLeftBarButtonItem = doneButton;
+  }
+}
+
 #pragma mark - SettingsRootTableViewController
 
 - (void)editButtonPressed {
@@ -147,6 +178,10 @@
                 itemsInSectionWithIdentifier:SectionIdentifierFields]];
 }
 
+- (BOOL)showCancelDuringEditing {
+  return YES;
+}
+
 #pragma mark - LegacyChromeTableViewController
 
 - (void)loadModel {
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm
index 8d7b309..8254c25 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm
@@ -27,10 +27,11 @@
 
 using chrome_test_util::ButtonWithAccessibilityLabel;
 using chrome_test_util::ButtonWithAccessibilityLabelId;
+using chrome_test_util::NavigationBarCancelButton;
 using chrome_test_util::NavigationBarDoneButton;
 using chrome_test_util::PaymentMethodsButton;
-using chrome_test_util::SettingsMenuBackButton;
 using chrome_test_util::SettingsDoneButton;
+using chrome_test_util::SettingsMenuBackButton;
 using chrome_test_util::SettingsToolbarAddButton;
 using chrome_test_util::TabGridEditButton;
 
@@ -330,6 +331,10 @@
       performAction:grey_tap()];
   [ChromeEarlGrey verifyAccessibilityForCurrentScreen];
 
+  // Leave edit mode.
+  [[EarlGrey selectElementWithMatcher:NavigationBarCancelButton()]
+      performAction:grey_tap()];
+
   // Go back to the list view page.
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton(0)]
       performAction:grey_tap()];
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browing_data_egtest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browing_data_egtest.mm
index 12e347c6..470ceb1 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browing_data_egtest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browing_data_egtest.mm
@@ -228,6 +228,38 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// Tests that the confirm button is disabled if no browsing data type is
+// selected.
+- (void)testDisabledConfirmButtonWhenNoSelection {
+  // Disable selection of all browsing data types.
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteBrowsingHistory];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kCloseTabs];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteCookies];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteCache];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeletePasswords];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteFormData];
+
+  [self openQuickDeleteBrowsingDataPage];
+
+  // Check that the confirm button is disabled.
+  [[EarlGrey selectElementWithMatcher:navigationBarConfirmButtonMatcher()]
+      assertWithMatcher:grey_not(grey_enabled())];
+
+  // Select a browsing data type.
+  [[EarlGrey selectElementWithMatcher:historyCellMatcher()]
+      performAction:grey_tap()];
+
+  // Check that the confirm button is enabled.
+  [[EarlGrey selectElementWithMatcher:navigationBarConfirmButtonMatcher()]
+      assertWithMatcher:grey_enabled()];
+}
+
 // Tests the cancel button does not save changes to prefs.
 - (void)testCancelButtonDoesNotUpdatePrefs {
   // Set all prefs to false.
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browsing_data_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browsing_data_view_controller.mm
index e375cc8e..f158628 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browsing_data_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browsing_data_view_controller.mm
@@ -15,7 +15,6 @@
 #import "ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browsing_data_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mutator.h"
-#import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util_mac.h"
@@ -52,7 +51,7 @@
 @interface QuickDeleteBrowsingDataViewController () <
     TableViewLinkHeaderFooterItemDelegate> {
   UITableViewDiffableDataSource<NSNumber*, NSNumber*>* _dataSource;
-  browsing_data::TimePeriod _timeRange;
+
   NSString* _historySummary;
   NSString* _tabsSummary;
   NSString* _cacheSummary;
@@ -85,6 +84,7 @@
       UINavigationItemLargeTitleDisplayModeNever;
   self.navigationItem.leftBarButtonItem = [self cancelButton];
   self.navigationItem.rightBarButtonItem = [self confirmButton];
+  [self updateConfirmButtonEnabledStatus];
   self.title = l10n_util::GetNSString(IDS_IOS_DELETE_BROWSING_DATA_TITLE);
   [self loadModel];
 }
@@ -129,7 +129,7 @@
       [_dataSource itemIdentifierForIndexPath:indexPath].integerValue);
 
   // Update selection value for the corresponding cell with `itemIdentifier`.
-  [self updateSelectionForItemIdentifier:itemIdentifier];
+  [self toggleSelectionForItemIdentifier:itemIdentifier];
 
   // Update the snapshot for the selected cell.
   [self updateSnapshotForItemIdentifier:itemIdentifier];
@@ -183,15 +183,11 @@
 #pragma mark - QuickDeleteConsumer
 
 - (void)setTimeRange:(browsing_data::TimePeriod)timeRange {
-  if (_timeRange == timeRange) {
-    return;
-  }
-  _timeRange = timeRange;
+  // No-op: This ViewController doesn't make user of the selected time range.
 }
 
 - (void)setBrowsingDataSummary:(NSString*)summary {
-  // TODO(crbug.com/353211728): Remove this after refactoring the main page
-  // summary to use the new methods for results & selection.
+  // No-op: This ViewController doesn't show the overall browsing data summary.
 }
 
 - (void)setShouldShowFooter:(BOOL)shouldShowFooter {
@@ -208,38 +204,28 @@
   [_dataSource applySnapshot:snapshot animatingDifferences:YES];
 }
 
-- (void)updateHistoryWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  _historySummary =
-      quick_delete_util::GetCounterTextFromResult(result, _timeRange);
+- (void)setHistorySummary:(NSString*)historySummary {
+  _historySummary = historySummary;
   [self updateSnapshotForItemIdentifier:ItemIdentifierHistory];
 }
 
-- (void)updateTabsWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  _tabsSummary =
-      quick_delete_util::GetCounterTextFromResult(result, _timeRange);
+- (void)setTabsSummary:(NSString*)tabsSummary {
+  _tabsSummary = tabsSummary;
   [self updateSnapshotForItemIdentifier:ItemIdentifierTabs];
 }
 
-- (void)updateCacheWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  _cacheSummary =
-      quick_delete_util::GetCounterTextFromResult(result, _timeRange);
+- (void)setCacheSummary:(NSString*)cacheSummary {
+  _cacheSummary = cacheSummary;
   [self updateSnapshotForItemIdentifier:ItemIdentifierCache];
 }
 
-- (void)updatePasswordsWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  _passwordsSummary =
-      quick_delete_util::GetCounterTextFromResult(result, _timeRange);
+- (void)setPasswordsSummary:(NSString*)passwordsSummary {
+  _passwordsSummary = passwordsSummary;
   [self updateSnapshotForItemIdentifier:ItemIdentifierPasswords];
 }
 
-- (void)updateAutofillWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  _autofillSummary =
-      quick_delete_util::GetCounterTextFromResult(result, _timeRange);
+- (void)setAutofillSummary:(NSString*)autofillSummary {
+  _autofillSummary = autofillSummary;
   [self updateSnapshotForItemIdentifier:ItemIdentifierAutofill];
 }
 
@@ -283,6 +269,14 @@
 
 #pragma mark - Private
 
+// Updates the enabled status of the confirm button. The confirm button should
+// only be enabled if at least one browsing data type is selected for deletion.
+- (void)updateConfirmButtonEnabledStatus {
+  self.navigationItem.rightBarButtonItem.enabled =
+      _historySelected || _tabsSelected || _siteDataSelected ||
+      _cacheSelected || _passwordsSelected || _autofillSelected;
+}
+
 // Returns the cancel button on the navigation bar.
 - (UIBarButtonItem*)cancelButton {
   UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc]
@@ -412,10 +406,12 @@
       [_dataSource snapshot];
   [snapshot reloadItemsWithIdentifiers:@[ @(itemIdentifier) ]];
   [_dataSource applySnapshot:snapshot animatingDifferences:YES];
+
+  [self updateConfirmButtonEnabledStatus];
 }
 
 // Toggles the selection for the given `itemIdentifier`.
-- (void)updateSelectionForItemIdentifier:(ItemIdentifier)itemIdentifier {
+- (void)toggleSelectionForItemIdentifier:(ItemIdentifier)itemIdentifier {
   switch (itemIdentifier) {
     case ItemIdentifierHistory: {
       _historySelected = !_historySelected;
@@ -442,6 +438,7 @@
       break;
     }
   }
+  [self updateConfirmButtonEnabledStatus];
 }
 
 // Returns the icon for the given `itemIdentifier`.
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_consumer.h b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_consumer.h
index 133e10784..f1c584b 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_consumer.h
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_consumer.h
@@ -11,9 +11,9 @@
 enum class TimePeriod;
 }
 
-// Consumer for the QuickDeleteMediator to update the
+// Consumer for the QuickDeleteMediator to set the
 // QuickDeleteViewController.
-@protocol QuickDeleteConsumer
+@protocol QuickDeleteConsumer <NSObject>
 
 // Sets the ViewController with initial value for the deletion `timeRange`.
 - (void)setTimeRange:(browsing_data::TimePeriod)timeRange;
@@ -25,25 +25,20 @@
 // footer string or not.
 - (void)setShouldShowFooter:(BOOL)shouldShowFooter;
 
-// Updates the ViewController with the result of history counter.
-- (void)updateHistoryWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result;
+// Sets the ViewController with the history summary.
+- (void)setHistorySummary:(NSString*)historySummary;
 
-// Updates the ViewController with the result of cache counter.
-- (void)updateTabsWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result;
+// Sets the ViewController with the tabs summary.
+- (void)setTabsSummary:(NSString*)tabsSummary;
 
-// Updates the ViewController with the result of tabs counter.
-- (void)updateCacheWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result;
+// Sets the ViewController with the cache summary.
+- (void)setCacheSummary:(NSString*)cacheSummary;
 
-// Updates the ViewController with the result of passwords counter.
-- (void)updatePasswordsWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result;
+// Sets the ViewController with the passwords summary.
+- (void)setPasswordsSummary:(NSString*)passwordsSummary;
 
-// Updates the ViewController with the result of autofill counter.
-- (void)updateAutofillWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result;
+// Sets the ViewController with the autofill summary.
+- (void)setAutofillSummary:(NSString*)autofillSummary;
 
 // Sets the boolean value for the history pref selection.
 - (void)setHistorySelection:(BOOL)selected;
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_egtest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_egtest.mm
index 7557aa9..b74cb81 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_egtest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_egtest.mm
@@ -374,6 +374,40 @@
       assertWithMatcher:grey_nil()];
 }
 
+// Tests that the browsing data button is disabled if no browsing data type is
+// selected.
+- (void)testDisabledBrowsingDataButtonWhenNoSelection {
+  // Disable selection of all browsing data types.
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteBrowsingHistory];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kCloseTabs];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteCookies];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteCache];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeletePasswords];
+  [ChromeEarlGrey setBoolValue:false
+                   forUserPref:browsing_data::prefs::kDeleteFormData];
+
+  [self openQuickDeleteFromThreeDotMenu];
+
+  id<GREYMatcher> browsingDataButton = ButtonWithAccessibilityLabel(
+      l10n_util::GetNSString(IDS_IOS_DELETE_BROWSING_DATA_BUTTON));
+  // Check that the browsing data button is disabled.
+  [[EarlGrey selectElementWithMatcher:browsingDataButton]
+      assertWithMatcher:grey_not(grey_enabled())];
+
+  // Select a browsing data type.
+  [ChromeEarlGrey setBoolValue:true
+                   forUserPref:browsing_data::prefs::kDeleteBrowsingHistory];
+
+  // Check that the browsing data button is enabled.
+  [[EarlGrey selectElementWithMatcher:browsingDataButton]
+      assertWithMatcher:grey_enabled()];
+}
+
 // Tests the selection time range for the browsing data deletion: the time range
 // selection is shown with the pref value and a new selection updates the pref.
 - (void)testTimeRangeForDeletionSelection {
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator.mm
index e2a2a8b..c9a2c044 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator.mm
@@ -21,6 +21,7 @@
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/browsing_data_counter_wrapper_producer.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_consumer.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_presentation_commands.h"
+#import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 
@@ -192,6 +193,9 @@
 
   bool shouldCloseTabs = _prefs->GetBoolean(browsing_data::prefs::kCloseTabs);
 
+  CHECK((removeMask != BrowsingDataRemoveMask::REMOVE_NOTHING) ||
+        shouldCloseTabs);
+
   // If we cannot perform the tabs closure animation, then close the tabs when
   // deleting the other data.
   if (shouldCloseTabs && !_canPerformTabsClosureAnimation) {
@@ -234,8 +238,15 @@
       },
       std::move(removeBrowsingDataCompletion));
 
-  _browsingDataRemover->RemoveInRange(beginTime, endTime, removeMask,
-                                      std::move(delayedCompletion));
+  // If we have nothing to remove in the in progress UI, then already trigger
+  // the completion block.
+  if (removeMask == BrowsingDataRemoveMask::REMOVE_NOTHING) {
+    CHECK(shouldCloseTabs);
+    std::move(delayedCompletion).Run();
+  } else {
+    _browsingDataRemover->RemoveInRange(beginTime, endTime, removeMask,
+                                        std::move(delayedCompletion));
+  }
 }
 
 - (void)updateHistorySelection:(BOOL)selected {
@@ -604,29 +615,33 @@
 - (void)updateResultOnConsumer:
     (const browsing_data::BrowsingDataCounter::Result*)result {
   std::string prefName = result->source()->GetPrefName();
+  browsing_data::TimePeriod timeRange = static_cast<browsing_data::TimePeriod>(
+      _prefs->GetInteger(browsing_data::prefs::kDeleteTimePeriod));
+  NSString* summary =
+      quick_delete_util::GetCounterTextFromResult(*result, timeRange);
 
   if (prefName == browsing_data::prefs::kDeleteBrowsingHistory) {
-    [_consumer updateHistoryWithResult:*result];
+    [_consumer setHistorySummary:summary];
     return;
   }
 
   if (prefName == browsing_data::prefs::kCloseTabs) {
-    [_consumer updateTabsWithResult:*result];
+    [_consumer setTabsSummary:summary];
     return;
   }
 
   if (prefName == browsing_data::prefs::kDeleteCache) {
-    [_consumer updateCacheWithResult:*result];
+    [_consumer setCacheSummary:summary];
     return;
   }
 
   if (prefName == browsing_data::prefs::kDeletePasswords) {
-    [_consumer updatePasswordsWithResult:*result];
+    [_consumer setPasswordsSummary:summary];
     return;
   }
 
   if (prefName == browsing_data::prefs::kDeleteFormData) {
-    [_consumer updateAutofillWithResult:*result];
+    [_consumer setAutofillSummary:summary];
     return;
   }
 }
@@ -635,6 +650,7 @@
   if (preferenceName == browsing_data::prefs::kDeleteTimePeriod) {
     [_consumer setTimeRange:static_cast<browsing_data::TimePeriod>(
                                 _prefs->GetInteger(preferenceName))];
+    // Maybe update cache summary.
     return;
   }
 
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator_unittest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator_unittest.mm
index dd10616..1e2fe32 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_mediator_unittest.mm
@@ -26,6 +26,7 @@
 #import "ios/chrome/browser/signin/model/identity_manager_factory.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/fake_browsing_data_counter_wrapper_producer.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_consumer.h"
+#import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
 #import "ios/web/public/test/web_task_environment.h"
@@ -122,6 +123,11 @@
     prefs()->SetBoolean(browsing_data::prefs::kDeleteFormData, false);
   }
 
+  browsing_data::TimePeriod timeRange() {
+    return static_cast<browsing_data::TimePeriod>(
+        prefs()->GetInteger(browsing_data::prefs::kDeleteTimePeriod));
+  }
+
   // Triggers the history callback passed to
   // `FakeBrowsingDataCounterWrapperProducer` with a `HistoryResult` with
   // `num_history_items`.
@@ -137,7 +143,9 @@
                         browsing_data::BrowsingDataCounter::ResultCallback());
     const browsing_data::HistoryCounter::HistoryResult historyResult(
         &historyCounter, num_history_items, false, false);
-    OCMExpect([consumer_ updateHistoryWithResult:historyResult]);
+    OCMExpect([consumer_
+        setHistorySummary:quick_delete_util::GetCounterTextFromResult(
+                              historyResult, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:historyResult];
   }
@@ -152,7 +160,9 @@
             browser_state_.get()));
     const TabsCounter::TabsResult tabsResult(&tabsCounter, num_tabs,
                                              /*num_windows=*/0, {});
-    OCMExpect([consumer_ updateTabsWithResult:tabsResult]);
+    OCMExpect(
+        [consumer_ setTabsSummary:quick_delete_util::GetCounterTextFromResult(
+                                      tabsResult, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:tabsResult];
   }
@@ -165,9 +175,11 @@
     browsing_data::PasswordsCounter passwordsCounter(password_store_.get(),
                                                      nullptr, nullptr, nullptr);
     const browsing_data::PasswordsCounter::PasswordsResult passwordsResult(
-        &passwordsCounter, num_passwords, 0, 0, std::vector<std::string>(),
-        std::vector<std::string>());
-    OCMExpect([consumer_ updatePasswordsWithResult:passwordsResult]);
+        &passwordsCounter, num_passwords, 0, false,
+        std::vector<std::string>(num_passwords, "test.com"), {});
+    OCMExpect([consumer_
+        setPasswordsSummary:quick_delete_util::GetCounterTextFromResult(
+                                passwordsResult, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:passwordsResult];
   }
@@ -181,7 +193,9 @@
     browsing_data::AutofillCounter autofillCounter(nullptr, nullptr, nullptr);
     const browsing_data::AutofillCounter::AutofillResult autofillResult(
         &autofillCounter, num_suggestions, num_cards, num_addresses, false);
-    OCMExpect([consumer_ updateAutofillWithResult:autofillResult]);
+    OCMExpect([consumer_
+        setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
+                               autofillResult, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:autofillResult];
   }
@@ -247,7 +261,9 @@
         &counter, test_case.num_sites, test_case.sync_enabled,
         test_case.sync_enabled);
     OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
-    OCMExpect([consumer_ updateHistoryWithResult:result]);
+    OCMExpect([consumer_
+        setHistorySummary:quick_delete_util::GetCounterTextFromResult(
+                              result, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:result];
     EXPECT_OCMOCK_VERIFY(consumer_);
@@ -303,7 +319,9 @@
     const TabsCounter::TabsResult result(&counter, test_case.num_tabs,
                                          test_case.num_windows, {});
     OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
-    OCMExpect([consumer_ updateTabsWithResult:result]);
+    OCMExpect(
+        [consumer_ setTabsSummary:quick_delete_util::GetCounterTextFromResult(
+                                      result, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:result];
     EXPECT_OCMOCK_VERIFY(consumer_);
@@ -343,12 +361,12 @@
                    IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PASSWORDS,
                    2)},
         {2, 0, true, l10n_util::GetPluralNSStringF(
-                   IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PASSWORDS,
-                   2)},
+                        IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PASSWORDS,
+                        2)},
         {1, 0, false, l10n_util::GetPluralNSStringF(
                    IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PASSWORDS, 1)},
         {2, 0, false, l10n_util::GetPluralNSStringF(
-                   IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PASSWORDS, 2)},
+                         IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PASSWORDS, 2)},
     };
   // clang-format on
 
@@ -359,9 +377,12 @@
     const browsing_data::PasswordsCounter::PasswordsResult result(
         &counter, test_case.num_profile_passwords,
         test_case.num_account_passwords, test_case.sync_enabled,
-        std::vector<std::string>(), std::vector<std::string>());
+        std::vector<std::string>(test_case.num_profile_passwords, "test.com"),
+        std::vector<std::string>(test_case.num_account_passwords, "test.com"));
     OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
-    OCMExpect([consumer_ updatePasswordsWithResult:result]);
+    OCMExpect([consumer_
+        setPasswordsSummary:quick_delete_util::GetCounterTextFromResult(
+                                result, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:result];
     EXPECT_OCMOCK_VERIFY(consumer_);
@@ -411,7 +432,9 @@
     const browsing_data::AutofillCounter::AutofillResult result(
         &counter, 0, 0, test_case.num_addresses, test_case.sync_enabled);
     OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
-    OCMExpect([consumer_ updateAutofillWithResult:result]);
+    OCMExpect([consumer_
+        setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
+                               result, timeRange())]);
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:result];
     EXPECT_OCMOCK_VERIFY(consumer_);
@@ -462,7 +485,9 @@
         &counter, 0, test_case.num_cards, 0, test_case.sync_enabled);
 
     OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
-    OCMExpect([consumer_ updateAutofillWithResult:result]);
+    OCMExpect([consumer_
+        setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
+                               result, timeRange())]);
 
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:result];
@@ -515,7 +540,9 @@
     const browsing_data::AutofillCounter::AutofillResult result(
         &counter, test_case.num_suggestions, 0, 0, test_case.sync_enabled);
     OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
-    OCMExpect([consumer_ updateAutofillWithResult:result]);
+    OCMExpect([consumer_
+        setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
+                               result, timeRange())]);
 
     [fake_browsing_data_counter_wrapper_producer_
         triggerUpdateUICallbackForResult:result];
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm
index 3d204e06..b73f8cb 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm
@@ -77,10 +77,19 @@
     TableViewLinkHeaderFooterItemDelegate> {
   UITableViewDiffableDataSource<NSNumber*, NSNumber*>* _dataSource;
   UITableView* _tableView;
+
+  NSLayoutConstraint* _tableViewHeightConstraint;
+
   browsing_data::TimePeriod _timeRange;
   NSString* _browsingDataSummary;
   BOOL _shouldShowFooter;
-  NSLayoutConstraint* _tableViewHeightConstraint;
+
+  BOOL _historySelected;
+  BOOL _tabsSelected;
+  BOOL _siteDataSelected;
+  BOOL _cacheSelected;
+  BOOL _passwordsSelected;
+  BOOL _autofillSelected;
 }
 @end
 
@@ -131,13 +140,9 @@
 
   [self displayGradientView:NO];
 
-  // Configure the color of the primary button to red, as the default colour is
-  // blue.
-  UIButtonConfiguration* buttonConfiguration =
-      self.primaryActionButton.configuration;
-  buttonConfiguration.background.backgroundColor =
-      [UIColor colorNamed:kRedColor];
-  self.primaryActionButton.configuration = buttonConfiguration;
+  // Configure the color of the primary button to red in several states, as the
+  // default colour is blue.
+  [self updatePrimaryActionButtonEnabledStatus];
   self.confirmationCheckmarkColor = [UIColor colorNamed:kRed600Color];
   self.confirmationButtonColor = [UIColor colorNamed:kRed100Color];
 
@@ -297,53 +302,59 @@
                   }];
 }
 
-- (void)updateHistoryWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  // TODO(crbug.com/353211728): Refactor summary using this result.
+- (void)setHistorySummary:(NSString*)historySummary {
+  // No-op: This ViewController doesn't show the individual summaries for each
+  // browsing data type.
 }
 
-- (void)updateTabsWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  // TODO(crbug.com/353211728): Refactor summary using this result.
+- (void)setTabsSummary:(NSString*)tabsSummary {
+  // No-op: This ViewController doesn't show the individual summaries for each
+  // browsing data type.
 }
 
-- (void)updateCacheWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  // TODO(crbug.com/353211728): Refactor summary using this result.
+- (void)setCacheSummary:(NSString*)cacheSummary {
+  // No-op: This ViewController doesn't show the individual summaries for each
+  // browsing data type.
 }
 
-- (void)updatePasswordsWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  // TODO(crbug.com/353211728): Refactor summary using this result.
+- (void)setPasswordsSummary:(NSString*)passwordsSummary {
+  // No-op: This ViewController doesn't show the individual summaries for each
+  // browsing data type.
 }
 
-- (void)updateAutofillWithResult:
-    (const browsing_data::BrowsingDataCounter::Result&)result {
-  // TODO(crbug.com/353211728): Refactor summary using this result.
+- (void)setAutofillSummary:(NSString*)autofillSummary {
+  // No-op: This ViewController doesn't show the individual summaries for each
+  // browsing data type.
 }
 
 - (void)setHistorySelection:(BOOL)selected {
-  // TODO(crbug.com/353211728): Refactor summary using this type selection.
+  _historySelected = selected;
+  [self updatePrimaryActionButtonEnabledStatus];
 }
 
 - (void)setTabsSelection:(BOOL)selected {
-  // TODO(crbug.com/353211728): Refactor summary using this type selection.
+  _tabsSelected = selected;
+  [self updatePrimaryActionButtonEnabledStatus];
 }
 
 - (void)setSiteDataSelection:(BOOL)selected {
-  // TODO(crbug.com/353211728): Refactor summary using this type selection.
+  _siteDataSelected = selected;
+  [self updatePrimaryActionButtonEnabledStatus];
 }
 
 - (void)setCacheSelection:(BOOL)selected {
-  // TODO(crbug.com/353211728): Refactor summary using this type selection.
+  _cacheSelected = selected;
+  [self updatePrimaryActionButtonEnabledStatus];
 }
 
 - (void)setPasswordsSelection:(BOOL)selected {
-  // TODO(crbug.com/353211728): Refactor summary using this type selection.
+  _passwordsSelected = selected;
+  [self updatePrimaryActionButtonEnabledStatus];
 }
 
 - (void)setAutofillSelection:(BOOL)selected {
-  // TODO(crbug.com/353211728): Refactor summary using this type selection.
+  _autofillSelected = selected;
+  [self updatePrimaryActionButtonEnabledStatus];
 }
 
 - (void)deletionInProgress {
@@ -400,6 +411,21 @@
 
 #pragma mark - Private
 
+// Updates the enabled status of the primary button. The primary button should
+// only be enabled if at least one browsing data type is selected for deletion.
+- (void)updatePrimaryActionButtonEnabledStatus {
+  self.primaryActionButton.enabled = _historySelected || _tabsSelected ||
+                                     _siteDataSelected || _cacheSelected ||
+                                     _passwordsSelected || _autofillSelected;
+
+  UIButtonConfiguration* buttonConfiguration =
+      self.primaryActionButton.configuration;
+  buttonConfiguration.background.backgroundColor =
+      self.primaryActionButton.enabled ? [UIColor colorNamed:kRedColor]
+                                       : [UIColor colorNamed:kRed100Color];
+  self.primaryActionButton.configuration = buttonConfiguration;
+}
+
 // Action handler that executes when a voiceover announcement ends.
 - (void)handleUIAccessibilityAnnouncementDidFinishNotification:
     (NSNotification*)notification {
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
index b4889af..cf4ef93 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
@@ -779,7 +779,8 @@
 
 // Verifies that the location bar is above the keyboard when tapping a text
 // field on web. Tapping it should dismiss the keyboard.
-- (void)testTapLocationBarAboveTheKeyboard {
+// TODO(crbug.com/363988044): Flaky on iphone-simulator.
+- (void)FLAKY_testTapLocationBarAboveTheKeyboard {
   [self verifyTapLocationBarAboveTheKeyboardWithMatcher:
             FormInputAccessoryOmniboxTypingShield()];
 }
diff --git a/ios/chrome/browser/visited_url_ranking/model/BUILD.gn b/ios/chrome/browser/visited_url_ranking/model/BUILD.gn
index 27832942..c9aa4c9 100644
--- a/ios/chrome/browser/visited_url_ranking/model/BUILD.gn
+++ b/ios/chrome/browser/visited_url_ranking/model/BUILD.gn
@@ -27,6 +27,7 @@
     "//ios/chrome/browser/shared/model/profile",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/sync/model",
+    "//ios/chrome/browser/sync/model:device_info_sync_service_factory",
     "//ios/components/webui:url_constants",
     "//ios/web/public",
     "//ios/web/public/navigation",
diff --git a/ios/chrome/browser/visited_url_ranking/model/visited_url_ranking_service_factory.mm b/ios/chrome/browser/visited_url_ranking/model/visited_url_ranking_service_factory.mm
index b366aab..a0dd681b 100644
--- a/ios/chrome/browser/visited_url_ranking/model/visited_url_ranking_service_factory.mm
+++ b/ios/chrome/browser/visited_url_ranking/model/visited_url_ranking_service_factory.mm
@@ -7,6 +7,7 @@
 #import "components/history_clusters/core/config.h"
 #import "components/keyed_service/core/service_access_type.h"
 #import "components/keyed_service/ios/browser_state_dependency_manager.h"
+#import "components/sync_device_info/device_info_sync_service.h"
 #import "components/visited_url_ranking/internal/history_url_visit_data_fetcher.h"
 #import "components/visited_url_ranking/internal/session_url_visit_data_fetcher.h"
 #import "components/visited_url_ranking/internal/transformer/bookmarks_url_visit_aggregates_transformer.h"
@@ -22,6 +23,7 @@
 #import "ios/chrome/browser/segmentation_platform/model/segmentation_platform_service_factory.h"
 #import "ios/chrome/browser/shared/model/browser_state/browser_state_otr_helper.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+#import "ios/chrome/browser/sync/model/device_info_sync_service_factory.h"
 #import "ios/chrome/browser/sync/model/session_sync_service_factory.h"
 #import "ios/chrome/browser/visited_url_ranking/model/ios_tab_model_url_visit_data_fetcher.h"
 
@@ -41,6 +43,7 @@
   DependsOn(ios::BookmarkModelFactory::GetInstance());
   DependsOn(
       segmentation_platform::SegmentationPlatformServiceFactory::GetInstance());
+  DependsOn(DeviceInfoSyncServiceFactory::GetInstance());
 }
 
 // static
@@ -77,10 +80,12 @@
   auto* history_service = ios::HistoryServiceFactory::GetForBrowserState(
       browser_state, ServiceAccessType::IMPLICIT_ACCESS);
   if (history_service) {
+    syncer::DeviceInfoSyncService* device_info_sync_service =
+        DeviceInfoSyncServiceFactory::GetForBrowserState(browser_state);
     data_fetchers.emplace(
         visited_url_ranking::Fetcher::kHistory,
         std::make_unique<visited_url_ranking::HistoryURLVisitDataFetcher>(
-            history_service));
+            history_service, device_info_sync_service));
   }
 
   std::map<visited_url_ranking::URLVisitAggregatesTransformType,
diff --git a/ios/chrome/credential_provider_extension/BUILD.gn b/ios/chrome/credential_provider_extension/BUILD.gn
index 487bdc60..a9384c1 100644
--- a/ios/chrome/credential_provider_extension/BUILD.gn
+++ b/ios/chrome/credential_provider_extension/BUILD.gn
@@ -107,6 +107,7 @@
     "passkey_util.mm",
   ]
   deps = [
+    ":passkey_keychain_provider",
     "//base",
     "//components/sync/protocol",
     "//components/webauthn/core/browser:passkey_model",
@@ -141,6 +142,30 @@
   frameworks = [ "Foundation.framework" ]
 }
 
+source_set("passkey_keychain_provider") {
+  public_deps = [ ":passkey_keychain_provider_header" ]
+  deps = [ ios_passkey_keychain_provider_target ]
+  assert_no_deps = [ "//ios/chrome/browser/*" ]
+  frameworks = [ "Foundation.framework" ]
+}
+
+source_set("passkey_keychain_provider_header") {
+  sources = [ "passkey_keychain_provider.h" ]
+  deps = [ "//base" ]
+  assert_no_deps = [ "//ios/chrome/browser/*" ]
+  frameworks = [ "Foundation.framework" ]
+}
+
+source_set("passkey_keychain_provider_implementation") {
+  sources = [ "passkey_keychain_provider.mm" ]
+  deps = [
+    ":passkey_keychain_provider_header",
+    "//base",
+  ]
+  assert_no_deps = [ "//ios/chrome/browser/*" ]
+  frameworks = [ "Foundation.framework" ]
+}
+
 source_set("account_verification_provider") {
   public_deps = [ ":account_verification_provider_header" ]
   deps = [ ios_account_verification_provider_target ]
diff --git a/ios/chrome/credential_provider_extension/credential_provider_view_controller.mm b/ios/chrome/credential_provider_extension/credential_provider_view_controller.mm
index 87ca8d1..056d6c8 100644
--- a/ios/chrome/credential_provider_extension/credential_provider_view_controller.mm
+++ b/ios/chrome/credential_provider_extension/credential_provider_view_controller.mm
@@ -233,7 +233,7 @@
           passkeyCredentialRequest.credentialIdentity);
 
   __weak __typeof(self) weakSelf = self;
-  FetchKeyCompletionBlock completion = ^(NSData* securityDomainSecret) {
+  auto completion = ^(const PasskeyKeychainProvider::SharedKeyList& keyList) {
     CredentialProviderViewController* strongSelf = weakSelf;
     if (!strongSelf) {
       return;
@@ -242,8 +242,7 @@
     ASPasskeyRegistrationCredential* passkeyRegistrationCredential =
         PerformPasskeyCreation(passkeyCredentialRequest.clientDataHash,
                                identity.relyingPartyIdentifier,
-                               identity.userName, identity.userHandle,
-                               securityDomainSecret);
+                               identity.userName, identity.userHandle, keyList);
     if (passkeyRegistrationCredential) {
       [strongSelf completeRegistrationRequestWithSelectedPasskeyCredential:
                       passkeyRegistrationCredential];
@@ -252,7 +251,11 @@
     }
   };
 
-  FetchSecurityDomainSecret(completion);
+  // TODO(crbug.com/355047459): Add navigation controller.
+  FetchSecurityDomainSecret(
+      [self gaia],
+      /*navigation_controller =*/nil,
+      PasskeyKeychainProvider::ReauthenticatePurpose::kEncrypt, completion);
 }
 
 #pragma mark - Properties
@@ -373,24 +376,29 @@
       ASPasskeyCredentialRequest* passkeyCredentialRequest =
           base::apple::ObjCCastStrict<ASPasskeyCredentialRequest>(
               credentialRequest);
-      // TODO(crbug.com/330355124): Handle
+      // TODO(crbug.com/355047459): Handle
       // passkeyCredentialRequest.userVerificationPreference.
 
       __weak __typeof(self) weakSelf = self;
-      FetchKeyCompletionBlock completion = ^(NSData* securityDomainSecret) {
-        CredentialProviderViewController* strongSelf = weakSelf;
-        if (!strongSelf) {
-          return;
-        }
+      auto completion =
+          ^(const PasskeyKeychainProvider::SharedKeyList& keyList) {
+            CredentialProviderViewController* strongSelf = weakSelf;
+            if (!strongSelf) {
+              return;
+            }
 
-        ASPasskeyAssertionCredential* passkeyCredential =
-            PerformPasskeyAssertion(credential,
-                                    passkeyCredentialRequest.clientDataHash,
-                                    nil, securityDomainSecret);
-        [strongSelf userSelectedPasskey:passkeyCredential];
-      };
+            ASPasskeyAssertionCredential* passkeyCredential =
+                PerformPasskeyAssertion(credential,
+                                        passkeyCredentialRequest.clientDataHash,
+                                        nil, keyList);
+            [strongSelf userSelectedPasskey:passkeyCredential];
+          };
 
-      FetchSecurityDomainSecret(completion);
+      // TODO(crbug.com/355047459): Add navigation controller.
+      FetchSecurityDomainSecret(
+          credential.gaia,
+          /*navigation_controller =*/nil,
+          PasskeyKeychainProvider::ReauthenticatePurpose::kDecrypt, completion);
       return;
     }
   }
@@ -537,6 +545,20 @@
                    completion:nil];
 }
 
+- (NSString*)gaia {
+  // TODO(crbug.com/355041765): Get gaia from ios keychain instead of the
+  // credential store, since that would fail if there are no synced credentials
+  // in the store.
+  NSArray<id<Credential>>* credentials = self.credentialStore.credentials;
+  NSUInteger credentialIndex =
+      [credentials indexOfObjectPassingTest:^BOOL(id<Credential> credential,
+                                                  NSUInteger idx, BOOL* stop) {
+        return credential.gaia.length > 0;
+      }];
+  return credentialIndex != NSNotFound ? credentials[credentialIndex].gaia
+                                       : nil;
+}
+
 #pragma mark - SuccessfulReauthTimeAccessor
 
 - (void)updateSuccessfulReauthTime {
diff --git a/ios/chrome/credential_provider_extension/passkey_keychain_provider.h b/ios/chrome/credential_provider_extension/passkey_keychain_provider.h
new file mode 100644
index 0000000..b98ec58
--- /dev/null
+++ b/ios/chrome/credential_provider_extension/passkey_keychain_provider.h
@@ -0,0 +1,69 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_PASSKEY_KEYCHAIN_PROVIDER_H_
+#define IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_PASSKEY_KEYCHAIN_PROVIDER_H_
+
+#import <UIKit/UIKit.h>
+
+#include <vector>
+
+#include "base/functional/callback_forward.h"
+
+@class UIViewController;
+
+// Class to manage passkey vault keys.
+class PasskeyKeychainProvider {
+ public:
+  // The client-defined purpose of the reauthentication flow.
+  enum class ReauthenticatePurpose {
+    // Unspecified action.
+    kUnspecified,
+    // The client is trying to encrypt using the shared key.
+    kEncrypt,
+    // The user is trying to decrypt using the shared key.
+    kDecrypt,
+  };
+
+  // Helper types representing a key and a list of key respectively.
+  using SharedKey = std::vector<uint8_t>;
+  using SharedKeyList = std::vector<SharedKey>;
+
+  // Types for the different callbacks.
+  using KeyFetchedCallback = base::OnceCallback<void(const SharedKeyList&)>;
+  using KeysMarkedAsAsStaleCallback = base::OnceCallback<void(void)>;
+
+  PasskeyKeychainProvider();
+
+  PasskeyKeychainProvider(const PasskeyKeychainProvider&) = delete;
+  PasskeyKeychainProvider& operator=(const PasskeyKeychainProvider&) = delete;
+
+  ~PasskeyKeychainProvider();
+
+  // Asynchronously fetches the shared keys for the identity identified by
+  // `gaia` and invokes `callback` with the fetched keys.
+  // - "gaia" is used to identify the account.
+  // - "navigation_controller" is used to display UI for the user to enter
+  //   credentials. Can be nil, in which case FetchKeys still attempts to fetch
+  //   keys, but fails immediately if any user interaction is required.
+  // - "purpose" is used to specify if the keys will be used to encrypt or
+  //   decrypt. This is mostly for logging purposes and has no effect on the
+  //   keys fetched.
+  // - "callback" is called once the keys are fetched and receives the fetched
+  //   keys as input (the array will be empty on failure).
+  void FetchKeys(NSString* gaia,
+                 UINavigationController* navigation_controller,
+                 ReauthenticatePurpose purpose,
+                 KeyFetchedCallback callback);
+
+  // Asynchronously marks the keys as stale for the identity identified by
+  // `gaia` and invokes `callback` after completion. This should be invoked
+  // only after attempting and failing to decrypt a passkey using the keys
+  // received from the "FetchKeys" function above.
+  // - "gaia" is used to identify the account.
+  // - "callback" is called once the keys are marked as stale.
+  void MarkKeysAsStale(NSString* gaia, KeysMarkedAsAsStaleCallback callback);
+};
+
+#endif  // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_PASSKEY_KEYCHAIN_PROVIDER_H_
diff --git a/ios/chrome/credential_provider_extension/passkey_keychain_provider.mm b/ios/chrome/credential_provider_extension/passkey_keychain_provider.mm
new file mode 100644
index 0000000..7b751cca
--- /dev/null
+++ b/ios/chrome/credential_provider_extension/passkey_keychain_provider.mm
@@ -0,0 +1,29 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/credential_provider_extension/passkey_keychain_provider.h"
+
+#import "base/functional/callback.h"
+
+PasskeyKeychainProvider::PasskeyKeychainProvider() = default;
+
+PasskeyKeychainProvider::~PasskeyKeychainProvider() = default;
+
+void PasskeyKeychainProvider::FetchKeys(
+    NSString* gaia,
+    UINavigationController* navigation_controller,
+    ReauthenticatePurpose purpose,
+    KeyFetchedCallback callback) {
+  if (!callback.is_null()) {
+    std::move(callback).Run(SharedKeyList());
+  }
+}
+
+void PasskeyKeychainProvider::MarkKeysAsStale(
+    NSString* gaia,
+    KeysMarkedAsAsStaleCallback callback) {
+  if (!callback.is_null()) {
+    std::move(callback).Run();
+  }
+}
diff --git a/ios/chrome/credential_provider_extension/passkey_util.h b/ios/chrome/credential_provider_extension/passkey_util.h
index 7c427c9..c7154b0 100644
--- a/ios/chrome/credential_provider_extension/passkey_util.h
+++ b/ios/chrome/credential_provider_extension/passkey_util.h
@@ -8,14 +8,21 @@
 #import <AuthenticationServices/AuthenticationServices.h>
 #import <Foundation/Foundation.h>
 
+#import "base/functional/callback.h"
+#import "ios/chrome/credential_provider_extension/passkey_keychain_provider.h"
+
 @protocol Credential;
 
-// The completion block called after fetching the vault key.
-using FetchKeyCompletionBlock = void (^)(NSData* sds);
+typedef void (^FetchKeyCompletionBlock)(
+    const PasskeyKeychainProvider::SharedKeyList& keyList);
 
 // Fetches the Security Domain Secret and calls the completion block
 // with the Security Domain Secret as the input argument.
-void FetchSecurityDomainSecret(FetchKeyCompletionBlock completion);
+void FetchSecurityDomainSecret(
+    NSString* gaia,
+    UINavigationController* navigation_controller,
+    PasskeyKeychainProvider::ReauthenticatePurpose purpose,
+    FetchKeyCompletionBlock callback);
 
 // On a success, returns a newly created passkey.
 // Returns nil otherwise.
@@ -24,7 +31,8 @@
     NSString* rp_id,
     NSString* user_name,
     NSData* user_handle,
-    NSData* security_domain_secret) API_AVAILABLE(ios(17.0));
+    const PasskeyKeychainProvider::SharedKeyList& keyList)
+    API_AVAILABLE(ios(17.0));
 
 // On a success, returns a valid passkey assertion structure.
 // Returns nil otherwise.
@@ -32,6 +40,7 @@
     id<Credential> credential,
     NSData* client_data_hash,
     NSArray<NSData*>* allowed_credentials,
-    NSData* security_domain_secret) API_AVAILABLE(ios(17.0));
+    const PasskeyKeychainProvider::SharedKeyList& keyList)
+    API_AVAILABLE(ios(17.0));
 
 #endif  // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_PASSKEY_UTIL_H_
diff --git a/ios/chrome/credential_provider_extension/passkey_util.mm b/ios/chrome/credential_provider_extension/passkey_util.mm
index 224c50b..90e6b40 100644
--- a/ios/chrome/credential_provider_extension/passkey_util.mm
+++ b/ios/chrome/credential_provider_extension/passkey_util.mm
@@ -24,14 +24,14 @@
   container.insert(container.end(), span.begin(), span.end());
 }
 
-// Returns the security domain secret by fetching it from the vault.
-NSData* GetSecurityDomainSecret() {
-  // TODO(crbug.com/330355124): Replace this placeholder function with a real
-  // vault access.
-  std::vector<uint8_t> sds;
-  base::HexStringToBytes(
-      "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF", &sds);
-  return [NSData dataWithBytes:sds.data() length:sds.size()];
+// Returns the security domain secret from the vault keys.
+NSData* GetSecurityDomainSecret(
+    const PasskeyKeychainProvider::SharedKeyList& keyList) {
+  if (keyList.empty()) {
+    return nil;
+  }
+  // TODO(crbug.com/355041765): Do we need to handle multiple keys?
+  return [NSData dataWithBytes:keyList[0].data() length:keyList[0].size()];
 }
 
 // Wrapper around passkey_model_utils's MakeAuthenticatorDataForAssertion
@@ -74,6 +74,8 @@
   sync_pb::WebauthnCredentialSpecifics_Encrypted credential_secrets;
   if (!webauthn::passkey_model_utils::DecryptWebauthnCredentialSpecificsData(
           trusted_vault_key, credential_specifics, &credential_secrets)) {
+    // TODO(crbug.com/355047427): On the first failed attempt, mark keys as
+    // stale, re-fetch the keys and try to decrypt again.
     return nil;
   }
 
@@ -96,9 +98,17 @@
 
 }  // namespace
 
-void FetchSecurityDomainSecret(FetchKeyCompletionBlock completion) {
-  NSData* security_domain_secret = GetSecurityDomainSecret();
-  completion(security_domain_secret);
+void FetchSecurityDomainSecret(
+    NSString* gaia,
+    UINavigationController* navigation_controller,
+    PasskeyKeychainProvider::ReauthenticatePurpose purpose,
+    FetchKeyCompletionBlock callback) {
+  PasskeyKeychainProvider passkeyKeychainProvider;
+  passkeyKeychainProvider.FetchKeys(
+      gaia, navigation_controller, purpose,
+      base::BindOnce(^(const PasskeyKeychainProvider::SharedKeyList& keyList) {
+        callback(keyList);
+      }));
 }
 
 ASPasskeyRegistrationCredential* PerformPasskeyCreation(
@@ -106,7 +116,9 @@
     NSString* rp_id,
     NSString* user_name,
     NSData* user_handle,
-    NSData* security_domain_secret) API_AVAILABLE(ios(17.0)) {
+    const PasskeyKeychainProvider::SharedKeyList& keyList)
+    API_AVAILABLE(ios(17.0)) {
+  NSData* security_domain_secret = GetSecurityDomainSecret(keyList);
   if (!security_domain_secret) {
     return nil;
   }
@@ -156,7 +168,13 @@
     id<Credential> credential,
     NSData* client_data_hash,
     NSArray<NSData*>* allowed_credentials,
-    NSData* security_domain_secret) API_AVAILABLE(ios(17.0)) {
+    const PasskeyKeychainProvider::SharedKeyList& keyList)
+    API_AVAILABLE(ios(17.0)) {
+  NSData* security_domain_secret = GetSecurityDomainSecret(keyList);
+  if (!security_domain_secret) {
+    return nil;
+  }
+
   // If the array is empty, then the relying party accepts any passkey
   // credential.
   if (allowed_credentials.count > 0 &&
@@ -173,7 +191,7 @@
   // Update the credential's last used time.
   credential.lastUsedTime =
       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds();
-  // TODO(crbug.com/330355124): Save the last used time of the credential to
+  // TODO(crbug.com/355047898): Save the last used time of the credential to
   //                            update it the next time Chrome syncs.
 
   return [ASPasskeyAssertionCredential
diff --git a/ios/chrome/credential_provider_extension/passkey_util_unittest.mm b/ios/chrome/credential_provider_extension/passkey_util_unittest.mm
index 8d0a3e24..328ccc60 100644
--- a/ios/chrome/credential_provider_extension/passkey_util_unittest.mm
+++ b/ios/chrome/credential_provider_extension/passkey_util_unittest.mm
@@ -31,11 +31,11 @@
   return Sha256(StringToData("ClientDataHash"));
 }
 
-NSData* SecurityDomainSecret() {
-  std::vector<uint8_t> sds;
+PasskeyKeychainProvider::SharedKeyList SecurityDomainSecret() {
+  PasskeyKeychainProvider::SharedKey sds;
   base::HexStringToBytes(
       "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF", &sds);
-  return [NSData dataWithBytes:sds.data() length:sds.size()];
+  return {sds};
 }
 
 ArchivableCredential* TestPasskeyCredential() {
diff --git a/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm b/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm
index 40b9755..c287fc1d 100644
--- a/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm
+++ b/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm
@@ -143,21 +143,27 @@
         // self.requestParameters.userVerificationPreference.
 
         __weak __typeof(self) weakSelf = self;
-        FetchKeyCompletionBlock completion = ^(NSData* securityDomainSecret) {
-          CredentialListCoordinator* strongSelf = weakSelf;
-          if (!strongSelf) {
-            return;
-          }
+        auto completion =
+            ^(const PasskeyKeychainProvider::SharedKeyList& keyList) {
+              CredentialListCoordinator* strongSelf = weakSelf;
+              if (!strongSelf) {
+                return;
+              }
 
-          ASPasskeyAssertionCredential* passkeyCredential =
-              PerformPasskeyAssertion(
-                  credential, strongSelf.requestParameters.clientDataHash,
-                  strongSelf.allowedCredentials, securityDomainSecret);
-          [strongSelf.credentialResponseHandler
-              userSelectedPasskey:passkeyCredential];
-        };
+              ASPasskeyAssertionCredential* passkeyCredential =
+                  PerformPasskeyAssertion(
+                      credential, strongSelf.requestParameters.clientDataHash,
+                      strongSelf.allowedCredentials, keyList);
+              [strongSelf.credentialResponseHandler
+                  userSelectedPasskey:passkeyCredential];
+            };
 
-        FetchSecurityDomainSecret(completion);
+        // TODO(crbug.com/355047459): Add navigation controller.
+        FetchSecurityDomainSecret(
+            credential.gaia,
+            /*navigation_controller =*/nil,
+            PasskeyKeychainProvider::ReauthenticatePurpose::kDecrypt,
+            completion);
       }
     }
   }];
diff --git a/ios/chrome/test/providers/lens/test_lens_overlay_controller.mm b/ios/chrome/test/providers/lens/test_lens_overlay_controller.mm
index 83b4d1d6f23f..243f74d 100644
--- a/ios/chrome/test/providers/lens/test_lens_overlay_controller.mm
+++ b/ios/chrome/test/providers/lens/test_lens_overlay_controller.mm
@@ -9,6 +9,10 @@
 
 @implementation TestLensOverlayController
 
+- (BOOL)isPanningSelectionUI {
+  return NO;
+}
+
 - (void)setLensOverlayDelegate:(id<ChromeLensOverlayDelegate>)delegate {
   // NO-OP
 }
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
index a3d240b..d1cca43 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-ebe818fab8e0eb3ce43efe4dc9237bfeb72a3f60
\ No newline at end of file
+d71f04b7a234158e6e97514e4680c16db2bf1909
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 6c0293b..6b8c593b 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-ccabc0584201536ad6cc9dbffffd75e44b647258
\ No newline at end of file
+6ada6da53ce3f2e0b640a5d0367f4a6253d77685
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index cb68f42..33716a95 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-37db27db865aee9acc6c220f4513e7b7e8176866
\ No newline at end of file
+0402e8abb2dc5694ae9111166cb4566a2d2664e0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
index aaebbf9..d5cd20b 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-817c33cebc74cbf570eaa872eff023805109586e
\ No newline at end of file
+4caf2377e1e579c7cb3ca2aec0c8e0994ef4d680
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
index cc45a06..831ac73 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-7c527721cdc479a6b42c7222cbb551fa6ecf93c6
\ No newline at end of file
+d40b790720631609451cdecbfd4073ec90098b26
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 30f3482e..00533d8f 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-df4f4220b14e783ad25910728bc4d95215350fa6
\ No newline at end of file
+c13a863aa3770699b709292809c0c696bd752d02
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index bff54d8..c2938f45 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-cb405979dff6f3a842c0441d174b0d3706576f73
\ No newline at end of file
+eb4faf6c0794648feaf765ec220a7f8e81b876fd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index f5fef36..d47752e 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-b11d3ed9fd0bc163405a401ad79e01e98f003c6f
\ No newline at end of file
+670f77ab983e644e9d8569b7669729dcdcaa836e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 9466100..9024810 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-510c1e597d8581d9eac64aa700d481c529db6c64
\ No newline at end of file
+69e86ff0247ac4d6166deabf65e3d8c69de39572
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 2ad3c50..74792fe 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-b128d2662c3455bc82d09d02951b9a3bc155634d
\ No newline at end of file
+85a99ea449732c34b2f35fefcacdc3d4970912ab
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 69326441..0c5a938 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-372802d3d4a659842ef3571e8c5d9d043ab23b50
\ No newline at end of file
+2e852b4fbe46e40a01d6de54c1f1ade5b60d7170
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 2884f685..290dec5 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-b8d87b00848d65c85848f074c0877d8216886cc2
\ No newline at end of file
+b4fc6ffe819c0c571ec4eee90beef4603c150022
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 63195e2..5dcf50e 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-4ca09009d19cd749327389e085321a2c8eba3891
\ No newline at end of file
+ffa1aefcfacc4a96f9e72526695a0cb64377f773
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 2fb25527..44318c1 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-58b185a89f550debf76c11b763ea18f0a732cf28
\ No newline at end of file
+e355ca4ce9ce61182b2dc544bff3eebce0e7a022
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index d159dc4..1b99711 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-8b3ab88658bfd56f7c999bc07845a1714f804dc9
\ No newline at end of file
+c9feb368b9dfe31f3cfc948b601d7839f77680d9
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/lens/lens_overlay_api.h b/ios/public/provider/chrome/browser/lens/lens_overlay_api.h
index 8089724..f52ce002 100644
--- a/ios/public/provider/chrome/browser/lens/lens_overlay_api.h
+++ b/ios/public/provider/chrome/browser/lens/lens_overlay_api.h
@@ -31,6 +31,9 @@
 // Defines the interface for interacting with a Chrome Lens Overlay.
 @protocol ChromeLensOverlay
 
+// Whether the user is currently panning the selection UI.
+@property(nonatomic, readonly) BOOL isPanningSelectionUI;
+
 // Sets the delegate for `ChromeLensOverlay`.
 - (void)setLensOverlayDelegate:(id<ChromeLensOverlayDelegate>)delegate;
 
diff --git a/ios/web/content/BUILD.gn b/ios/web/content/BUILD.gn
index 7385f1a..6529154 100644
--- a/ios/web/content/BUILD.gn
+++ b/ios/web/content/BUILD.gn
@@ -41,6 +41,7 @@
     "//base",
     "//build:blink_buildflags",
     "//components/embedder_support/ios:web_contents_delegate",
+    "//components/javascript_dialogs",
     "//components/js_injection/browser",
     "//content/public/browser",
     "//ios/web/annotations",
@@ -79,6 +80,8 @@
   sources = [
     "ui/content_context_menu_controller.h",
     "ui/content_context_menu_controller.mm",
+    "ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.h",
+    "ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.mm",
     "ui/web_contents_view_delegate_impl.h",
     "ui/web_contents_view_delegate_impl.mm",
   ]
@@ -86,6 +89,7 @@
   deps = [
     ":content",
     "//base",
+    "//components/javascript_dialogs",
     "//content/public/browser",
     "//ios/web/public:public",
     "//ios/web/public/ui:ui",
diff --git a/ios/web/content/DEPS b/ios/web/content/DEPS
index b6d2692..2ed9c53 100644
--- a/ios/web/content/DEPS
+++ b/ios/web/content/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+content/public/browser",
   "+components/crash/core/common",
+  "+components/javascript_dialogs",
   "+components/js_injection",
 ]
 specific_include_rules = {
diff --git a/ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.h b/ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.h
new file mode 100644
index 0000000..108e0b0
--- /dev/null
+++ b/ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.h
@@ -0,0 +1,47 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_CONTENT_UI_JAVASCRIPT_DIALOGS_JAVASCRIPT_TAB_MODAL_DIALOG_MANAGER_DELEGATE_IOS_H_
+#define IOS_WEB_CONTENT_UI_JAVASCRIPT_DIALOGS_JAVASCRIPT_TAB_MODAL_DIALOG_MANAGER_DELEGATE_IOS_H_
+
+#import "base/functional/callback.h"
+#import "base/memory/raw_ptr.h"
+#import "components/javascript_dialogs/tab_modal_dialog_manager_delegate.h"
+
+namespace content {
+class WebContents;
+}
+
+class JavaScriptTabModalDialogManagerDelegateIOS
+    : public javascript_dialogs::TabModalDialogManagerDelegate {
+ public:
+  explicit JavaScriptTabModalDialogManagerDelegateIOS(
+      content::WebContents* web_contents);
+  ~JavaScriptTabModalDialogManagerDelegateIOS() override;
+
+  JavaScriptTabModalDialogManagerDelegateIOS(
+      const JavaScriptTabModalDialogManagerDelegateIOS& other) = delete;
+  JavaScriptTabModalDialogManagerDelegateIOS& operator=(
+      const JavaScriptTabModalDialogManagerDelegateIOS& other) = delete;
+
+  // javascript_dialogs::TabModalDialogManagerDelegate:
+  base::WeakPtr<javascript_dialogs::TabModalDialogView> CreateNewDialog(
+      content::WebContents* alerting_web_contents,
+      const std::u16string& title,
+      content::JavaScriptDialogType dialog_type,
+      const std::u16string& message_text,
+      const std::u16string& default_prompt_text,
+      content::JavaScriptDialogManager::DialogClosedCallback dialog_callback,
+      base::OnceClosure dialog_closed_callback) override;
+  void WillRunDialog() override;
+  void DidCloseDialog() override;
+  void SetTabNeedsAttention(bool attention) override;
+  bool IsWebContentsForemost() override;
+  bool IsApp() override;
+
+ private:
+  raw_ptr<content::WebContents> web_contents_;
+};
+
+#endif  // IOS_WEB_CONTENT_UI_JAVASCRIPT_DIALOGS_JAVASCRIPT_TAB_MODAL_DIALOG_MANAGER_DELEGATE_IOS_H_
diff --git a/ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.mm b/ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.mm
new file mode 100644
index 0000000..5a7490145
--- /dev/null
+++ b/ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.mm
@@ -0,0 +1,47 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.h"
+
+#import "components/javascript_dialogs/ios/tab_modal_dialog_view_ios.h"
+#import "content/public/browser/javascript_dialog_manager.h"
+
+JavaScriptTabModalDialogManagerDelegateIOS::
+    JavaScriptTabModalDialogManagerDelegateIOS(
+        content::WebContents* web_contents)
+    : web_contents_(web_contents) {}
+
+JavaScriptTabModalDialogManagerDelegateIOS::
+    ~JavaScriptTabModalDialogManagerDelegateIOS() = default;
+
+base::WeakPtr<javascript_dialogs::TabModalDialogView>
+JavaScriptTabModalDialogManagerDelegateIOS::CreateNewDialog(
+    content::WebContents* alerting_web_contents,
+    const std::u16string& title,
+    content::JavaScriptDialogType dialog_type,
+    const std::u16string& message_text,
+    const std::u16string& default_prompt_text,
+    content::JavaScriptDialogManager::DialogClosedCallback
+        callback_on_button_clicked,
+    base::OnceClosure callback_on_cancelled) {
+  return javascript_dialogs::TabModalDialogViewIOS::Create(
+      web_contents_, alerting_web_contents, title, dialog_type, message_text,
+      default_prompt_text, std::move(callback_on_button_clicked),
+      std::move(callback_on_cancelled));
+}
+
+void JavaScriptTabModalDialogManagerDelegateIOS::WillRunDialog() {}
+
+void JavaScriptTabModalDialogManagerDelegateIOS::DidCloseDialog() {}
+
+void JavaScriptTabModalDialogManagerDelegateIOS::SetTabNeedsAttention(
+    bool attention) {}
+
+bool JavaScriptTabModalDialogManagerDelegateIOS::IsWebContentsForemost() {
+  return false;
+}
+
+bool JavaScriptTabModalDialogManagerDelegateIOS::IsApp() {
+  return false;
+}
diff --git a/ios/web/content/ui/web_contents_view_delegate_impl.mm b/ios/web/content/ui/web_contents_view_delegate_impl.mm
index 151c446..a647001c 100644
--- a/ios/web/content/ui/web_contents_view_delegate_impl.mm
+++ b/ios/web/content/ui/web_contents_view_delegate_impl.mm
@@ -6,15 +6,22 @@
 
 #import <memory>
 
+#import "components/javascript_dialogs/tab_modal_dialog_manager.h"
 #import "content/public/browser/context_menu_params.h"
 #import "content/public/browser/render_frame_host.h"
 #import "content/public/browser/web_contents.h"
 #import "content/public/browser/web_contents_view_delegate.h"
 #import "ios/web/content/ui/content_context_menu_controller.h"
+#import "ios/web/content/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_ios.h"
 
 WebContentsViewDelegateImpl::WebContentsViewDelegateImpl(
     content::WebContents* web_contents)
-    : web_contents_(web_contents) {}
+    : web_contents_(web_contents) {
+  javascript_dialogs::TabModalDialogManager::CreateForWebContents(
+      web_contents_.get(),
+      std::make_unique<JavaScriptTabModalDialogManagerDelegateIOS>(
+          web_contents_.get()));
+}
 
 WebContentsViewDelegateImpl::~WebContentsViewDelegateImpl() {}
 
diff --git a/ios/web/content/web_state/content_web_state.h b/ios/web/content/web_state/content_web_state.h
index fbcc986..11294df 100644
--- a/ios/web/content/web_state/content_web_state.h
+++ b/ios/web/content/web_state/content_web_state.h
@@ -37,6 +37,7 @@
 
 namespace content {
 class FileSelectListener;
+class JavaScriptDialogManager;
 class NavigationEntry;
 class NavigationHandle;
 class RenderFrameHost;
@@ -224,6 +225,9 @@
                       scoped_refptr<content::FileSelectListener> listener,
                       const blink::mojom::FileChooserParams& params) override;
 
+  content::JavaScriptDialogManager* GetJavaScriptDialogManager(
+      content::WebContents* source) override;
+
  private:
   // Helper method to register notification observers.
   void RegisterNotificationObservers();
diff --git a/ios/web/content/web_state/content_web_state.mm b/ios/web/content/web_state/content_web_state.mm
index 1fffdee..b2c31b3 100644
--- a/ios/web/content/web_state/content_web_state.mm
+++ b/ios/web/content/web_state/content_web_state.mm
@@ -9,7 +9,9 @@
 #import "base/strings/utf_string_conversions.h"
 #import "components/embedder_support/ios/delegate/color_chooser/color_chooser_ios.h"
 #import "components/embedder_support/ios/delegate/file_chooser/file_select_helper_ios.h"
+#import "components/javascript_dialogs/tab_modal_dialog_manager.h"
 #import "content/public/browser/file_select_listener.h"
+#import "content/public/browser/javascript_dialog_manager.h"
 #import "content/public/browser/navigation_entry.h"
 #import "content/public/browser/visibility.h"
 #import "content/public/browser/web_contents.h"
@@ -836,4 +838,11 @@
       render_frame_host, listener, params);
 }
 
+content::JavaScriptDialogManager* ContentWebState::GetJavaScriptDialogManager(
+    content::WebContents* source) {
+  content::JavaScriptDialogManager* dialog =
+      javascript_dialogs::TabModalDialogManager::FromWebContents(source);
+  return dialog;
+}
+
 }  // namespace web
diff --git a/ios/web_view/internal/sync/web_view_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_sync_service_factory.mm
index 87bc8023..ec98806 100644
--- a/ios/web_view/internal/sync/web_view_sync_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_sync_service_factory.mm
@@ -108,6 +108,7 @@
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   controller_builder.SetSupervisedUserSettingsService(nullptr);
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
+  controller_builder.SetTabGroupSyncService(nullptr);
   controller_builder.SetTemplateURLService(nullptr);
   controller_builder.SetUserEventService(nullptr);
 
diff --git a/ios_internal b/ios_internal
index 68b91da..ec602e2 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 68b91da9d364b3e1c0af9b80156e674458b525ba
+Subproject commit ec602e23d833ae149c27f173248ef9c6255442bc
diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc
index 675291d3..a44fbc63 100644
--- a/media/audio/win/audio_output_win_unittest.cc
+++ b/media/audio/win/audio_output_win_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include <windows.h>
 
 #include <mmsystem.h>
diff --git a/media/base/android/media_codec_bridge_impl.cc b/media/base/android/media_codec_bridge_impl.cc
index be7591a..e85888d 100644
--- a/media/base/android/media_codec_bridge_impl.cc
+++ b/media/base/android/media_codec_bridge_impl.cc
@@ -708,10 +708,10 @@
     }
   }
 
-  ScopedJavaLocalRef<jintArray> clear_array = base::android::ToJavaIntArray(
-      env, native_clear_array.data(), num_subsamples);
-  ScopedJavaLocalRef<jintArray> cypher_array = base::android::ToJavaIntArray(
-      env, native_cypher_array.data(), num_subsamples);
+  ScopedJavaLocalRef<jintArray> clear_array =
+      base::android::ToJavaIntArray(env, native_clear_array);
+  ScopedJavaLocalRef<jintArray> cypher_array =
+      base::android::ToJavaIntArray(env, native_cypher_array);
 
   MediaCodecStatus status = static_cast<MediaCodecStatus>(
       Java_MediaCodecBridge_queueSecureInputBuffer(
diff --git a/media/cdm/cenc_utils_fuzzertest.cc b/media/cdm/cenc_utils_fuzzertest.cc
index d03fae3..759dcc5 100644
--- a/media/cdm/cenc_utils_fuzzertest.cc
+++ b/media/cdm/cenc_utils_fuzzertest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include <stddef.h>
 #include <stdint.h>
 #include <vector>
diff --git a/media/cdm/cenc_utils_unittest.cc b/media/cdm/cenc_utils_unittest.cc
index f50f083..d8c90fa 100644
--- a/media/cdm/cenc_utils_unittest.cc
+++ b/media/cdm/cenc_utils_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/cdm/cenc_utils.h"
 
 #include <stddef.h>
diff --git a/media/filters/ffmpeg_aac_bitstream_converter.cc b/media/filters/ffmpeg_aac_bitstream_converter.cc
index e26b6cd..ad9a8c82 100644
--- a/media/filters/ffmpeg_aac_bitstream_converter.cc
+++ b/media/filters/ffmpeg_aac_bitstream_converter.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/filters/ffmpeg_aac_bitstream_converter.h"
 
 #include "base/logging.h"
diff --git a/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc b/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc
index 1897eb09..093a5779 100644
--- a/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc
+++ b/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include <stddef.h>
 #include <stdint.h>
 
diff --git a/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc b/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
index 8de8c46..cfbbb89 100644
--- a/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
+++ b/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.h"
 
 #include <stdint.h>
diff --git a/media/filters/h264_to_annex_b_bitstream_converter.cc b/media/filters/h264_to_annex_b_bitstream_converter.cc
index 74f552055..01069114 100644
--- a/media/filters/h264_to_annex_b_bitstream_converter.cc
+++ b/media/filters/h264_to_annex_b_bitstream_converter.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/filters/h264_to_annex_b_bitstream_converter.h"
 
 #include <stddef.h>
diff --git a/media/filters/h265_to_annex_b_bitstream_converter.cc b/media/filters/h265_to_annex_b_bitstream_converter.cc
index 640b481c..6bd4c8e 100644
--- a/media/filters/h265_to_annex_b_bitstream_converter.cc
+++ b/media/filters/h265_to_annex_b_bitstream_converter.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/filters/h265_to_annex_b_bitstream_converter.h"
 
 #include <stddef.h>
diff --git a/media/filters/hls_data_source_provider.cc b/media/filters/hls_data_source_provider.cc
index ad2b7fc68..11f4fb8 100644
--- a/media/filters/hls_data_source_provider.cc
+++ b/media/filters/hls_data_source_provider.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/filters/hls_data_source_provider.h"
 #include "base/trace_event/trace_event.h"
 
diff --git a/media/filters/hls_manifest_demuxer_engine.cc b/media/filters/hls_manifest_demuxer_engine.cc
index b933a3e..c8e0589 100644
--- a/media/filters/hls_manifest_demuxer_engine.cc
+++ b/media/filters/hls_manifest_demuxer_engine.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/filters/hls_manifest_demuxer_engine.h"
 
 #include <optional>
diff --git a/media/filters/hls_rendition_impl.cc b/media/filters/hls_rendition_impl.cc
index 02b897d..45dea50a 100644
--- a/media/filters/hls_rendition_impl.cc
+++ b/media/filters/hls_rendition_impl.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/filters/hls_rendition_impl.h"
 
 #include "base/task/bind_post_task.h"
diff --git a/media/formats/mp2t/descriptors.cc b/media/formats/mp2t/descriptors.cc
index 94c967fb..6c2eb9c 100644
--- a/media/formats/mp2t/descriptors.cc
+++ b/media/formats/mp2t/descriptors.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/descriptors.h"
 
 #include <vector>
diff --git a/media/formats/mp2t/es_adapter_video_unittest.cc b/media/formats/mp2t/es_adapter_video_unittest.cc
index a7d3be73..1882780 100644
--- a/media/formats/mp2t/es_adapter_video_unittest.cc
+++ b/media/formats/mp2t/es_adapter_video_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/es_adapter_video.h"
 
 #include <stddef.h>
diff --git a/media/formats/mp2t/es_parser.cc b/media/formats/mp2t/es_parser.cc
index 1bf00d39..b66f551 100644
--- a/media/formats/mp2t/es_parser.cc
+++ b/media/formats/mp2t/es_parser.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/es_parser.h"
 
 #include "base/logging.h"
diff --git a/media/formats/mp2t/es_parser_adts.cc b/media/formats/mp2t/es_parser_adts.cc
index e16cd9e..dea858d 100644
--- a/media/formats/mp2t/es_parser_adts.cc
+++ b/media/formats/mp2t/es_parser_adts.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/es_parser_adts.h"
 
 #include <stddef.h>
diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc
index b75fc95..1064355 100644
--- a/media/formats/mp2t/es_parser_h264.cc
+++ b/media/formats/mp2t/es_parser_h264.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/es_parser_h264.h"
 
 #include <limits>
diff --git a/media/formats/mp2t/es_parser_mpeg1audio.cc b/media/formats/mp2t/es_parser_mpeg1audio.cc
index 6cd645fd..597e7ca 100644
--- a/media/formats/mp2t/es_parser_mpeg1audio.cc
+++ b/media/formats/mp2t/es_parser_mpeg1audio.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/es_parser_mpeg1audio.h"
 
 #include <vector>
diff --git a/media/formats/mp2t/es_parser_test_base.cc b/media/formats/mp2t/es_parser_test_base.cc
index 414275e..acc95d3 100644
--- a/media/formats/mp2t/es_parser_test_base.cc
+++ b/media/formats/mp2t/es_parser_test_base.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/es_parser_test_base.h"
 
 #include "base/check_op.h"
diff --git a/media/formats/mp2t/mp2t_stream_parser.cc b/media/formats/mp2t/mp2t_stream_parser.cc
index e89c0a3c..ab1ad25 100644
--- a/media/formats/mp2t/mp2t_stream_parser.cc
+++ b/media/formats/mp2t/mp2t_stream_parser.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/mp2t_stream_parser.h"
 
 #include <memory>
diff --git a/media/formats/mp2t/mp2t_stream_parser_unittest.cc b/media/formats/mp2t/mp2t_stream_parser_unittest.cc
index 0d0411b..abfa59c 100644
--- a/media/formats/mp2t/mp2t_stream_parser_unittest.cc
+++ b/media/formats/mp2t/mp2t_stream_parser_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/mp2t_stream_parser.h"
 
 #include <openssl/aes.h>
diff --git a/media/formats/mp2t/timestamp_unroller_unittest.cc b/media/formats/mp2t/timestamp_unroller_unittest.cc
index cc2f999..98f3b1b5 100644
--- a/media/formats/mp2t/timestamp_unroller_unittest.cc
+++ b/media/formats/mp2t/timestamp_unroller_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/timestamp_unroller.h"
 
 #include <stddef.h>
diff --git a/media/formats/mp2t/ts_packet.cc b/media/formats/mp2t/ts_packet.cc
index 5a28e4d..79a5202a 100644
--- a/media/formats/mp2t/ts_packet.cc
+++ b/media/formats/mp2t/ts_packet.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/ts_packet.h"
 
 #include <memory>
diff --git a/media/formats/mp2t/ts_section_pes.cc b/media/formats/mp2t/ts_section_pes.cc
index e97a710a..bb3b8c399 100644
--- a/media/formats/mp2t/ts_section_pes.cc
+++ b/media/formats/mp2t/ts_section_pes.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/ts_section_pes.h"
 
 #include <memory>
diff --git a/media/formats/mp2t/ts_section_psi.cc b/media/formats/mp2t/ts_section_psi.cc
index ed2b03b..b951568d 100644
--- a/media/formats/mp2t/ts_section_psi.cc
+++ b/media/formats/mp2t/ts_section_psi.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp2t/ts_section_psi.h"
 
 #include <algorithm>
diff --git a/media/formats/mp4/aac.cc b/media/formats/mp4/aac.cc
index eae8efdff..ae3c469 100644
--- a/media/formats/mp4/aac.cc
+++ b/media/formats/mp4/aac.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/aac.h"
 
 #include <stddef.h>
diff --git a/media/formats/mp4/aac_unittest.cc b/media/formats/mp4/aac_unittest.cc
index c73dd4f..d35680b0 100644
--- a/media/formats/mp4/aac_unittest.cc
+++ b/media/formats/mp4/aac_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include <stdint.h>
 
 #include <string>
diff --git a/media/formats/mp4/ac3.cc b/media/formats/mp4/ac3.cc
index e884cec..dd900cd 100644
--- a/media/formats/mp4/ac3.cc
+++ b/media/formats/mp4/ac3.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/ac3.h"
 
 #include <algorithm>
diff --git a/media/formats/mp4/avc.cc b/media/formats/mp4/avc.cc
index 0990467..47f105b 100644
--- a/media/formats/mp4/avc.cc
+++ b/media/formats/mp4/avc.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/avc.h"
 
 #include <memory>
diff --git a/media/formats/mp4/avc_unittest.cc b/media/formats/mp4/avc_unittest.cc
index f05d3991..4828cd0 100644
--- a/media/formats/mp4/avc_unittest.cc
+++ b/media/formats/mp4/avc_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/avc.h"
 
 #include <stddef.h>
diff --git a/media/formats/mp4/box_reader_unittest.cc b/media/formats/mp4/box_reader_unittest.cc
index 0676d98..50d7f64 100644
--- a/media/formats/mp4/box_reader_unittest.cc
+++ b/media/formats/mp4/box_reader_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/box_reader.h"
 
 #include <stdint.h>
diff --git a/media/formats/mp4/eac3.cc b/media/formats/mp4/eac3.cc
index 6998491..6b808282 100644
--- a/media/formats/mp4/eac3.cc
+++ b/media/formats/mp4/eac3.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/eac3.h"
 
 #include <algorithm>
diff --git a/media/formats/mp4/es_descriptor_unittest.cc b/media/formats/mp4/es_descriptor_unittest.cc
index 04e9eae..94bac2a 100644
--- a/media/formats/mp4/es_descriptor_unittest.cc
+++ b/media/formats/mp4/es_descriptor_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/es_descriptor.h"
 
 #include <stdint.h>
diff --git a/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_fuzztest.cc b/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_fuzztest.cc
index 5e7d0c44..28daaab 100644
--- a/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_fuzztest.cc
+++ b/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_fuzztest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include <stdint.h>
 
 #include <memory>
diff --git a/media/formats/mp4/hevc.cc b/media/formats/mp4/hevc.cc
index db812462..024aff9 100644
--- a/media/formats/mp4/hevc.cc
+++ b/media/formats/mp4/hevc.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/hevc.h"
 
 #include <algorithm>
diff --git a/media/formats/mp4/hevc_unittest.cc b/media/formats/mp4/hevc_unittest.cc
index 7920699..d9cdf73 100644
--- a/media/formats/mp4/hevc_unittest.cc
+++ b/media/formats/mp4/hevc_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/hevc.h"
 
 #include "media/formats/mp4/nalu_test_helper.h"
diff --git a/media/formats/mp4/mp4_stream_parser_unittest.cc b/media/formats/mp4/mp4_stream_parser_unittest.cc
index 11924074..a5953048 100644
--- a/media/formats/mp4/mp4_stream_parser_unittest.cc
+++ b/media/formats/mp4/mp4_stream_parser_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/mp4_stream_parser.h"
 
 #include <stddef.h>
diff --git a/media/formats/mp4/sample_to_group_iterator_unittest.cc b/media/formats/mp4/sample_to_group_iterator_unittest.cc
index fa99954..3f94267 100644
--- a/media/formats/mp4/sample_to_group_iterator_unittest.cc
+++ b/media/formats/mp4/sample_to_group_iterator_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/sample_to_group_iterator.h"
 
 #include <stddef.h>
diff --git a/media/formats/mp4/track_run_iterator_unittest.cc b/media/formats/mp4/track_run_iterator_unittest.cc
index 6cd2646..22874d2 100644
--- a/media/formats/mp4/track_run_iterator_unittest.cc
+++ b/media/formats/mp4/track_run_iterator_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mp4/track_run_iterator.h"
 
 #include <stddef.h>
diff --git a/media/formats/mpeg/adts_stream_parser.cc b/media/formats/mpeg/adts_stream_parser.cc
index a406375..5e0b48bd 100644
--- a/media/formats/mpeg/adts_stream_parser.cc
+++ b/media/formats/mpeg/adts_stream_parser.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/formats/mpeg/adts_stream_parser.h"
 
 #include <stddef.h>
diff --git a/media/gpu/android/ndk_audio_encoder.cc b/media/gpu/android/ndk_audio_encoder.cc
index 26478c1a..6084e78 100644
--- a/media/gpu/android/ndk_audio_encoder.cc
+++ b/media/gpu/android/ndk_audio_encoder.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/android/ndk_audio_encoder.h"
 
 #include <aaudio/AAudio.h>
diff --git a/media/gpu/h265_builder.cc b/media/gpu/h265_builder.cc
index 44e716f9..a3b4864d4 100644
--- a/media/gpu/h265_builder.cc
+++ b/media/gpu/h265_builder.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/h265_builder.h"
 #include "media/filters/h26x_annex_b_bitstream_builder.h"
 
diff --git a/media/gpu/h265_decoder.cc b/media/gpu/h265_decoder.cc
index 8f72aa9..71266331 100644
--- a/media/gpu/h265_decoder.cc
+++ b/media/gpu/h265_decoder.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/h265_decoder.h"
 
 #include <algorithm>
diff --git a/media/gpu/h265_decoder_fuzzer.cc b/media/gpu/h265_decoder_fuzzer.cc
index 0e60dab..36f3866 100644
--- a/media/gpu/h265_decoder_fuzzer.cc
+++ b/media/gpu/h265_decoder_fuzzer.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/h265_decoder.h"
 
 #include <stddef.h>
diff --git a/media/gpu/mac/video_toolbox_h265_accelerator.cc b/media/gpu/mac/video_toolbox_h265_accelerator.cc
index b8c3a9d..7efe77b 100644
--- a/media/gpu/mac/video_toolbox_h265_accelerator.cc
+++ b/media/gpu/mac/video_toolbox_h265_accelerator.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/mac/video_toolbox_h265_accelerator.h"
 
 #include <array>
diff --git a/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc b/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc
index 0bfc9ee1..0b8c62308 100644
--- a/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc
+++ b/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h"
 
 #include "build/chromeos_buildflags.h"
diff --git a/media/gpu/vaapi/test/h265_decoder.cc b/media/gpu/vaapi/test/h265_decoder.cc
index d1dc262d..a7d6356 100644
--- a/media/gpu/vaapi/test/h265_decoder.cc
+++ b/media/gpu/vaapi/test/h265_decoder.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/vaapi/test/h265_decoder.h"
 
 #include <algorithm>
diff --git a/media/gpu/vaapi/test/h265_vaapi_wrapper.cc b/media/gpu/vaapi/test/h265_vaapi_wrapper.cc
index 198c90a..8c30e20 100644
--- a/media/gpu/vaapi/test/h265_vaapi_wrapper.cc
+++ b/media/gpu/vaapi/test/h265_vaapi_wrapper.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/vaapi/test/h265_vaapi_wrapper.h"
 
 #include "build/chromeos_buildflags.h"
diff --git a/media/gpu/windows/d3d11_h265_accelerator.cc b/media/gpu/windows/d3d11_h265_accelerator.cc
index a5892d2..c9a7c3c 100644
--- a/media/gpu/windows/d3d11_h265_accelerator.cc
+++ b/media/gpu/windows/d3d11_h265_accelerator.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/gpu/windows/d3d11_h265_accelerator.h"
 
 #include <algorithm>
diff --git a/media/muxers/mp4_muxer_delegate.cc b/media/muxers/mp4_muxer_delegate.cc
index 299f329..ecd7437 100644
--- a/media/muxers/mp4_muxer_delegate.cc
+++ b/media/muxers/mp4_muxer_delegate.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/muxers/mp4_muxer_delegate.h"
 
 #include "base/logging.h"
diff --git a/media/muxers/mp4_muxer_delegate_unittest.cc b/media/muxers/mp4_muxer_delegate_unittest.cc
index 89a51ed..acc1553c 100644
--- a/media/muxers/mp4_muxer_delegate_unittest.cc
+++ b/media/muxers/mp4_muxer_delegate_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/muxers/mp4_muxer_delegate.h"
 
 #include <algorithm>
diff --git a/media/parsers/h264_bit_reader.cc b/media/parsers/h264_bit_reader.cc
index fd77d320..81a5178 100644
--- a/media/parsers/h264_bit_reader.cc
+++ b/media/parsers/h264_bit_reader.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/parsers/h264_bit_reader.h"
 #include "base/check.h"
 
diff --git a/media/parsers/h265_nalu_parser.cc b/media/parsers/h265_nalu_parser.cc
index 14b50d8..b6f1dd6 100644
--- a/media/parsers/h265_nalu_parser.cc
+++ b/media/parsers/h265_nalu_parser.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/parsers/h265_nalu_parser.h"
 
 #include <stddef.h>
diff --git a/media/parsers/h265_parser.cc b/media/parsers/h265_parser.cc
index 2471638..b6211fa 100644
--- a/media/parsers/h265_parser.cc
+++ b/media/parsers/h265_parser.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/parsers/h265_parser.h"
 
 #include <stddef.h>
diff --git a/media/parsers/h265_parser_unittest.cc b/media/parsers/h265_parser_unittest.cc
index d80bb66..06d35226 100644
--- a/media/parsers/h265_parser_unittest.cc
+++ b/media/parsers/h265_parser_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include <memory>
 #include <string>
 
diff --git a/media/renderers/win/media_foundation_audio_stream.cc b/media/renderers/win/media_foundation_audio_stream.cc
index 0426c98..06ed8aa3 100644
--- a/media/renderers/win/media_foundation_audio_stream.cc
+++ b/media/renderers/win/media_foundation_audio_stream.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/renderers/win/media_foundation_audio_stream.h"
 
 #include <mferror.h>
diff --git a/media/video/openh264_video_encoder.cc b/media/video/openh264_video_encoder.cc
index 7b032065..a92ddad 100644
--- a/media/video/openh264_video_encoder.cc
+++ b/media/video/openh264_video_encoder.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "media/video/openh264_video_encoder.h"
 
 #include <algorithm>
diff --git a/mojo/public/java/system/core_impl.cc b/mojo/public/java/system/core_impl.cc
index f231f00b..f16671da6 100644
--- a/mojo/public/java/system/core_impl.cc
+++ b/mojo/public/java/system/core_impl.cc
@@ -182,13 +182,13 @@
     return Java_CoreImpl_newReadMessageResult(env, result, nullptr, nullptr);
 
   // Extend handles to 64-bit values if necessary.
-  std::vector<jlong> java_handles(handles.size());
+  std::vector<int64_t> java_handles(handles.size());
   base::ranges::copy(handles, java_handles.begin());
   return Java_CoreImpl_newReadMessageResult(
       env, result,
       base::android::ToJavaByteArray(env, static_cast<uint8_t*>(buffer),
                                      num_bytes),
-      base::android::ToJavaLongArray(env, java_handles.data(), num_handles));
+      base::android::ToJavaLongArray(env, java_handles));
 }
 
 static ScopedJavaLocalRef<jobject> JNI_CoreImpl_ReadData(
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index f92b58f..ddd2842 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -1329,8 +1329,7 @@
   mouse_middle_button_last_position_ =
       gfx::ToRoundedPoint(event.PositionInWidget());
 
-  SelectionChangeInvalidator selection_invalidator(this);
-  selection_.clear();
+  ClearTextSelection();
 
   int unused_page_index = -1;
   int unused_char_index = -1;
@@ -1403,8 +1402,9 @@
 
   // Handle the case when focus starts outside a form text area and stays
   // outside.
-  if (selection_.empty())
+  if (selection_.empty()) {
     return false;
+  }
 
   std::vector<gfx::Rect> selection_rect_vector =
       GetAllScreenRectsUnion(selection_, GetVisibleRect().origin());
@@ -1412,8 +1412,8 @@
     if (rect.Contains(point))
       return false;
   }
-  SelectionChangeInvalidator selection_invalidator(this);
-  selection_.clear();
+
+  ClearTextSelection();
   return true;
 }
 
@@ -2172,8 +2172,8 @@
   return read_only_;
 }
 
-void PDFiumEngine::SetReadOnly(bool enable) {
-  read_only_ = enable;
+void PDFiumEngine::SetReadOnly(bool read_only) {
+  read_only_ = read_only;
   SetFormHighlight(!read_only_);
   ClearTextSelection();
 }
@@ -4011,8 +4011,7 @@
   bool is_form_text_area =
       PDFiumPage::FormTypeToArea(form_type) == PDFiumPage::FORM_TEXT_AREA;
   if (is_form_text_area) {
-    SelectionChangeInvalidator selection_invalidator(this);
-    selection_.clear();
+    ClearTextSelection();
   }
   SetFieldFocus(is_form_text_area ? FocusFieldType::kText
                                   : FocusFieldType::kNonText);
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 57d1d3f..2ab92a2 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -205,7 +205,7 @@
   void RotateClockwise();
   void RotateCounterclockwise();
   bool IsReadOnly() const;
-  void SetReadOnly(bool enable);
+  void SetReadOnly(bool read_only);
   void SetDocumentLayout(DocumentLayout::PageSpread page_spread);
   void DisplayAnnotations(bool display);
 
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 1f4940bc..a4f93e0 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -727,12 +727,7 @@
 }
 
 source_set("display_layout") {
-  sources = [
-    "desktop_display_layout_util.cc",
-    "desktop_display_layout_util.h",
-    "desktop_geometry.cc",
-    "desktop_geometry.h",
-  ]
+  sources = [ "desktop_geometry.h" ]
   deps = [ "//ui/gfx" ]
 }
 
@@ -745,10 +740,6 @@
       "linux/gnome_display_config_dbus_client.h",
       "linux/scoped_glib.cc",
       "linux/scoped_glib.h",
-      "x11_crtc_resizer.cc",
-      "x11_crtc_resizer.h",
-      "x11_desktop_resizer.cc",
-      "x11_desktop_resizer.h",
       "x11_display_util.cc",
       "x11_display_util.h",
     ]
@@ -761,6 +752,7 @@
       "//ui/base",
       "//ui/base/x",
       "//ui/gfx/geometry",
+      "//ui/gfx/x",
     ]
   }
 }
@@ -828,7 +820,6 @@
     "corp_host_status_logger_unittest.cc",
     "daemon_process_unittest.cc",
     "desktop_display_info_unittest.cc",
-    "desktop_display_layout_util_unittest.cc",
     "desktop_process_unittest.cc",
     "desktop_session_agent_unittest.cc",
     "ftl_echo_message_listener_unittest.cc",
@@ -945,10 +936,7 @@
   }
 
   if (remoting_use_x11) {
-    sources += [
-      "x11_crtc_resizer_unittest.cc",
-      "x11_display_util_unittest.cc",
-    ]
+    sources += [ "x11_display_util_unittest.cc" ]
     deps += [
       ":x11_display_utils",
       "//ui/gfx/x",
diff --git a/remoting/host/desktop_display_layout_util.cc b/remoting/host/desktop_display_layout_util.cc
deleted file mode 100644
index 387ac04..0000000
--- a/remoting/host/desktop_display_layout_util.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/desktop_display_layout_util.h"
-
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "base/ranges/algorithm.h"
-
-namespace remoting {
-
-DisplayLayoutDiff::DisplayLayoutDiff() = default;
-DisplayLayoutDiff::DisplayLayoutDiff(const DisplayLayoutDiff&) = default;
-DisplayLayoutDiff::DisplayLayoutDiff(DisplayLayoutDiff&&) = default;
-DisplayLayoutDiff::~DisplayLayoutDiff() = default;
-
-DisplayLayoutDiff CalculateDisplayLayoutDiff(
-    const std::vector<DesktopLayoutWithContext>& current_displays,
-    const DesktopLayoutSet& new_layout) {
-  DisplayLayoutDiff diff;
-
-  // A list where the index is the index of |current_displays| and the value
-  // denotes whether the display is found in the new layout. Used to detect
-  // deletion of displays.
-  std::vector<bool> current_display_found(current_displays.size(), false);
-
-  for (const DesktopLayout& track_layout : new_layout.layouts) {
-    if (!track_layout.screen_id().has_value()) {
-      diff.new_displays.layouts.push_back(track_layout);
-      continue;
-    }
-    auto current_display_it = base::ranges::find(
-        current_displays, track_layout.screen_id(),
-        [](const auto& display) { return display.layout.screen_id(); });
-    if (current_display_it == current_displays.end()) {
-      LOG(ERROR) << "Ignoring unknown screen_id " << *track_layout.screen_id();
-      continue;
-    }
-    current_display_found[current_display_it - current_displays.begin()] = true;
-    if (track_layout.position_x() != current_display_it->layout.position_x() ||
-        track_layout.position_y() != current_display_it->layout.position_y() ||
-        track_layout.width() != current_display_it->layout.width() ||
-        track_layout.height() != current_display_it->layout.height() ||
-        track_layout.dpi().x() != current_display_it->layout.dpi().x() ||
-        track_layout.dpi().y() != current_display_it->layout.dpi().y()) {
-      VLOG(1) << "Video layout for screen_id " << *track_layout.screen_id()
-              << " has been changed.";
-      diff.updated_displays.emplace_back(track_layout,
-                                         current_display_it->context);
-    } else {
-      VLOG(1) << "Video layout for screen_id " << *track_layout.screen_id()
-              << " has not been changed.";
-    }
-  }
-
-  for (size_t i = 0u; i < current_display_found.size(); i++) {
-    if (!current_display_found[i]) {
-      diff.removed_displays.push_back(current_displays[i]);
-    }
-  }
-  return diff;
-}
-
-}  // namespace remoting
diff --git a/remoting/host/desktop_display_layout_util.h b/remoting/host/desktop_display_layout_util.h
deleted file mode 100644
index 9cc03d8..0000000
--- a/remoting/host/desktop_display_layout_util.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_HOST_DESKTOP_DISPLAY_LAYOUT_UTIL_H_
-#define REMOTING_HOST_DESKTOP_DISPLAY_LAYOUT_UTIL_H_
-
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "remoting/host/desktop_geometry.h"
-
-namespace remoting {
-
-// Struct that allows passing in the display layout with a context, usually a
-// platform-specific representation of the display.
-struct DesktopLayoutWithContext {
-  DesktopLayout layout;
-  raw_ptr<void> context;
-};
-
-struct DisplayLayoutDiff {
-  DisplayLayoutDiff();
-  DisplayLayoutDiff(const DisplayLayoutDiff&);
-  DisplayLayoutDiff(DisplayLayoutDiff&&);
-  ~DisplayLayoutDiff();
-
-  DesktopLayoutSet new_displays;
-  std::vector<DesktopLayoutWithContext> updated_displays;
-  std::vector<DesktopLayoutWithContext> removed_displays;
-};
-
-// Calculates the difference between the current display layout and the new
-// display layout. Displays are matched using the screen ID.
-DisplayLayoutDiff CalculateDisplayLayoutDiff(
-    const std::vector<DesktopLayoutWithContext>& current_displays,
-    const DesktopLayoutSet& new_layout);
-
-}  // namespace remoting
-
-#endif  // REMOTING_HOST_DESKTOP_DISPLAY_LAYOUT_UTIL_H_
diff --git a/remoting/host/desktop_display_layout_util_unittest.cc b/remoting/host/desktop_display_layout_util_unittest.cc
deleted file mode 100644
index 9704038e..0000000
--- a/remoting/host/desktop_display_layout_util_unittest.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/desktop_display_layout_util.h"
-
-#include <optional>
-#include <vector>
-
-#include "build/build_config.h"
-#include "remoting/host/desktop_geometry.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/vector2d.h"
-
-namespace remoting {
-
-std::ostream& operator<<(std::ostream& os, const DesktopLayout& layout) {
-  if (layout.screen_id().has_value()) {
-    os << *layout.screen_id() << ": ";
-  } else {
-    os << "(no screen id): ";
-  }
-  return os << layout.position_x() << "," << layout.position_y() << " : "
-            << layout.width() << "x" << layout.height() << " @ "
-            << layout.dpi().x() << "x" << layout.dpi().y();
-}
-
-namespace {
-
-remoting::DesktopLayout MakeLayout(int position_x,
-                                   int position_y,
-                                   int width,
-                                   int height,
-                                   int x_dpi,
-                                   int y_dpi,
-                                   std::optional<int64_t> screen_id) {
-  return remoting::DesktopLayout(
-      screen_id, gfx::Rect(position_x, position_y, width, height),
-      gfx::Vector2d(x_dpi, y_dpi));
-}
-
-void* ContextOf(int i) {
-  return reinterpret_cast<void*>(i);
-}
-
-}  // namespace
-
-std::ostream& operator<<(
-    std::ostream& os,
-    const remoting::DesktopLayoutWithContext& layout_with_context) {
-  return os << "{layout=" << layout_with_context.layout
-            << ", context=" << layout_with_context.context << "}";
-}
-
-bool operator==(const remoting::DesktopLayoutWithContext& a,
-                const remoting::DesktopLayoutWithContext& b) {
-  return a.layout == b.layout && a.context == b.context;
-}
-
-TEST(DesktopDisplayLayoutUtilTest, CalculateDisplayLayoutDiff) {
-  std::vector<DesktopLayoutWithContext> current_displays = {
-      {.layout = MakeLayout(0, 0, 1230, 1230, 96, 96, 123),
-       .context = ContextOf(1)},
-      {.layout = MakeLayout(1230, 0, 2340, 2340, 192, 192, 234),
-       .context = ContextOf(2)},
-      {.layout = MakeLayout(0, 1230, 3450, 3450, 96, 96, 345),
-       .context = ContextOf(3)}};
-  DesktopLayoutSet new_layout(
-      {// Updated.
-       MakeLayout(3450, 1230, 2340, 2000, 100, 96, 234),
-       // Unchanged.
-       MakeLayout(0, 1230, 3450, 3450, 96, 96, 345),
-       // New.
-       MakeLayout(3450, 3450, 4560, 4560, 192, 192, {})});
-  auto diff = CalculateDisplayLayoutDiff(current_displays, new_layout);
-
-  DesktopLayoutSet expected_new_displays;
-  expected_new_displays.layouts.push_back(
-      MakeLayout(3450, 3450, 4560, 4560, 192, 192, {}));
-  EXPECT_EQ(diff.new_displays, expected_new_displays);
-
-  std::vector<DesktopLayoutWithContext> expected_updated_displays = {
-      {.layout = MakeLayout(3450, 1230, 2340, 2000, 100, 96, 234),
-       .context = ContextOf(2)}};
-  EXPECT_EQ(diff.updated_displays, expected_updated_displays);
-
-  std::vector<DesktopLayoutWithContext> expected_removed_displays = {
-      {.layout = MakeLayout(0, 0, 1230, 1230, 96, 96, 123),
-       .context = ContextOf(1)}};
-  EXPECT_EQ(diff.removed_displays, expected_removed_displays);
-}
-
-}  // namespace remoting
diff --git a/remoting/host/desktop_geometry.cc b/remoting/host/desktop_geometry.cc
deleted file mode 100644
index f08b6b1..0000000
--- a/remoting/host/desktop_geometry.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/desktop_geometry.h"
-
-namespace remoting {
-
-bool DesktopLayout::operator==(const DesktopLayout& rhs) const = default;
-DesktopLayout::DesktopLayout(const DesktopLayout& other) = default;
-DesktopLayout& DesktopLayout::operator=(const DesktopLayout& other) = default;
-
-DesktopLayoutSet::DesktopLayoutSet() = default;
-DesktopLayoutSet::DesktopLayoutSet(const DesktopLayoutSet&) = default;
-DesktopLayoutSet::DesktopLayoutSet(const std::vector<DesktopLayout> layouts)
-    : layouts(layouts) {}
-DesktopLayoutSet& DesktopLayoutSet::operator=(const DesktopLayoutSet&) =
-    default;
-DesktopLayoutSet::~DesktopLayoutSet() = default;
-bool DesktopLayoutSet::operator==(const DesktopLayoutSet& rhs) const = default;
-
-}  // namespace remoting
diff --git a/remoting/host/desktop_geometry.h b/remoting/host/desktop_geometry.h
index f3ddc7f4..de737df 100644
--- a/remoting/host/desktop_geometry.h
+++ b/remoting/host/desktop_geometry.h
@@ -5,17 +5,10 @@
 #ifndef REMOTING_HOST_DESKTOP_GEOMETRY_H_
 #define REMOTING_HOST_DESKTOP_GEOMETRY_H_
 
-#include <optional>
-#include <vector>
-
-#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/vector2d.h"
 
 namespace remoting {
-using DesktopScreenId = intptr_t;
-
-const DesktopScreenId kFullDesktopScreenId = -1;
 
 class DesktopResolution {
  public:
@@ -29,46 +22,6 @@
   gfx::Vector2d dpi_;
 };
 
-class DesktopLayout {
- public:
-  DesktopLayout(std::optional<int64_t> screen_id,
-                gfx::Rect rect,
-                gfx::Vector2d dpi)
-      : screen_id_(screen_id), rect_(rect), dpi_(dpi) {}
-  DesktopLayout(const DesktopLayout& other);
-  DesktopLayout& operator=(const DesktopLayout& other);
-  bool operator==(const DesktopLayout& rhs) const;
-
-  std::optional<int64_t> screen_id() const { return screen_id_; }
-  void set_screen_id(int64_t id) { screen_id_ = id; }
-
-  const gfx::Rect& rect() const { return rect_; }
-  const gfx::Vector2d& dpi() const { return dpi_; }
-  // Make this struct API shape like VideoTrackLayout proto in
-  // //remoting/proto/control.proto
-  int width() const { return rect().width(); }
-  int height() const { return rect().height(); }
-  int position_x() const { return rect().x(); }
-  int position_y() const { return rect().y(); }
-
- private:
-  std::optional<int64_t> screen_id_;
-  gfx::Rect rect_;
-  gfx::Vector2d dpi_;
-};
-
-struct DesktopLayoutSet {
-  DesktopLayoutSet();
-  DesktopLayoutSet(const DesktopLayoutSet&);
-  explicit DesktopLayoutSet(const std::vector<DesktopLayout> layouts);
-  DesktopLayoutSet& operator=(const DesktopLayoutSet&);
-  ~DesktopLayoutSet();
-  bool operator==(const DesktopLayoutSet& rhs) const;
-
-  std::vector<DesktopLayout> layouts;
-  std::optional<int64_t> primary_screen_id;
-};
-
 }  // namespace remoting
 
 #endif  // REMOTING_HOST_DESKTOP_GEOMETRY_H_
diff --git a/remoting/host/desktop_resizer_x11.cc b/remoting/host/desktop_resizer_x11.cc
index afa396d..8ea08d51 100644
--- a/remoting/host/desktop_resizer_x11.cc
+++ b/remoting/host/desktop_resizer_x11.cc
@@ -4,79 +4,276 @@
 
 #include "remoting/host/desktop_resizer_x11.h"
 
-#include <optional>
+#include <gio/gio.h>
 
-#include "base/ranges/algorithm.h"
-#include "remoting/host/base/screen_resolution.h"
+#include <algorithm>
+#include <cstdlib>
+#include <iterator>
+#include <memory>
+#include <ranges>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/system/sys_info.h"
+#include "base/types/cxx23_to_underlying.h"
+#include "remoting/base/logging.h"
 #include "remoting/host/desktop_geometry.h"
-#include "ui/gfx/geometry/rect.h"
+#include "remoting/host/linux/x11_util.h"
+#include "remoting/host/x11_display_util.h"
 #include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/x/future.h"
+#include "ui/gfx/x/randr.h"
+#include "ui/gfx/x/x11_crtc_resizer.h"
 
 namespace remoting {
 
 namespace {
 
-ScreenResolution DesktopResolutionToScreenResolution(
-    const DesktopResolution& resolution) {
-  return ScreenResolution(
-      webrtc::DesktopSize(resolution.dimensions().width(),
-                          resolution.dimensions().height()),
-      webrtc::DesktopVector(resolution.dpi().x(), resolution.dpi().y()));
-}
+// TODO(jamiewalch): Use the correct DPI for the mode: http://crbug.com/172405.
+const int kDefaultDPI = 96;
+constexpr base::TimeDelta kGnomeWaitTime = base::Seconds(1);
 
-DesktopResolution ScreenResolutionToDesktopResolution(
-    const ScreenResolution& resolution) {
-  return DesktopResolution(
-      gfx::Size(resolution.dimensions().width(),
-                resolution.dimensions().height()),
-      gfx::Vector2d(resolution.dpi().x(), resolution.dpi().y()));
+uint32_t GetDotClockForModeInfo() {
+  static int proc_num = base::SysInfo::NumberOfProcessors();
+  // Keep the proc_num logic in sync with linux_me2me_host.py
+  if (proc_num > 16) {
+    return 120 * 1e6;
+  }
+  return 60 * 1e6;
 }
 
 }  // namespace
 
-DesktopResizerX11::DesktopResizerX11() = default;
+DesktopResizerX11::DesktopResizerX11()
+    : connection_(x11::Connection::Get()),
+      randr_output_manager_("CRD_", GetDotClockForModeInfo()),
+      is_virtual_session_(IsVirtualSession(connection_)) {
+  has_randr_ = RandR()->present();
+  if (!has_randr_) {
+    return;
+  }
+  RandR()->SelectInput({RootWindow(), x11::RandR::NotifyMask::ScreenChange});
+
+  gnome_display_config_.Init();
+  registry_ = TakeGObject(g_settings_new("org.gnome.desktop.interface"));
+}
+
 DesktopResizerX11::~DesktopResizerX11() = default;
 
 // DesktopResizer interface
 ScreenResolution DesktopResizerX11::GetCurrentResolution(
     webrtc::ScreenId screen_id) {
-  return DesktopResolutionToScreenResolution(
-      resizer_.GetCurrentResolution(static_cast<DesktopScreenId>(screen_id)));
+  // Process pending events so that the connection setup data is updated
+  // with the correct display metrics.
+  if (has_randr_) {
+    connection_->DispatchAll();
+  }
+
+  // RANDR does not allow fetching information on a particular monitor. So
+  // fetch all of them and try to find the requested monitor.
+  auto reply = RandR()->GetMonitors({RootWindow()}).Sync();
+  if (reply) {
+    for (const auto& monitor : reply->monitors) {
+      if (static_cast<x11::RandRMonitorConfig::ScreenId>(monitor.name) !=
+          static_cast<x11::RandRMonitorConfig::ScreenId>(screen_id)) {
+        continue;
+      }
+      gfx::Vector2d dpi = GetMonitorDpi(monitor);
+      return ScreenResolution(
+          webrtc::DesktopSize(monitor.width, monitor.height),
+          webrtc::DesktopVector(dpi.x(), dpi.y()));
+    }
+  }
+
+  LOG(ERROR) << "Cannot find current resolution for screen ID " << screen_id
+             << ". Resolution of the default screen will be returned.";
+
+  return ScreenResolution(
+      webrtc::DesktopSize(connection_->default_screen().width_in_pixels,
+                          connection_->default_screen().height_in_pixels),
+      webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
 }
 std::list<ScreenResolution> DesktopResizerX11::GetSupportedResolutions(
     const ScreenResolution& preferred,
     webrtc::ScreenId screen_id) {
-  std::list<DesktopResolution> resolutions = resizer_.GetSupportedResolutions(
-      ScreenResolutionToDesktopResolution(preferred), screen_id);
   std::list<ScreenResolution> result;
-  base::ranges::transform(resolutions, std::back_inserter(result),
-                          DesktopResolutionToScreenResolution);
+  if (!has_randr_ || !is_virtual_session_) {
+    return result;
+  }
+
+  // Clamp the specified size to something valid for the X server.
+  if (auto response = RandR()->GetScreenSizeRange({RootWindow()}).Sync()) {
+    int width =
+        std::clamp(static_cast<uint16_t>(preferred.dimensions().width()),
+                   response->min_width, response->max_width);
+    int height =
+        std::clamp(static_cast<uint16_t>(preferred.dimensions().height()),
+                   response->min_height, response->max_height);
+    // Additionally impose a minimum size of 640x480, since anything smaller
+    // doesn't seem very useful.
+    result.emplace_back(
+        webrtc::DesktopSize(std::max(640, width), std::max(480, height)),
+        preferred.dpi());
+  }
   return result;
 }
 void DesktopResizerX11::SetResolution(const ScreenResolution& resolution,
                                       webrtc::ScreenId screen_id) {
-  resizer_.SetResolution(ScreenResolutionToDesktopResolution(resolution),
-                         screen_id);
+  if (!has_randr_ || !is_virtual_session_) {
+    return;
+  }
+
+  // Grab the X server while we're changing the display resolution. This
+  // ensures that the display configuration doesn't change under our feet.
+  x11::ScopedXGrabServer grabber(connection_);
+
+  // RANDR does not allow fetching information on a particular monitor. So
+  // fetch all of them and try to find the requested monitor.
+  std::vector<x11::RandR::MonitorInfo> monitors;
+  if (!randr_output_manager_.TryGetCurrentMonitors(monitors)) {
+    return;
+  }
+
+  for (const auto& monitor : monitors) {
+    if (static_cast<x11::RandRMonitorConfig::ScreenId>(monitor.name) !=
+        static_cast<x11::RandRMonitorConfig::ScreenId>(screen_id)) {
+      continue;
+    }
+
+    if (monitor.outputs.size() != 1) {
+      // This implementation only supports resizing a Monitor attached to a
+      // single output. The case where size() > 1 should never occur with
+      // Xorg+video-dummy.
+      // TODO(crbug.com/40225767): Maybe support resizing a Monitor not
+      // attached to any Output?
+      LOG(ERROR) << "Monitor " << screen_id
+                 << " has unexpected #outputs: " << monitor.outputs.size();
+      return;
+    }
+
+    if (!monitor.automatic) {
+      // This implementation only supports resizing synthesized Monitors which
+      // automatically track their Outputs.
+      // TODO(crbug.com/40225767): Maybe support resizing manually-created
+      // Monitors?
+      LOG(ERROR) << "Not resizing Monitor " << screen_id
+                 << " that was created manually.";
+      return;
+    }
+
+    SetResolutionForOutput(monitor.outputs[0], resolution);
+    return;
+  }
+  LOG(ERROR) << "Monitor " << screen_id << " not found.";
 }
+
 void DesktopResizerX11::RestoreResolution(const ScreenResolution& original,
                                           webrtc::ScreenId screen_id) {
-  resizer_.SetResolution(ScreenResolutionToDesktopResolution(original),
-                         screen_id);
+  SetResolution(original, screen_id);
 }
+
 void DesktopResizerX11::SetVideoLayout(const protocol::VideoLayout& layout) {
-  DesktopLayoutSet desktop_layouts;
+  if (!has_randr_ || !is_virtual_session_) {
+    return;
+  }
+  x11::RandRMonitorLayout desktop_layouts;
   if (layout.has_primary_screen_id()) {
     desktop_layouts.primary_screen_id = layout.primary_screen_id();
   }
   for (const auto& track : layout.video_track()) {
-    desktop_layouts.layouts.emplace_back(
+    desktop_layouts.configs.emplace_back(
         track.has_screen_id() ? std::make_optional(track.screen_id())
                               : std::nullopt,
         gfx::Rect(track.position_x(), track.position_y(), track.width(),
                   track.height()),
         gfx::Vector2d(track.x_dpi(), track.y_dpi()));
   }
-  resizer_.SetVideoLayout(desktop_layouts);
+  randr_output_manager_.SetLayout(desktop_layouts);
+}
+
+void DesktopResizerX11::SetResolutionForOutput(
+    x11::RandR::Output output,
+    const ScreenResolution& resolution) {
+  // Actually do the resize operation, preserving the current mode name. Note
+  // that we have to detach the output from the mode in order to delete the
+  // mode and re-create it with the new resolution. The output may also need to
+  // be detached from all modes in order to reduce the root window size.
+  HOST_LOG << "Resizing RANDR Output " << base::to_underlying(output) << " to "
+           << resolution.dimensions().width() << "x"
+           << resolution.dimensions().height();
+
+  randr_output_manager_.SetResolutionForOutput(
+      output,
+      gfx::Size(resolution.dimensions().width(),
+                resolution.dimensions().height()),
+      gfx::Vector2d(resolution.dpi().x(), resolution.dpi().y()));
+
+  // Check to see if GNOME is using automatic-scaling. If the value is non-zero,
+  // the user prefers a particular scaling, so don't adjust the
+  // text-scaling-factor here.
+  if (g_settings_get_uint(registry_.get(), "scaling-factor") == 0U) {
+    // Start the timer to update the text-scaling-factor. Any previously
+    // started timer will be cancelled.
+    requested_dpi_ = resolution.dpi().x();
+    gnome_delay_timer_.Start(FROM_HERE, kGnomeWaitTime, this,
+                             &DesktopResizerX11::RequestGnomeDisplayConfig);
+  }
+}
+
+void DesktopResizerX11::RequestGnomeDisplayConfig() {
+  // Unretained() is safe because `this` owns gnome_display_config_ which
+  // cancels callbacks on destruction.
+  gnome_display_config_.GetMonitorsConfig(
+      base::BindOnce(&DesktopResizerX11::OnGnomeDisplayConfigReceived,
+                     base::Unretained(this)));
+}
+
+void DesktopResizerX11::OnGnomeDisplayConfigReceived(
+    GnomeDisplayConfig config) {
+  // Look for an enabled monitor. Disabled monitors have no Mode set - a
+  // monitor can become disabled by being added then removed (using the website
+  // Display options). The Xorg xf86-video-dummy driver has a quirk that, once a
+  // monitor becomes "connected", it stays forever in the connected state, even
+  // if it is later disabled. All connected monitors (enabled or disabled) are
+  // included in the GNOME config.
+
+  // For X11, the calculation of the text-scaling-factor does not depend on
+  // which enabled monitor is chosen here, because GNOME's X11 backend forces
+  // all monitors to have the same scale. However, it makes sense to select
+  // an enabled monitor, since a disabled monitor might not have a reliable
+  // "scale" property returned by GNOME.
+  auto monitor_iter =
+      base::ranges::find_if(config.monitors, [](const auto& entry) {
+        return entry.second.GetCurrentMode() != nullptr;
+      });
+  if (monitor_iter == std::ranges::end(config.monitors)) {
+    LOG(ERROR) << "No enabled monitor found in GNOME config.";
+    return;
+  }
+  const auto& monitor = monitor_iter->second;
+
+  if (monitor.scale == 0) {
+    // This should never happen - avoid division by 0.
+    return;
+  }
+
+  // The GNOME scaling, multiplied by the GNOME text-scaling-factor, will be the
+  // rendered scaling of text. This should be the client's requested DPI divided
+  // by kDefaultDPI.
+  double text_scaling_factor =
+      static_cast<double>(requested_dpi_) / kDefaultDPI / monitor.scale;
+  HOST_LOG << "Target DPI = " << requested_dpi_
+           << ", GNOME scale = " << monitor.scale
+           << ", calculated text-scaling = " << text_scaling_factor;
+
+  if (!g_settings_set_double(registry_.get(), "text-scaling-factor",
+                             text_scaling_factor)) {
+    // Just log a warning - failure is expected if the value falls outside the
+    // interval [0.5, 3.0].
+    LOG(WARNING) << "Failed to set text-scaling-factor.";
+  }
 }
 
 }  // namespace remoting
diff --git a/remoting/host/desktop_resizer_x11.h b/remoting/host/desktop_resizer_x11.h
index c8e426c..ce39ef8 100644
--- a/remoting/host/desktop_resizer_x11.h
+++ b/remoting/host/desktop_resizer_x11.h
@@ -5,8 +5,12 @@
 #ifndef REMOTING_HOST_DESKTOP_RESIZER_X11_H_
 #define REMOTING_HOST_DESKTOP_RESIZER_X11_H_
 
+#include "base/timer/timer.h"
 #include "remoting/host/desktop_resizer.h"
-#include "remoting/host/x11_desktop_resizer.h"
+#include "remoting/host/linux/gnome_display_config.h"
+#include "remoting/host/linux/gnome_display_config_dbus_client.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/randr_output_manager.h"
 
 namespace remoting {
 
@@ -29,7 +33,40 @@
   void SetVideoLayout(const protocol::VideoLayout& layout) override;
 
  private:
-  X11DesktopResizer resizer_;
+  using OutputInfoList = std::vector<
+      std::pair<x11::RandR::Output, x11::RandR::GetOutputInfoReply>>;
+
+  // Add a mode matching the specified resolution and switch to it.
+  void SetResolutionForOutput(x11::RandR::Output output,
+                              const ScreenResolution& resolution);
+
+  // Gets a list of outputs that are not connected to any CRTCs.
+  OutputInfoList GetDisabledOutputs();
+
+  void RequestGnomeDisplayConfig();
+  void OnGnomeDisplayConfigReceived(GnomeDisplayConfig config);
+
+  x11::RandR* RandR() const { return &connection_->randr(); }
+  const x11::Window& RootWindow() const {
+    return connection_->default_screen().root;
+  }
+
+  raw_ptr<x11::Connection> connection_;
+  x11::RandROutputManager randr_output_manager_;
+  bool has_randr_;
+  bool is_virtual_session_;
+
+  // Used to fetch GNOME's current scale setting, so the correct
+  // text-scaling-factor can be calculated.
+  GnomeDisplayConfigDBusClient gnome_display_config_;
+
+  // Used to rate-limit requests to GNOME.
+  base::OneShotTimer gnome_delay_timer_;
+
+  int requested_dpi_;
+
+  // Used to set the text-scaling-factor.
+  ScopedGObject<GSettings> registry_;
 };
 
 }  // namespace remoting
diff --git a/remoting/host/host_config.cc b/remoting/host/host_config.cc
index 33ca8da..ea297e10 100644
--- a/remoting/host/host_config.cc
+++ b/remoting/host/host_config.cc
@@ -28,6 +28,7 @@
 const char kCorpHostTypeHint[] = "corp";
 const char kCloudHostTypeHint[] = "cloud";
 const char kMe2MeHostTypeHint[] = "me2me";
+const char kCloudApiKeyPath[] = "cloud_api_key";
 
 // Deprecated values.
 const char kDeprecatedHostOwnerEmailConfigPath[] = "host_owner_email";
diff --git a/remoting/host/host_config.h b/remoting/host/host_config.h
index 63e153b..5cee5cf 100644
--- a/remoting/host/host_config.h
+++ b/remoting/host/host_config.h
@@ -56,6 +56,12 @@
 extern const char kCloudHostTypeHint[];
 extern const char kMe2MeHostTypeHint[];
 
+// The API_KEY used for Cloud API service requests. Note that this is only used
+// for billing and quota purposes and is does not provide authn/authz. Using an
+// API_KEY for a different project than where the request originates from will
+// result in the request being rejected.
+extern const char kCloudApiKeyPath[];
+
 // Deprecated keys. These keys were used in pre-M120 host versions and are being
 // kept around for backward compatibility. We should consider rewriting the
 // config file at some point so we no longer need to support them.
diff --git a/remoting/host/linux/x11_util.cc b/remoting/host/linux/x11_util.cc
index 06d0135..e84f28f 100644
--- a/remoting/host/linux/x11_util.cc
+++ b/remoting/host/linux/x11_util.cc
@@ -17,16 +17,6 @@
 
 namespace remoting {
 
-ScopedXGrabServer::ScopedXGrabServer(x11::Connection* connection)
-    : connection_(connection) {
-  connection_->GrabServer();
-}
-
-ScopedXGrabServer::~ScopedXGrabServer() {
-  connection_->UngrabServer();
-  connection_->Flush();
-}
-
 bool IgnoreXServerGrabs(x11::Connection* connection, bool ignore) {
   if (!connection->xtest().present()) {
     return false;
diff --git a/remoting/host/linux/x11_util.h b/remoting/host/linux/x11_util.h
index 44d82ea..6b95266 100644
--- a/remoting/host/linux/x11_util.h
+++ b/remoting/host/linux/x11_util.h
@@ -19,21 +19,6 @@
 
 namespace remoting {
 
-// Grab/release the X server within a scope. This can help avoid race
-// conditions that would otherwise lead to X errors.
-class ScopedXGrabServer {
- public:
-  explicit ScopedXGrabServer(x11::Connection* connection);
-
-  ScopedXGrabServer(const ScopedXGrabServer&) = delete;
-  ScopedXGrabServer& operator=(const ScopedXGrabServer&) = delete;
-
-  ~ScopedXGrabServer();
-
- private:
-  raw_ptr<x11::Connection> connection_;
-};
-
 // Make a connection to the X Server impervious to X Server grabs. Returns
 // true if successful or false if the required XTEST extension is not present.
 bool IgnoreXServerGrabs(x11::Connection* connection, bool ignore);
diff --git a/remoting/host/setup/cloud_host_starter.cc b/remoting/host/setup/cloud_host_starter.cc
index 42e6215d..151a6a2 100644
--- a/remoting/host/setup/cloud_host_starter.cc
+++ b/remoting/host/setup/cloud_host_starter.cc
@@ -15,6 +15,8 @@
 #include "base/sequence_checker.h"
 #include "remoting/base/cloud_service_client.h"
 #include "remoting/base/protobuf_http_status.h"
+#include "remoting/host/host_config.h"
+#include "remoting/host/pin_hash.h"
 #include "remoting/host/setup/host_starter.h"
 #include "remoting/host/setup/host_starter_base.h"
 #include "remoting/proto/google/internal/remoting/cloud/v1alpha/remote_access_service.pb.h"
@@ -45,6 +47,7 @@
   void RegisterNewHost(const std::string& public_key,
                        std::optional<std::string> access_token) override;
   void RemoveOldHostFromDirectory(base::OnceClosure on_host_removed) override;
+  void ApplyConfigValues(base::Value::Dict& config) override;
 
   // CloudServiceClient callback.
   void OnProvisionGceInstanceResponse(
@@ -137,6 +140,25 @@
   std::move(on_host_removed).Run();
 }
 
+void CloudHostStarter::ApplyConfigValues(base::Value::Dict& config) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // The legacy code is taken when an API_KEY is not provided. In that case, the
+  // host acts like a Me2Me host rather than a Cloud host. Note that is kept for
+  // compatibility reasons but is not going to be supported long-term.
+  // TODO: joedow - Remove this when all Cloud hosts are required to use the
+  // Cloud API.
+  if (params().api_key.empty()) {
+    config.Set(kHostTypeHintPath, kMe2MeHostTypeHint);
+    config.Set(kHostSecretHashConfigPath,
+               MakeHostPinHash(params().id, params().pin));
+  } else {
+    config.Set(kHostTypeHintPath, kCloudHostTypeHint);
+    config.Set(kRequireSessionAuthorizationPath, true);
+    config.Set(kCloudApiKeyPath, params().api_key);
+  }
+}
+
 }  // namespace
 
 std::unique_ptr<HostStarter> ProvisionCloudInstance(
diff --git a/remoting/host/setup/corp_host_starter.cc b/remoting/host/setup/corp_host_starter.cc
index 76b037c2..bcc6043 100644
--- a/remoting/host/setup/corp_host_starter.cc
+++ b/remoting/host/setup/corp_host_starter.cc
@@ -19,6 +19,7 @@
 #include "remoting/base/corp_service_client.h"
 #include "remoting/base/internal_headers.h"
 #include "remoting/base/protobuf_http_status.h"
+#include "remoting/host/host_config.h"
 #include "remoting/host/setup/buildflags.h"
 #include "remoting/host/setup/host_starter.h"
 #include "remoting/host/setup/host_starter_base.h"
@@ -43,6 +44,7 @@
   void RegisterNewHost(const std::string& public_key,
                        std::optional<std::string> access_token) override;
   void RemoveOldHostFromDirectory(base::OnceClosure on_host_removed) override;
+  void ApplyConfigValues(base::Value::Dict& config) override;
   void ReportError(const std::string& error_message,
                    base::OnceClosure on_error_reported) override;
 
@@ -107,6 +109,13 @@
   std::move(on_host_removed).Run();
 }
 
+void CorpHostStarter::ApplyConfigValues(base::Value::Dict& config) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  config.Set(kRequireSessionAuthorizationPath, true);
+  config.Set(kHostTypeHintPath, kCorpHostTypeHint);
+}
+
 void CorpHostStarter::ReportError(const std::string& message,
                                   base::OnceClosure on_error_reported) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/remoting/host/setup/host_starter_base.cc b/remoting/host/setup/host_starter_base.cc
index 6c97c32..ba86ebfe 100644
--- a/remoting/host/setup/host_starter_base.cc
+++ b/remoting/host/setup/host_starter_base.cc
@@ -26,7 +26,6 @@
 #include "remoting/base/fqdn.h"
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/host/host_config.h"
-#include "remoting/host/pin_hash.h"
 #include "remoting/host/setup/daemon_controller.h"
 #include "remoting/host/setup/host_starter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -240,22 +239,7 @@
     config.Set(kHostNameConfigPath, start_host_params_.name);
   }
 
-  // TODO: joedow - Handle Cloud hosts here.
-  if (!start_host_params_.username.empty()) {
-    // Configuring for a username means session authorization is required.
-    // TODO: joedow - Replace this check once we have access to the robot scopes
-    // and can set this for Corp and Cloud hosts.
-    config.Set(kRequireSessionAuthorizationPath, true);
-    config.Set(kHostTypeHintPath, kCorpHostTypeHint);
-  } else {
-    config.Set(kHostTypeHintPath, kMe2MeHostTypeHint);
-
-    if (!start_host_params_.pin.empty()) {
-      std::string host_secret_hash = remoting::MakeHostPinHash(
-          start_host_params_.id, start_host_params_.pin);
-      config.Set(kHostSecretHashConfigPath, host_secret_hash);
-    }
-  }
+  ApplyConfigValues(config);
 
   config.Set(kUsageStatsConsentConfigPath,
              start_host_params_.enable_crash_reporting);
diff --git a/remoting/host/setup/host_starter_base.h b/remoting/host/setup/host_starter_base.h
index bf3026c..a370986 100644
--- a/remoting/host/setup/host_starter_base.h
+++ b/remoting/host/setup/host_starter_base.h
@@ -82,6 +82,7 @@
   void StopOldHost();
   void OnOldHostStopped(DaemonController::AsyncResult result);
   void GenerateConfigFile();
+  virtual void ApplyConfigValues(base::Value::Dict& config) = 0;
   void OnNewHostStarted(DaemonController::AsyncResult result);
 
   // |HandleError| will cause |on_done_| to be executed.
diff --git a/remoting/host/setup/host_starter_base_unittest.cc b/remoting/host/setup/host_starter_base_unittest.cc
index a726da2..630e6dd6 100644
--- a/remoting/host/setup/host_starter_base_unittest.cc
+++ b/remoting/host/setup/host_starter_base_unittest.cc
@@ -51,6 +51,9 @@
 constexpr char kTestDirectoryId[] = "test_directory_id";
 constexpr char kTestMachineName[] = "test_machine_name";
 
+constexpr char kTestConfigValuePath[] = "test_config_value";
+constexpr char kTestConfigValue[] = "so_much_value";
+
 class TestDaemonControllerDelegate : public DaemonController::Delegate {
  public:
   TestDaemonControllerDelegate();
@@ -154,6 +157,7 @@
   void RegisterNewHost(const std::string& public_key,
                        std::optional<std::string> access_token) override;
   void RemoveOldHostFromDirectory(base::OnceClosure on_removed) override;
+  void ApplyConfigValues(base::Value::Dict& config) override;
   void ReportError(const std::string& error_message,
                    base::OnceClosure on_done) override;
 
@@ -210,6 +214,10 @@
   std::move(on_removed).Run();
 }
 
+void TestHostStarter::ApplyConfigValues(base::Value::Dict& config) {
+  config.Set(kTestConfigValuePath, kTestConfigValue);
+}
+
 void TestHostStarter::ReportError(const std::string& error_message,
                                   base::OnceClosure on_done) {
   error_message_ = error_message;
@@ -356,9 +364,10 @@
   value = config->FindString(kHostNameConfigPath);
   ASSERT_NE(value, nullptr);
   EXPECT_EQ(*value, kTestMachineName);
-  // Just check for existence here.
-  EXPECT_TRUE(config->FindString(kPrivateKeyConfigPath));
-  EXPECT_TRUE(config->FindString(kHostSecretHashConfigPath));
+  // Verify subclass value was applied.
+  value = config->FindString(kTestConfigValuePath);
+  ASSERT_NE(value, nullptr);
+  EXPECT_EQ(*value, kTestConfigValue);
 
   // Verify Stop() was not called.
   EXPECT_FALSE(test_daemon_controller_delegate().stop_called());
@@ -366,7 +375,7 @@
 
 TEST_F(HostStarterBaseTest, CorpCodePath) {
   HostStarter::Params params;
-  params.owner_email = kTestUserEmail;
+  params.username = kTestUserEmail;
 
   test_host_starter().StartHost(std::move(params), GetCompletionCallback());
   RunUntilQuit();
@@ -395,10 +404,10 @@
   EXPECT_EQ(*value, kTestDirectoryId);
   // We use the value from GetHostname() if no name is provided.
   EXPECT_TRUE(config->FindString(kHostNameConfigPath));
-  // Just check for existence here.
-  EXPECT_TRUE(config->FindString(kPrivateKeyConfigPath));
-  // Ensure we did not write a PIN hash value since no PIN was provided.
-  EXPECT_FALSE(config->FindString(kHostSecretHashConfigPath));
+  // Verify subclass value was applied.
+  value = config->FindString(kTestConfigValuePath);
+  ASSERT_NE(value, nullptr);
+  EXPECT_EQ(*value, kTestConfigValue);
 
   // Verify Stop() was not called.
   EXPECT_FALSE(test_daemon_controller_delegate().stop_called());
@@ -436,10 +445,10 @@
   EXPECT_EQ(*value, kTestDirectoryId);
   // We use the value from GetHostname() if no name is provided.
   EXPECT_TRUE(config->FindString(kHostNameConfigPath));
-  // Just check for existence here.
-  EXPECT_TRUE(config->FindString(kPrivateKeyConfigPath));
-  // Ensure we did not write a PIN hash value since no PIN was provided.
-  EXPECT_FALSE(config->FindString(kHostSecretHashConfigPath));
+  // Verify subclass value was applied.
+  value = config->FindString(kTestConfigValuePath);
+  ASSERT_NE(value, nullptr);
+  EXPECT_EQ(*value, kTestConfigValue);
 
   // Verify Stop() was not called.
   EXPECT_FALSE(test_daemon_controller_delegate().stop_called());
@@ -477,10 +486,10 @@
   EXPECT_EQ(*value, kTestDirectoryId);
   // We use the value from GetHostname() if no name is provided.
   EXPECT_TRUE(config->FindString(kHostNameConfigPath));
-  // Just check for existence here.
-  EXPECT_TRUE(config->FindString(kPrivateKeyConfigPath));
-  // Ensure we wrote a PIN hash value since a PIN was provided.
-  EXPECT_TRUE(config->FindString(kHostSecretHashConfigPath));
+  // Verify subclass value was applied.
+  value = config->FindString(kTestConfigValuePath);
+  ASSERT_NE(value, nullptr);
+  EXPECT_EQ(*value, kTestConfigValue);
 
   // Verify Stop() was not called.
   EXPECT_FALSE(test_daemon_controller_delegate().stop_called());
diff --git a/remoting/host/setup/oauth_host_starter.cc b/remoting/host/setup/oauth_host_starter.cc
index 8b1e261..b18e8c55 100644
--- a/remoting/host/setup/oauth_host_starter.cc
+++ b/remoting/host/setup/oauth_host_starter.cc
@@ -21,6 +21,8 @@
 #include "remoting/base/directory_service_client.h"
 #include "remoting/base/passthrough_oauth_token_getter.h"
 #include "remoting/base/protobuf_http_status.h"
+#include "remoting/host/host_config.h"
+#include "remoting/host/pin_hash.h"
 #include "remoting/host/setup/host_starter.h"
 #include "remoting/host/setup/host_starter_base.h"
 #include "remoting/proto/remoting/v1/directory_messages.pb.h"
@@ -45,6 +47,7 @@
   void RegisterNewHost(const std::string& public_key,
                        std::optional<std::string> access_token) override;
   void RemoveOldHostFromDirectory(base::OnceClosure on_host_removed) override;
+  void ApplyConfigValues(base::Value::Dict& config) override;
 
   // DirectoryServiceClient callbacks.
   void OnDeleteHostResponse(
@@ -103,6 +106,14 @@
   }
 }
 
+void OAuthHostStarter::ApplyConfigValues(base::Value::Dict& config) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  config.Set(kHostTypeHintPath, kMe2MeHostTypeHint);
+  config.Set(kHostSecretHashConfigPath,
+             MakeHostPinHash(params().id, params().pin));
+}
+
 void OAuthHostStarter::OnRegisterHostResponse(
     const ProtobufHttpStatus& status,
     std::unique_ptr<apis::v1::RegisterHostResponse> response) {
diff --git a/remoting/host/x11_desktop_resizer.cc b/remoting/host/x11_desktop_resizer.cc
deleted file mode 100644
index dda795c..0000000
--- a/remoting/host/x11_desktop_resizer.cc
+++ /dev/null
@@ -1,669 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
-#include "remoting/host/x11_desktop_resizer.h"
-
-#include <gio/gio.h>
-
-#include <algorithm>
-#include <iterator>
-#include <memory>
-#include <ranges>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/containers/contains.h"
-#include "base/memory/ptr_util.h"
-#include "base/notreached.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/system/sys_info.h"
-#include "base/types/cxx23_to_underlying.h"
-#include "remoting/base/logging.h"
-#include "remoting/host/desktop_geometry.h"
-#include "remoting/host/linux/x11_util.h"
-#include "remoting/host/x11_crtc_resizer.h"
-#include "remoting/host/x11_display_util.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/x/future.h"
-#include "ui/gfx/x/randr.h"
-
-// On Linux, we use the xrandr extension to change the desktop resolution.
-//
-// Xrandr has a number of restrictions that make exact resize more complex:
-//
-//   1. It's not possible to change the resolution of an existing mode. Instead,
-//      the mode must be deleted and recreated.
-//   2. It's not possible to delete a mode that's in use.
-//   3. Errors are communicated via Xlib's spectacularly unhelpful mechanism
-//      of terminating the process unless you install an error handler.
-//   4. The root window size must always enclose any enabled Outputs (that is,
-//      any output which is attached to a CRTC).
-//   5. An Output cannot be given properties (xy-offsets, mode) which would
-//      extend its rectangle beyond the root window size.
-//
-// Since we want the current mode name to be consistent (for each Output), the
-// approach is as follows:
-//
-//   1. Fetch information about all the active (enabled) CRTCs.
-//   2. Disable the RANDR Output being resized.
-//   3. Delete the CRD mode, if it exists.
-//   4. Create the CRD mode at the new resolution, and add it to the Output's
-//      list of modes.
-//   5. Adjust the properties (in memory) of any CRTCs to be modified:
-//      * Width/height (mode) of the CRTC being resized.
-//      * xy-offsets to avoid overlapping CRTCs.
-//   6. Disable any CRTCs that might prevent changing the root window size.
-//   7. Compute the bounding rectangle of all CRTCs (after adjustment), and set
-//      it as the new root window size.
-//   8. Apply all adjusted CRTC properties to the CRTCs. This will set the
-//      Output being resized to the new CRD mode (which re-enables it), and it
-//      will re-enable any other CRTCs that were disabled.
-
-namespace {
-
-constexpr auto kInvalidMode = static_cast<x11::RandR::Mode>(0);
-constexpr auto kDisabledCrtc = static_cast<x11::RandR::Crtc>(0);
-constexpr base::TimeDelta kGnomeWaitTime = base::Seconds(1);
-
-int PixelsToMillimeters(int pixels, int dpi) {
-  DCHECK(dpi != 0);
-
-  const double kMillimetersPerInch = 25.4;
-
-  // (pixels / dpi) is the length in inches. Multiplying by
-  // kMillimetersPerInch converts to mm. Multiplication is done first to
-  // avoid integer division.
-  return static_cast<int>(kMillimetersPerInch * pixels / dpi);
-}
-
-// Returns a physical size in mm that will work well with GNOME's
-// automatic scale-selection algorithm.
-gfx::Size CalculateSizeInMmForGnome(
-    const remoting::DesktopResolution& resolution) {
-  int width_mm = PixelsToMillimeters(resolution.dimensions().width(),
-                                     resolution.dpi().x());
-  int height_mm = PixelsToMillimeters(resolution.dimensions().height(),
-                                      resolution.dpi().y());
-
-  // GNOME will, by default, choose an automatic scaling-factor based on the
-  // monitor's physical size (mm) and resolution (pixels). Some versions of
-  // GNOME have a problem when the computed DPI is close to 192. GNOME
-  // calculates the DPI using:
-  // dpi = size_pixels / (size_mm / 25.4)
-  // This is the reverse of PixelsToMillimeters() which should result in
-  // the same values as resolution.dpi() except for any floating-point
-  // truncation errors. GNOME will choose 2x scaling only if both the width and
-  // height DPIs are strictly greater than 192. The problem is that a user might
-  // connect from a 192dpi device and then GNOME's choice of scaling is randomly
-  // subject to rounding errors. If the calculation worked out at exactly
-  // 192dpi, the inequality test would fail and GNOME would choose 1x scaling.
-  // To address this, width_mm/height_mm are decreased slightly (increasing the
-  // calculated DPI) to favor 2x over 1x scaling for 192dpi devices.
-  width_mm--;
-  height_mm--;
-
-  // GNOME treats some pairs of width/height values as untrustworthy and will
-  // always choose 1x scaling for them. These values come from
-  // meta_monitor_has_aspect_as_size() in
-  // https://gitlab.gnome.org/GNOME/mutter/-/blob/main/src/backends/meta-monitor-manager.c
-  constexpr std::pair<int, int> kBadSizes[] = {
-      {16, 9}, {16, 10}, {160, 90}, {160, 100}, {1600, 900}, {1600, 1000}};
-  if (base::Contains(kBadSizes, std::pair(width_mm, height_mm))) {
-    width_mm--;
-  }
-  return {width_mm, height_mm};
-}
-
-// TODO(jamiewalch): Use the correct DPI for the mode: http://crbug.com/172405.
-const int kDefaultDPI = 96;
-
-x11::RandR::Output GetOutputFromContext(void* context) {
-  return reinterpret_cast<x11::RandR::MonitorInfo*>(context)->outputs[0];
-}
-
-std::string GetModeNameForOutput(x11::RandR::Output output) {
-  // The name of the mode representing the current client view resolution. This
-  // must be unique per Output, so that Outputs can be resized independently.
-  return "CRD_" + base::NumberToString(base::to_underlying(output));
-}
-
-uint32_t GetDotClockForModeInfo() {
-  static int proc_num = base::SysInfo::NumberOfProcessors();
-  // Keep the proc_num logic in sync with linux_me2me_host.py
-  if (proc_num > 16) {
-    return 120 * 1e6;
-  }
-  return 60 * 1e6;
-}
-
-// Gets current layout with context information from a list of monitors.
-std::vector<remoting::DesktopLayoutWithContext> GetLayoutWithContext(
-    std::vector<x11::RandR::MonitorInfo>& monitors) {
-  std::vector<remoting::DesktopLayoutWithContext> current_displays;
-  for (auto& monitor : monitors) {
-    // This implementation only supports resizing synthesized Monitors which
-    // automatically track their Outputs.
-    // TODO(crbug.com/40225767): Maybe support resizing manually-created
-    // monitors?
-    if (monitor.automatic) {
-      current_displays.push_back(
-          {.layout = remoting::ToVideoTrackLayout(monitor),
-           .context = &monitor});
-    }
-  }
-  return current_displays;
-}
-
-}  // namespace
-
-namespace remoting {
-
-ScreenResources::ScreenResources() = default;
-
-ScreenResources::~ScreenResources() = default;
-
-bool ScreenResources::Refresh(x11::RandR* randr, x11::Window window) {
-  resources_ = nullptr;
-  if (auto response = randr->GetScreenResourcesCurrent({window}).Sync()) {
-    resources_ = std::move(response.reply);
-  }
-  return resources_ != nullptr;
-}
-
-x11::RandR::Mode ScreenResources::GetIdForMode(const std::string& name) {
-  CHECK(resources_);
-  const char* names = reinterpret_cast<const char*>(resources_->names.data());
-  for (const auto& mode_info : resources_->modes) {
-    std::string mode_name(names, mode_info.name_len);
-    names += mode_info.name_len;
-    if (name == mode_name) {
-      return static_cast<x11::RandR::Mode>(mode_info.id);
-    }
-  }
-  return kInvalidMode;
-}
-
-x11::RandR::GetScreenResourcesCurrentReply* ScreenResources::get() {
-  return resources_.get();
-}
-
-X11DesktopResizer::X11DesktopResizer()
-    : connection_(x11::Connection::Get()),
-      randr_(&connection_->randr()),
-      screen_(&connection_->default_screen()),
-      root_(screen_->root),
-      is_virtual_session_(IsVirtualSession(connection_)) {
-  has_randr_ = randr_->present();
-  if (!has_randr_) {
-    return;
-  }
-  randr_->SelectInput({root_, x11::RandR::NotifyMask::ScreenChange});
-
-  gnome_display_config_.Init();
-  registry_ = TakeGObject(g_settings_new("org.gnome.desktop.interface"));
-}
-
-X11DesktopResizer::~X11DesktopResizer() = default;
-
-DesktopResolution X11DesktopResizer::GetCurrentResolution(
-    DesktopScreenId screen_id) {
-  // Process pending events so that the connection setup data is updated
-  // with the correct display metrics.
-  if (has_randr_) {
-    connection_->DispatchAll();
-  }
-
-  // RANDR does not allow fetching information on a particular monitor. So
-  // fetch all of them and try to find the requested monitor.
-  auto reply = randr_->GetMonitors({root_}).Sync();
-  if (reply) {
-    for (const auto& monitor : reply->monitors) {
-      if (static_cast<DesktopScreenId>(monitor.name) != screen_id) {
-        continue;
-      }
-      return DesktopResolution(gfx::Size(monitor.width, monitor.height),
-                               GetMonitorDpi(monitor));
-    }
-  }
-
-  LOG(ERROR) << "Cannot find current resolution for screen ID " << screen_id
-             << ". Resolution of the default screen will be returned.";
-
-  DesktopResolution result(
-      gfx::Size(connection_->default_screen().width_in_pixels,
-                connection_->default_screen().height_in_pixels),
-      gfx::Vector2d(kDefaultDPI, kDefaultDPI));
-  return result;
-}
-
-std::list<DesktopResolution> X11DesktopResizer::GetSupportedResolutions(
-    const DesktopResolution& preferred,
-    DesktopScreenId screen_id) {
-  std::list<DesktopResolution> result;
-  if (!has_randr_ || !is_virtual_session_) {
-    return result;
-  }
-
-  // Clamp the specified size to something valid for the X server.
-  if (auto response = randr_->GetScreenSizeRange({root_}).Sync()) {
-    int width =
-        std::clamp(static_cast<uint16_t>(preferred.dimensions().width()),
-                   response->min_width, response->max_width);
-    int height =
-        std::clamp(static_cast<uint16_t>(preferred.dimensions().height()),
-                   response->min_height, response->max_height);
-    // Additionally impose a minimum size of 640x480, since anything smaller
-    // doesn't seem very useful.
-    result.emplace_back(gfx::Size(std::max(640, width), std::max(480, height)),
-                        preferred.dpi());
-  }
-  return result;
-}
-
-void X11DesktopResizer::SetResolution(const DesktopResolution& resolution,
-                                      DesktopScreenId screen_id) {
-  if (!has_randr_ || !is_virtual_session_) {
-    return;
-  }
-
-  // Grab the X server while we're changing the display resolution. This ensures
-  // that the display configuration doesn't change under our feet.
-  ScopedXGrabServer grabber(connection_);
-
-  // RANDR does not allow fetching information on a particular monitor. So
-  // fetch all of them and try to find the requested monitor.
-  std::vector<x11::RandR::MonitorInfo> monitors;
-  if (!TryGetCurrentMonitors(monitors)) {
-    return;
-  }
-
-  for (const auto& monitor : monitors) {
-    if (static_cast<DesktopScreenId>(monitor.name) != screen_id) {
-      continue;
-    }
-
-    if (monitor.outputs.size() != 1) {
-      // This implementation only supports resizing a Monitor attached to a
-      // single output. The case where size() > 1 should never occur with
-      // Xorg+video-dummy.
-      // TODO(crbug.com/40225767): Maybe support resizing a Monitor not
-      // attached to any Output?
-      LOG(ERROR) << "Monitor " << screen_id
-                 << " has unexpected #outputs: " << monitor.outputs.size();
-      return;
-    }
-
-    if (!monitor.automatic) {
-      // This implementation only supports resizing synthesized Monitors which
-      // automatically track their Outputs.
-      // TODO(crbug.com/40225767): Maybe support resizing manually-created
-      // Monitors?
-      LOG(ERROR) << "Not resizing Monitor " << screen_id
-                 << " that was created manually.";
-      return;
-    }
-
-    SetResolutionForOutput(monitor.outputs[0], resolution);
-    return;
-  }
-  LOG(ERROR) << "Monitor " << screen_id << " not found.";
-}
-
-void X11DesktopResizer::RestoreResolution(const DesktopResolution& original,
-                                          DesktopScreenId screen_id) {
-  SetResolution(original, screen_id);
-}
-
-bool X11DesktopResizer::TryGetCurrentMonitors(
-    std::vector<x11::RandR::MonitorInfo>& list) {
-  if (!has_randr_ || !is_virtual_session_) {
-    return false;
-  }
-
-  if (!resources_.Refresh(randr_, root_)) {
-    return false;
-  }
-
-  auto reply = randr_->GetMonitors({root_}).Sync();
-  if (!reply) {
-    return false;
-  }
-  std::copy(reply->monitors.begin(), reply->monitors.end(),
-            std::back_inserter(list));
-  return true;
-}
-
-DesktopLayoutSet X11DesktopResizer::GetLayout() {
-  DesktopLayoutSet result;
-  std::vector<x11::RandR::MonitorInfo> monitors;
-  if (!TryGetCurrentMonitors(monitors)) {
-    return DesktopLayoutSet();
-  }
-  for (const auto& layout : GetLayoutWithContext(monitors)) {
-    result.layouts.emplace_back(layout.layout);
-  }
-  return result;
-}
-
-void X11DesktopResizer::SetVideoLayout(const DesktopLayoutSet& layout) {
-  if (!has_randr_ || !is_virtual_session_) {
-    return;
-  }
-  // Grab the X server while we're changing the display resolution. This ensures
-  // that the display configuration doesn't change under our feet.
-  ScopedXGrabServer grabber(connection_);
-
-  std::vector<x11::RandR::MonitorInfo> monitors;
-  if (!TryGetCurrentMonitors(monitors)) {
-    return;
-  }
-  std::vector<DesktopLayoutWithContext> current_displays =
-      GetLayoutWithContext(monitors);
-
-  // TODO(yuweih): Verify that the layout is valid, e.g. no overlaps or gaps
-  // between displays.
-  DisplayLayoutDiff diff = CalculateDisplayLayoutDiff(current_displays, layout);
-
-  X11CrtcResizer resizer(resources_.get(), connection_);
-  resizer.FetchActiveCrtcs();
-
-  const std::vector<DesktopLayout>& new_layouts = diff.new_displays.layouts;
-  // Add displays
-  if (!new_layouts.empty()) {
-    auto outputs = GetDisabledOutputs();
-    size_t i = 0u;
-    for (; i < outputs.size() && i < new_layouts.size(); i++) {
-      auto& output_pair = outputs[i];
-      auto output = output_pair.first;
-      auto& output_info = output_pair.second;
-      // For the video-dummy driver, the size of |crtcs| is exactly 1 and is
-      // different for each Output. In general, this is not true for other
-      // video-drivers, and the lists can overlap.
-      // TODO(yuweih): Consider making CRTC allocation smarter so it works with
-      // non-video-dummy drivers.
-      if (output_info.crtcs.empty()) {
-        LOG(ERROR) << "No available CRTC found associated with "
-                   << reinterpret_cast<char*>(output_info.name.data());
-        continue;
-      }
-      auto crtc = output_info.crtcs.front();
-      auto track_layout = new_layouts[i];
-      // Note that this has a weird behavior in GNOME, such that, if |output| is
-      // "disconnected", creating the mode somehow resizes all existing displays
-      // to 1024x768. Once the output is successfully enabled, it will remain
-      // "connected" and will no longer have the problem. The problem doesn't
-      // occur on XFCE or Cinnamon.
-      // TODO(yuweih): See if this is fixable, or at least implement some
-      // workaround, such as re-applying the layout.
-      auto mode =
-          UpdateMode(output, track_layout.width(), track_layout.height());
-      if (mode == kInvalidMode) {
-        LOG(ERROR) << "Failed to create new mode.";
-        continue;
-      }
-      resizer.AddActiveCrtc(
-          crtc, mode, {output},
-          gfx::Rect(track_layout.position_x(), track_layout.position_y(),
-                    track_layout.width(), track_layout.height()));
-      HOST_LOG << "Added display with crtc: " << base::to_underlying(crtc)
-               << ", output: " << base::to_underlying(output);
-    }
-    if (i < diff.new_displays.layouts.size()) {
-      LOG(WARNING) << "Failed to create "
-                   << (diff.new_displays.layouts.size() - i)
-                   << " display(s) due to insufficient resources.";
-    }
-  }
-
-  // Update displays
-  for (const auto& updated_display : diff.updated_displays) {
-    auto track_layout = updated_display.layout;
-    auto output = GetOutputFromContext(updated_display.context);
-    auto crtc = resizer.GetCrtcForOutput(output);
-    if (crtc == kDisabledCrtc) {
-      // This is not expected to happen. Disabled Outputs are not expected to
-      // have any Monitor, but |output| was found in the RRGetMonitors response,
-      // so it should have a CRTC attached.
-      LOG(ERROR) << "No CRTC found for output: " << base::to_underlying(output);
-      continue;
-    }
-    resizer.DisableCrtc(crtc);
-    auto mode = UpdateMode(output, track_layout.width(), track_layout.height());
-    if (mode == kInvalidMode) {
-      LOG(ERROR) << "Failed to create new mode.";
-      continue;
-    }
-    resizer.UpdateActiveCrtc(
-        crtc, mode,
-        gfx::Rect(track_layout.position_x(), track_layout.position_y(),
-                  track_layout.width(), track_layout.height()));
-    HOST_LOG << "Updated display with screen ID: "
-             << updated_display.layout.screen_id().value_or(-1);
-  }
-
-  // Remove displays
-  for (const auto& removed_display : diff.removed_displays) {
-    auto output = GetOutputFromContext(removed_display.context);
-    auto crtc = resizer.GetCrtcForOutput(output);
-    if (crtc == kDisabledCrtc) {
-      LOG(ERROR) << "No CRTC found for output: " << base::to_underlying(output);
-      continue;
-    }
-    resizer.DisableCrtc(crtc);
-    resizer.RemoveActiveCrtc(crtc);
-    DeleteMode(output, GetModeNameForOutput(output));
-    HOST_LOG << "Removed display with screen ID: "
-             << removed_display.layout.screen_id().value_or(-1);
-  }
-
-  resizer.NormalizeCrtcs();
-  UpdateRootWindow(resizer);
-}
-
-void X11DesktopResizer::SetResolutionForOutput(
-    x11::RandR::Output output,
-    const DesktopResolution& resolution) {
-  // Actually do the resize operation, preserving the current mode name. Note
-  // that we have to detach the output from the mode in order to delete the
-  // mode and re-create it with the new resolution. The output may also need to
-  // be detached from all modes in order to reduce the root window size.
-  HOST_LOG << "Resizing RANDR Output " << base::to_underlying(output) << " to "
-           << resolution.dimensions().width() << "x"
-           << resolution.dimensions().height();
-
-  X11CrtcResizer resizer(resources_.get(), connection_);
-
-  resizer.FetchActiveCrtcs();
-  auto crtc = resizer.GetCrtcForOutput(output);
-
-  if (crtc == kDisabledCrtc) {
-    // This is not expected to happen. Disabled Outputs are not expected to
-    // have any Monitor, but |output| was found in the RRGetMonitors response,
-    // so it should have a CRTC attached.
-    LOG(ERROR) << "No CRTC found for output: " << base::to_underlying(output);
-    return;
-  }
-
-  // Disable the output now, so that the old mode can be deleted and the new
-  // mode created and added to the output's available modes. The previous size
-  // and offsets will be stored in |resizer|.
-  resizer.DisableCrtc(crtc);
-
-  auto mode = UpdateMode(output, resolution.dimensions().width(),
-                         resolution.dimensions().height());
-  if (mode == kInvalidMode) {
-    // The CRTC is disabled, but there's no easy way to recover it here
-    // (the mode it was attached to has gone).
-    LOG(ERROR) << "Failed to create new mode.";
-    return;
-  }
-
-  // Update |active_crtcs_| with new sizes and offsets.
-  resizer.UpdateActiveCrtcs(crtc, mode, resolution.dimensions());
-  UpdateRootWindow(resizer);
-
-  gfx::Size size_mm = CalculateSizeInMmForGnome(resolution);
-  int width_mm = size_mm.width();
-  int height_mm = size_mm.height();
-  HOST_LOG << "Setting physical size in mm: " << width_mm << "x" << height_mm;
-  SetOutputPhysicalSizeInMM(connection_, output, width_mm, height_mm);
-
-  // Check to see if GNOME is using automatic-scaling. If the value is non-zero,
-  // the user prefers a particular scaling, so don't adjust the
-  // text-scaling-factor here.
-  if (g_settings_get_uint(registry_.get(), "scaling-factor") == 0U) {
-    // Start the timer to update the text-scaling-factor. Any previously
-    // started timer will be cancelled.
-    requested_dpi_ = resolution.dpi().x();
-    gnome_delay_timer_.Start(FROM_HERE, kGnomeWaitTime, this,
-                             &X11DesktopResizer::RequestGnomeDisplayConfig);
-  }
-}
-
-x11::RandR::Mode X11DesktopResizer::UpdateMode(x11::RandR::Output output,
-                                               int width,
-                                               int height) {
-  std::string mode_name = GetModeNameForOutput(output);
-  DeleteMode(output, mode_name);
-
-  // Set some clock values so that the computed refresh-rate is a realistic
-  // number:
-  // 60Hz = dot_clock / (htotal * vtotal).
-  // This allows GNOME's Display Settings tool to apply new settings for
-  // resolution/scaling - see crbug.com/1374488.
-  x11::RandR::ModeInfo mode;
-  mode.width = width;
-  mode.height = height;
-  mode.dot_clock = GetDotClockForModeInfo();
-  mode.htotal = 1000;
-  mode.vtotal = 1000;
-  mode.name_len = mode_name.size();
-  if (auto reply =
-          randr_->CreateMode({root_, mode, mode_name.c_str()}).Sync()) {
-    randr_->AddOutputMode({
-        output,
-        reply->mode,
-    });
-    return reply->mode;
-  }
-  return kInvalidMode;
-}
-
-void X11DesktopResizer::DeleteMode(x11::RandR::Output output,
-                                   const std::string& name) {
-  x11::RandR::Mode mode_id = resources_.GetIdForMode(name);
-  if (mode_id != kInvalidMode) {
-    randr_->DeleteOutputMode({output, mode_id});
-    randr_->DestroyMode({mode_id});
-    resources_.Refresh(randr_, root_);
-  }
-}
-
-void X11DesktopResizer::UpdateRootWindow(X11CrtcResizer& resizer) {
-  // Disable any CRTCs that have been changed, so that the root window can be
-  // safely resized to the bounding-box of the new CRTCs.
-  // This is non-optimal: the only CRTCs that need disabling are those whose
-  // original rectangles don't fit into the new root window - they are the ones
-  // that would prevent resizing the root window. But figuring these out would
-  // involve keeping track of all the original rectangles as well as the new
-  // ones. So, to keep the implementation simple (and working for any arbitrary
-  // layout algorithm), all changed CRTCs are disabled here.
-  resizer.DisableChangedCrtcs();
-
-  // Get the dimensions to resize the root window to.
-  auto dimensions = resizer.GetBoundingBox();
-
-  // TODO(lambroslambrou): Use the DPI from client size information.
-  uint32_t width_mm = PixelsToMillimeters(dimensions.width(), kDefaultDPI);
-  uint32_t height_mm = PixelsToMillimeters(dimensions.height(), kDefaultDPI);
-  randr_->SetScreenSize({root_, static_cast<uint16_t>(dimensions.width()),
-                         static_cast<uint16_t>(dimensions.height()), width_mm,
-                         height_mm});
-
-  resizer.MoveApplicationWindows();
-
-  // Apply the new CRTCs, which will re-enable any that were disabled.
-  resizer.ApplyActiveCrtcs();
-}
-
-X11DesktopResizer::OutputInfoList X11DesktopResizer::GetDisabledOutputs() {
-  OutputInfoList disabled_outputs;
-  for (x11::RandR::Output output : resources_.get()->outputs) {
-    auto reply = randr_
-                     ->GetOutputInfo({.output = output,
-                                      .config_timestamp =
-                                          resources_.get()->config_timestamp})
-                     .Sync();
-    if (!reply) {
-      continue;
-    }
-    if (reply->crtc == kDisabledCrtc) {
-      disabled_outputs.emplace_back(output, std::move(*reply.reply));
-    }
-  }
-  return disabled_outputs;
-}
-
-void X11DesktopResizer::RequestGnomeDisplayConfig() {
-  // Unretained() is safe because `this` owns gnome_display_config_ which
-  // cancels callbacks on destruction.
-  gnome_display_config_.GetMonitorsConfig(
-      base::BindOnce(&X11DesktopResizer::OnGnomeDisplayConfigReceived,
-                     base::Unretained(this)));
-}
-
-void X11DesktopResizer::OnGnomeDisplayConfigReceived(
-    GnomeDisplayConfig config) {
-  // Look for an enabled monitor. Disabled monitors have no Mode set - a
-  // monitor can become disabled by being added then removed (using the website
-  // Display options). The Xorg xf86-video-dummy driver has a quirk that, once a
-  // monitor becomes "connected", it stays forever in the connected state, even
-  // if it is later disabled. All connected monitors (enabled or disabled) are
-  // included in the GNOME config.
-
-  // For X11, the calculation of the text-scaling-factor does not depend on
-  // which enabled monitor is chosen here, because GNOME's X11 backend forces
-  // all monitors to have the same scale. However, it makes sense to select
-  // an enabled monitor, since a disabled monitor might not have a reliable
-  // "scale" property returned by GNOME.
-  auto monitor_iter =
-      base::ranges::find_if(config.monitors, [](const auto& entry) {
-        return entry.second.GetCurrentMode() != nullptr;
-      });
-  if (monitor_iter == std::ranges::end(config.monitors)) {
-    LOG(ERROR) << "No enabled monitor found in GNOME config.";
-    return;
-  }
-  const auto& monitor = monitor_iter->second;
-
-  if (monitor.scale == 0) {
-    // This should never happen - avoid division by 0.
-    return;
-  }
-
-  // The GNOME scaling, multiplied by the GNOME text-scaling-factor, will be the
-  // rendered scaling of text. This should be the client's requested DPI divided
-  // by kDefaultDPI.
-  double text_scaling_factor =
-      static_cast<double>(requested_dpi_) / kDefaultDPI / monitor.scale;
-  HOST_LOG << "Target DPI = " << requested_dpi_
-           << ", GNOME scale = " << monitor.scale
-           << ", calculated text-scaling = " << text_scaling_factor;
-
-  if (!g_settings_set_double(registry_.get(), "text-scaling-factor",
-                             text_scaling_factor)) {
-    // Just log a warning - failure is expected if the value falls outside the
-    // interval [0.5, 3.0].
-    LOG(WARNING) << "Failed to set text-scaling-factor.";
-  }
-}
-
-}  // namespace remoting
diff --git a/remoting/host/x11_desktop_resizer.h b/remoting/host/x11_desktop_resizer.h
deleted file mode 100644
index 9f0469e7..0000000
--- a/remoting/host/x11_desktop_resizer.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_HOST_X11_DESKTOP_RESIZER_H_
-#define REMOTING_HOST_X11_DESKTOP_RESIZER_H_
-
-#include <string.h>
-
-#include <list>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/memory/raw_ptr.h"
-#include "base/timer/timer.h"
-#include "remoting/host/desktop_display_layout_util.h"
-#include "remoting/host/desktop_geometry.h"
-#include "remoting/host/linux/gnome_display_config_dbus_client.h"
-#include "remoting/host/linux/scoped_glib.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/x/connection.h"
-#include "ui/gfx/x/randr.h"
-
-namespace remoting {
-
-class X11CrtcResizer;
-
-// Wrapper class for the XRRScreenResources struct.
-class ScreenResources {
- public:
-  ScreenResources();
-  ~ScreenResources();
-
-  bool Refresh(x11::RandR* randr, x11::Window window);
-
-  x11::RandR::Mode GetIdForMode(const std::string& name);
-
-  x11::RandR::GetScreenResourcesCurrentReply* get();
-
- private:
-  std::unique_ptr<x11::RandR::GetScreenResourcesCurrentReply> resources_;
-};
-
-class X11DesktopResizer {
- public:
-  X11DesktopResizer();
-  X11DesktopResizer(const X11DesktopResizer&) = delete;
-  X11DesktopResizer& operator=(const X11DesktopResizer&) = delete;
-  ~X11DesktopResizer();
-
-  DesktopResolution GetCurrentResolution(DesktopScreenId screen_id);
-  std::list<DesktopResolution> GetSupportedResolutions(
-      const DesktopResolution& preferred,
-      DesktopScreenId screen_id);
-  void SetResolution(const DesktopResolution& resolution,
-                     DesktopScreenId screen_id);
-  void RestoreResolution(const DesktopResolution& original,
-                         DesktopScreenId screen_id);
-  DesktopLayoutSet GetLayout();
-  void SetVideoLayout(const DesktopLayoutSet& layout);
-
- private:
-  using OutputInfoList = std::vector<
-      std::pair<x11::RandR::Output, x11::RandR::GetOutputInfoReply>>;
-
-  // Add a mode matching the specified resolution and switch to it.
-  void SetResolutionForOutput(x11::RandR::Output output,
-                              const DesktopResolution& resolution);
-
-  // Removes the existing mode from the output and replaces it with the new
-  // size. Returns the new mode ID, or None (0) on failure.
-  x11::RandR::Mode UpdateMode(x11::RandR::Output output, int width, int height);
-
-  // Remove the specified mode from the output, and delete it. If the mode is in
-  // use, it is not deleted.
-  // |name| should be set to GetModeNameForOutput(output). The parameter is to
-  // avoid creating the mode name twice.
-  void DeleteMode(x11::RandR::Output output, const std::string& name);
-
-  // Updates the root window using the bounding box of the CRTCs, then
-  // re-activate all CRTCs.
-  void UpdateRootWindow(X11CrtcResizer& resizer);
-
-  // Gets a list of outputs that are not connected to any CRTCs.
-  OutputInfoList GetDisabledOutputs();
-
-  // Attempts to get the current list of XRandR monitors from the current
-  // connection. Returns true on success in which case `list` is populated with
-  // the monitors. Returns false otherwise.
-  bool TryGetCurrentMonitors(std::vector<x11::RandR::MonitorInfo>& list);
-
-  void RequestGnomeDisplayConfig();
-  void OnGnomeDisplayConfigReceived(GnomeDisplayConfig config);
-
-  raw_ptr<x11::Connection> connection_;
-  const raw_ptr<x11::RandR> randr_ = nullptr;
-  const raw_ptr<const x11::Screen> screen_ = nullptr;
-  x11::Window root_;
-  ScreenResources resources_;
-  bool has_randr_;
-  bool is_virtual_session_;
-
-  // Used to fetch GNOME's current scale setting, so the correct
-  // text-scaling-factor can be calculated.
-  GnomeDisplayConfigDBusClient gnome_display_config_;
-
-  // Used to rate-limit requests to GNOME.
-  base::OneShotTimer gnome_delay_timer_;
-
-  int requested_dpi_;
-
-  // Used to set the text-scaling-factor.
-  ScopedGObject<GSettings> registry_;
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_HOST_X11_DESKTOP_RESIZER_H_
diff --git a/remoting/host/x11_display_util.cc b/remoting/host/x11_display_util.cc
index 0a68069..93dbf64 100644
--- a/remoting/host/x11_display_util.cc
+++ b/remoting/host/x11_display_util.cc
@@ -29,9 +29,10 @@
       CalculateDpi(monitor.height, monitor.height_in_millimeters));
 }
 
-DesktopLayout ToVideoTrackLayout(const x11::RandR::MonitorInfo& monitor) {
-  return DesktopLayout(
-      static_cast<DesktopScreenId>(monitor.name),
+x11::RandRMonitorConfig ToVideoTrackLayout(
+    const x11::RandR::MonitorInfo& monitor) {
+  return x11::RandRMonitorConfig(
+      static_cast<x11::RandRMonitorConfig::ScreenId>(monitor.name),
       gfx::Rect(monitor.x, monitor.y, monitor.width, monitor.height),
       GetMonitorDpi(monitor));
 }
diff --git a/remoting/host/x11_display_util.h b/remoting/host/x11_display_util.h
index e728cd4..be37a98b 100644
--- a/remoting/host/x11_display_util.h
+++ b/remoting/host/x11_display_util.h
@@ -5,17 +5,18 @@
 #ifndef REMOTING_HOST_X11_DISPLAY_UTIL_H_
 #define REMOTING_HOST_X11_DISPLAY_UTIL_H_
 
-#include "remoting/host/desktop_geometry.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/x/randr.h"
+#include "ui/gfx/x/randr_output_manager.h"
 
 namespace remoting {
 
 // Calculates DPI from an X11 monitor object.
 gfx::Vector2d GetMonitorDpi(const x11::RandR::MonitorInfo& monitor);
 
-// Converts an X11 monitor object to VideoTrackLayout.
-DesktopLayout ToVideoTrackLayout(const x11::RandR::MonitorInfo& monitor);
+// Converts an X11 monitor object to RandRMonitorConfig.
+x11::RandRMonitorConfig ToVideoTrackLayout(
+    const x11::RandR::MonitorInfo& monitor);
 
 }  // namespace remoting
 
diff --git a/remoting/host/x11_display_util_unittest.cc b/remoting/host/x11_display_util_unittest.cc
index 5897acf..1f66de8 100644
--- a/remoting/host/x11_display_util_unittest.cc
+++ b/remoting/host/x11_display_util_unittest.cc
@@ -29,12 +29,12 @@
                                      .height = 500,
                                      .width_in_millimeters = 100,
                                      .height_in_millimeters = 100};
-  DesktopLayout layout = ToVideoTrackLayout(monitor);
-  EXPECT_EQ(layout.screen_id(), 123);
-  EXPECT_EQ(layout.position_x(), 10);
-  EXPECT_EQ(layout.position_y(), 20);
-  EXPECT_EQ(layout.width(), 1000);
-  EXPECT_EQ(layout.height(), 500);
+  x11::RandRMonitorConfig layout = ToVideoTrackLayout(monitor);
+  EXPECT_EQ(layout.id(), 123);
+  EXPECT_EQ(layout.rect().x(), 10);
+  EXPECT_EQ(layout.rect().y(), 20);
+  EXPECT_EQ(layout.rect().width(), 1000);
+  EXPECT_EQ(layout.rect().height(), 500);
   EXPECT_EQ(layout.dpi().x(), 254);
   EXPECT_EQ(layout.dpi().y(), 127);
 }
diff --git a/services/image_annotation/annotator_unittest.cc b/services/image_annotation/annotator_unittest.cc
index ea67813..42935e6 100644
--- a/services/image_annotation/annotator_unittest.cc
+++ b/services/image_annotation/annotator_unittest.cc
@@ -65,182 +65,6 @@
 // Example image URLs.
 
 constexpr char kImage1Url[] = "https://www.example.com/image1.jpg";
-constexpr char kImage2Url[] = "https://www.example.com/image2.jpg";
-constexpr char kImage3Url[] = "https://www.example.com/image3.jpg";
-
-// Example server requests / responses.
-
-// Template for a request for a single image.
-constexpr char kTemplateRequest[] = R"(
-{
-  "imageRequests": [{
-    "imageId": "%s",
-    "imageBytes": "%s",
-    "engineParameters": [
-      {"ocrParameters": {}},
-      {"descriptionParameters": {}},
-      {"iconParameters": {}}
-    ]
-  }]
-}
-)";
-
-// Batch request for |kImage1Url|, |kImage2Url| and |kImage3Url|.
-constexpr char kBatchRequest[] = R"(
-{
-  "imageRequests": [
-    {
-      "imageId": "https://www.example.com/image3.jpg",
-      "imageBytes": "BwgJ",
-      "engineParameters": [
-        {"ocrParameters": {}},
-        {"descriptionParameters": {}},
-        {"iconParameters": {}}
-      ]
-    },
-    {
-      "imageId": "https://www.example.com/image2.jpg",
-      "imageBytes": "BAUG",
-      "engineParameters": [
-        {"ocrParameters": {}},
-        {"descriptionParameters": {}},
-        {"iconParameters": {}}
-      ]
-    },
-    {
-      "imageId": "https://www.example.com/image1.jpg",
-      "imageBytes": "AQID",
-      "engineParameters": [
-        {"ocrParameters": {}},
-        {"descriptionParameters": {}},
-        {"iconParameters": {}}
-      ]
-    }
-  ]
-})";
-
-// Successful OCR text extraction for |kImage1Url| with no descriptions.
-constexpr char kOcrSuccessResponse[] = R"(
-{
-  "results": [
-    {
-      "imageId": "https://www.example.com/image1.jpg",
-      "engineResults": [
-        {
-          "status": {},
-          "ocrEngine": {
-            "ocrRegions": [
-              {
-                "words": [
-                  {
-                    "detectedText": "Region",
-                    "confidenceScore": 1.0
-                  },
-                  {
-                    "detectedText": "1",
-                    "confidenceScore": 1.0
-                  }
-                ]
-              },
-              {
-                "words": [
-                  {
-                    "detectedText": "Region",
-                    "confidenceScore": 1.0
-                  },
-                  {
-                    "detectedText": "2",
-                    "confidenceScore": 1.0
-                  }
-                ]
-              }
-            ]
-          }
-        },
-        {
-          "status": {},
-          "descriptionEngine": {
-            "descriptionList": {}
-          }
-        }
-      ]
-    }
-  ]
-}
-)";
-
-// Batch response containing successful annotations for |kImage1Url| and
-// |kImage2Url|, and a failure for |kImage3Url|.
-//
-// The results also appear "out of order" (i.e. image 2 comes before image 1).
-constexpr char kBatchResponse[] = R"(
-{
-  "results": [
-    {
-      "imageId": "https://www.example.com/image2.jpg",
-      "engineResults": [
-        {
-          "status": {},
-          "ocrEngine": {
-            "ocrRegions": [{
-              "words": [{
-                "detectedText": "2",
-                "confidenceScore": 1.0
-              }]
-            }]
-          }
-        },
-        {
-          "status": {},
-          "descriptionEngine": {
-            "descriptionList": {}
-          }
-        }
-      ]
-    },
-    {
-      "imageId": "https://www.example.com/image1.jpg",
-      "engineResults": [
-        {
-          "status": {},
-          "ocrEngine": {
-            "ocrRegions": [{
-              "words": [{
-                "detectedText": "1",
-                "confidenceScore": 1.0
-              }]
-            }]
-          }
-        },
-        {
-          "status": {},
-          "descriptionEngine": {
-            "descriptionList": {}
-          }
-        }
-      ]
-    },
-    {
-      "imageId": "https://www.example.com/image3.jpg",
-      "engineResults": [
-        {
-          "status": {
-            "code": 8,
-            "message": "Resource exhausted"
-          },
-          "ocrEngine": {}
-        },
-        {
-          "status": {
-            "code": 8,
-            "message": "Resource exhausted"
-          },
-          "descriptionEngine": {}
-        }
-      ]
-    }
-  ]
-})";
 
 constexpr base::TimeDelta kThrottle = base::Seconds(1);
 
@@ -365,18 +189,6 @@
   scoped_refptr<network::SharedURLLoaderFactory> shared_loader_factory_;
 };
 
-// Returns a "canonically" formatted version of a JSON string by parsing and
-// then rewriting it.
-std::string ReformatJson(const std::string& in) {
-  const std::optional<base::Value> json = base::JSONReader::Read(in);
-  CHECK(json);
-
-  std::string out;
-  base::JSONWriter::Write(*json, &out);
-
-  return out;
-}
-
 // Receives the result of an annotation request and writes the result data into
 // the given variables.
 void ReportResult(std::optional<mojom::AnnotateImageError>* const error,
@@ -426,1980 +238,6 @@
 
 }  // namespace
 
-// Test that annotation works for one client, and that the cache is populated.
-TEST(AnnotatorTest, OcrSuccessAndCache) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-  TestImageProcessor processor;
-
-  // First call performs original image annotation.
-  {
-    std::optional<mojom::AnnotateImageError> error;
-    std::vector<mojom::Annotation> annotations;
-
-    annotator.AnnotateImage(
-        kImage1Url, kDescLang, processor.GetPendingRemote(),
-        base::BindOnce(&ReportResult, &error, &annotations));
-    test_task_env.RunUntilIdle();
-
-    // Annotator should have asked processor for pixels.
-    ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-    // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-    processor.callbacks().pop_back();
-    test_task_env.RunUntilIdle();
-
-    // No request should be sent yet (because service is waiting to batch up
-    // multiple requests).
-    EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-    test_task_env.FastForwardBy(base::Seconds(1));
-    test_task_env.RunUntilIdle();
-
-    // HTTP request should have been made.
-    const std::string request =
-        ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID"));
-    test_url_factory.ExpectRequestAndSimulateResponse(
-        "annotation", {} /* expected_headers */, request, kOcrSuccessResponse,
-        net::HTTP_OK);
-    test_task_env.RunUntilIdle();
-
-    // HTTP response should have completed and callback should have been called.
-    ASSERT_THAT(error, Eq(std::nullopt));
-    EXPECT_THAT(annotations,
-                UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr,
-                                                 1.0, "Region 1\nRegion 2")));
-
-    // Metrics should have been logged for the major actions of the service.
-    histogram_tester.ExpectUniqueSample(metrics_internal::kCacheHit, false, 1);
-    histogram_tester.ExpectUniqueSample(metrics_internal::kPixelFetchSuccess,
-                                        true, 1);
-    histogram_tester.ExpectUniqueSample(metrics_internal::kServerRequestSize,
-                                        request.size() / 1024, 1);
-    histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                        net::Error::OK, 1);
-    histogram_tester.ExpectUniqueSample(
-        metrics_internal::kServerHttpResponseCode, net::HTTP_OK, 1);
-    histogram_tester.ExpectUniqueSample(metrics_internal::kServerResponseSize,
-                                        std::strlen(kOcrSuccessResponse), 1);
-    histogram_tester.ExpectUniqueSample(metrics_internal::kJsonParseSuccess,
-                                        true, 1);
-    histogram_tester.ExpectUniqueSample(
-        base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-        0 /* OK RPC status */, 1);
-    histogram_tester.ExpectUniqueSample(
-        base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
-        0 /* OK RPC status */, 1);
-    histogram_tester.ExpectUniqueSample(
-        base::StringPrintf(metrics_internal::kAnnotationConfidence, "Ocr"), 100,
-        1);
-    histogram_tester.ExpectUniqueSample(
-        base::StringPrintf(metrics_internal::kAnnotationEmpty, "Ocr"), false,
-        1);
-  }
-
-  // Second call uses cached results.
-  {
-    std::optional<mojom::AnnotateImageError> error;
-    std::vector<mojom::Annotation> annotations;
-
-    annotator.AnnotateImage(
-        kImage1Url, kDescLang, processor.GetPendingRemote(),
-        base::BindOnce(&ReportResult, &error, &annotations));
-    test_task_env.RunUntilIdle();
-
-    // Pixels shouldn't be requested.
-    ASSERT_THAT(processor.callbacks(), IsEmpty());
-
-    // Results should have been directly returned without any server call.
-    ASSERT_THAT(error, Eq(std::nullopt));
-    EXPECT_THAT(annotations,
-                UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr,
-                                                 1.0, "Region 1\nRegion 2")));
-
-    // Metrics should have been logged for a cache hit.
-    EXPECT_THAT(histogram_tester.GetAllSamples(metrics_internal::kCacheHit),
-                UnorderedElementsAre(Bucket(false, 1), Bucket(true, 1)));
-  }
-}
-
-// Test that description annotations are successfully returned.
-TEST(AnnotatorTest, DescriptionSuccess) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-  TestImageProcessor processor;
-
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-  test_task_env.RunUntilIdle();
-
-  // HTTP request should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image1.jpg",
-             "engineResults": [
-               {
-                 "status": {},
-                 "ocrEngine": {}
-               },
-               {
-                 "status": {},
-                 "descriptionEngine": {
-                   "descriptionList": {
-                     "descriptions": [
-                       {
-                         "type": "CAPTION",
-                         "text": "This is an example image.",
-                         "score": 0.9
-                       },
-                       {
-                         "type": "LABEL",
-                         "text": "Example image",
-                         "score": 1.0
-                       }
-                     ]
-                   }
-                 }
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called.
-  ASSERT_THAT(error, Eq(std::nullopt));
-  EXPECT_THAT(
-      annotations,
-      UnorderedElementsAre(
-          AnnotatorEq(mojom::AnnotationType::kOcr, 1.0, ""),
-          AnnotatorEq(mojom::AnnotationType::kCaption, 0.9,
-                      "This is an example image."),
-          AnnotatorEq(mojom::AnnotationType::kLabel, 1.0, "Example image")));
-
-  // Metrics about the description results should have been logged.
-  histogram_tester.ExpectUniqueSample(
-      metrics_internal::kImageRequestIncludesDesc, true, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-      0 /* OK RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
-      0 /* OK RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence,
-                         "DescCaption"),
-      90, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence, "DescLabel"),
-      100, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "DescCaption"),
-      false, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "DescLabel"),
-      false, 1);
-}
-
-// Test that the specialized OCR result takes precedence.
-TEST(AnnotatorTest, DoubleOcrResult) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-  TestImageProcessor processor;
-
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-  test_task_env.RunUntilIdle();
-
-  // HTTP request should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image1.jpg",
-             "engineResults": [
-               {
-                 "status": {},
-                 "ocrEngine": {
-                   "ocrRegions": [{
-                     "words": [{
-                       "detectedText": "Region 1",
-                       "confidenceScore": 1.0
-                     }]
-                   }]
-                 }
-               },
-               {
-                 "status": {},
-                 "descriptionEngine": {
-                   "descriptionList": {
-                     "descriptions": [
-                       {
-                         "type": "CAPTION",
-                         "text": "This is an example image.",
-                         "score": 0.9
-                       },
-                       {
-                         "type": "OCR",
-                         "text": "R3gi0n I",
-                         "score": 1.0
-                       }
-                     ]
-                   }
-                 }
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called.
-  ASSERT_THAT(error, Eq(std::nullopt));
-  EXPECT_THAT(annotations,
-              UnorderedElementsAre(
-                  AnnotatorEq(mojom::AnnotationType::kOcr, 1.0, "Region 1"),
-                  AnnotatorEq(mojom::AnnotationType::kCaption, 0.9,
-                              "This is an example image.")));
-
-  // Metrics about the returned results should have been logged.
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-      0 /* OK RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
-      0 /* OK RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence, "Ocr"), 100,
-      1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence,
-                         "DescCaption"),
-      90, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence, "DescOcr"),
-      100, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "Ocr"), false, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "DescCaption"),
-      false, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "DescOcr"), false,
-      1);
-}
-
-// Test that HTTP failure is gracefully handled.
-TEST(AnnotatorTest, HttpError) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor;
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      "", net::HTTP_INTERNAL_SERVER_ERROR);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called.
-  EXPECT_THAT(error, Eq(mojom::AnnotateImageError::kFailure));
-  EXPECT_THAT(annotations, IsEmpty());
-
-  // Metrics about the HTTP request failure should have been logged.
-  histogram_tester.ExpectUniqueSample(
-      metrics_internal::kServerNetError,
-      net::Error::ERR_HTTP_RESPONSE_CODE_FAILURE, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_INTERNAL_SERVER_ERROR, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kClientResult,
-                                      ClientResult::kFailed, 1);
-}
-
-// Test that backend failure is gracefully handled.
-TEST(AnnotatorTest, BackendError) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor;
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image1.jpg",
-             "engineResults": [
-               {
-                 "status": {
-                   "code": 8,
-                   "message": "Resource exhausted"
-                 },
-                 "ocrEngine": {}
-               },
-               {
-                 "status": {
-                   "code": 8,
-                   "messages": "Resource exhausted"
-                 },
-                 "descriptionEngine": {}
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called
-  // with an error status.
-  EXPECT_THAT(error, Eq(mojom::AnnotateImageError::kFailure));
-  EXPECT_THAT(annotations, IsEmpty());
-
-  // Metrics about the backend failure should have been logged.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                      net::Error::OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_OK, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-      8 /* Failed RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
-      8 /* Failed RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kClientResult,
-                                      ClientResult::kFailed, 1);
-}
-
-// Test that partial results are returned if the OCR backend fails.
-TEST(AnnotatorTest, OcrBackendError) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor;
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image1.jpg",
-             "engineResults": [
-               {
-                 "status": {
-                   "code": 8,
-                   "message": "Resource exhausted"
-                 },
-                 "ocrEngine": {}
-               },
-               {
-                 "status": {},
-                 "descriptionEngine": {
-                   "descriptionList": {
-                     "descriptions": [{
-                       "type": "CAPTION",
-                       "text": "This is an example image.",
-                       "score": 0.9
-                     }]
-                   }
-                 }
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called.
-  EXPECT_THAT(error, Eq(std::nullopt));
-  EXPECT_THAT(annotations, UnorderedElementsAre(
-                               AnnotatorEq(mojom::AnnotationType::kCaption, 0.9,
-                                           "This is an example image.")));
-
-  // Metrics about the partial results should have been logged.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                      net::Error::OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_OK, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-      8 /* Failed RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
-      0 /* OK RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence,
-                         "DescCaption"),
-      90, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "DescCaption"),
-      false, 1);
-}
-
-// Test that partial results are returned if the description backend fails.
-TEST(AnnotatorTest, DescriptionBackendError) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor;
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image1.jpg",
-             "engineResults": [
-               {
-                 "status": {},
-                 "ocrEngine": {
-                   "ocrRegions": [{
-                     "words": [{
-                       "detectedText": "1",
-                       "confidenceScore": 1.0
-                     }]
-                   }]
-                 }
-               },
-               {
-                 "status": {
-                   "code": 8,
-                   "message": "Resource exhausted"
-                 },
-                 "descriptionEngine": {}
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called.
-  EXPECT_THAT(error, Eq(std::nullopt));
-  EXPECT_THAT(annotations, UnorderedElementsAre(AnnotatorEq(
-                               mojom::AnnotationType::kOcr, 1.0, "1")));
-
-  // Metrics about the partial results should have been logged.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                      net::Error::OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_OK, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-      0 /* OK RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
-      8 /* Failed RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence, "Ocr"), 100,
-      1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "Ocr"), false, 1);
-}
-
-// Test that server failure (i.e. nonsense response) is gracefully handled.
-TEST(AnnotatorTest, ServerError) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor;
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request should have been made; respond with nonsense string.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      "Hello, world!", net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called
-  // with an error status.
-  EXPECT_THAT(error, Eq(mojom::AnnotateImageError::kFailure));
-  EXPECT_THAT(annotations, IsEmpty());
-
-  // Metrics about the invalid response format should have been logged.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                      net::Error::OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kJsonParseSuccess,
-                                      false, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kClientResult,
-                                      ClientResult::kFailed, 1);
-}
-
-// Test that adult content returns an error.
-TEST(AnnotatorTest, AdultError) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor;
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor for pixels.
-  ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image1.jpg",
-             "engineResults": [
-               {
-                 "status": {},
-                 "ocrEngine": {
-                   "ocrRegions": []
-                 }
-               },
-               {
-                 "status": {},
-                 "descriptionEngine": {
-                   "failureReason": "ADULT"
-                 }
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // HTTP response should have completed and callback should have been called
-  // with an error status.
-  EXPECT_THAT(error, Eq(mojom::AnnotateImageError::kAdult));
-  EXPECT_THAT(annotations, IsEmpty());
-
-  // Metrics about the adult error should have been logged.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                      net::Error::OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kDescFailure,
-                                      DescFailureReason::kAdult, 1);
-}
-
-// Test that work is reassigned if a processor fails.
-TEST(AnnotatorTest, ProcessorFails) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor[3];
-  std::optional<mojom::AnnotateImageError> error[3];
-  std::vector<mojom::Annotation> annotations[3];
-
-  for (int i = 0; i < 3; ++i) {
-    annotator.AnnotateImage(
-        kImage1Url, kDescLang, processor[i].GetPendingRemote(),
-        base::BindOnce(&ReportResult, &error[i], &annotations[i]));
-  }
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 for image 1's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-
-  // Make processor 1 fail by returning empty bytes.
-  std::move(processor[0].callbacks()[0]).Run({}, 0, 0);
-  processor[0].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 2 for image 1's pixels.
-  ASSERT_THAT(processor[0].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-
-  // Send back image data.
-  std::move(processor[1].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[1].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request for image 1 should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      kOcrSuccessResponse, net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called all callbacks, but request 1 received an error
-  // when we returned empty bytes.
-  ASSERT_THAT(error, ElementsAre(mojom::AnnotateImageError::kFailure,
-                                 std::nullopt, std::nullopt));
-  EXPECT_THAT(annotations[0], IsEmpty());
-  EXPECT_THAT(annotations[1],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-  EXPECT_THAT(annotations[2],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-
-  // Metrics about the pixel fetch failure should have been logged.
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples(metrics_internal::kPixelFetchSuccess),
-      UnorderedElementsAre(Bucket(false, 1), Bucket(true, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(metrics_internal::kClientResult),
-              UnorderedElementsAre(
-                  Bucket(static_cast<int32_t>(ClientResult::kFailed), 1),
-                  Bucket(static_cast<int32_t>(ClientResult::kSucceeded), 2)));
-}
-
-// Test a case that was previously buggy: when one client requests annotations,
-// then fails local processing, then another client makes the same request.
-TEST(AnnotatorTest, ProcessorFailedPreviously) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor[2];
-  std::optional<mojom::AnnotateImageError> error[2];
-  std::vector<mojom::Annotation> annotations[2];
-
-  // Processor 1 makes a request for annotation of a given image.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[0].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[0], &annotations[0]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 for the image's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-
-  // Make processor 1 fail by returning empty bytes.
-  std::move(processor[0].callbacks()[0]).Run({}, 0, 0);
-  processor[0].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // Processor 2 makes a request for annotation of the same image.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[1].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[1], &annotations[1]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 2 for the image's pixels.
-  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor[1].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[1].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request for image 1 should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      kOcrSuccessResponse, net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called all callbacks, but request 1 received an error
-  // when we returned empty bytes.
-  ASSERT_THAT(error,
-              ElementsAre(mojom::AnnotateImageError::kFailure, std::nullopt));
-  EXPECT_THAT(annotations[0], IsEmpty());
-  EXPECT_THAT(annotations[1],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-}
-
-// Test that work is reassigned if processor dies.
-TEST(AnnotatorTest, ProcessorDies) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor[3];
-  std::optional<mojom::AnnotateImageError> error[3];
-  std::vector<mojom::Annotation> annotations[3];
-
-  for (int i = 0; i < 3; ++i) {
-    annotator.AnnotateImage(
-        kImage1Url, kDescLang, processor[i].GetPendingRemote(),
-        base::BindOnce(&ReportResult, &error[i], &annotations[i]));
-  }
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 for image 1's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-
-  // Kill processor 1.
-  processor[0].Reset();
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 2 for image 1's pixels.
-  ASSERT_THAT(processor[0].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-
-  // Send back image data.
-  std::move(processor[1].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[1].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // HTTP request for image 1 should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      kOcrSuccessResponse, net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called all callbacks, but request 1 was canceled when
-  // we reset processor 1.
-  ASSERT_THAT(error, ElementsAre(mojom::AnnotateImageError::kCanceled,
-                                 std::nullopt, std::nullopt));
-  EXPECT_THAT(annotations[0], IsEmpty());
-  EXPECT_THAT(annotations[1],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-  EXPECT_THAT(annotations[2],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-
-  // Metrics about the client cancelation should have been logged.
-  EXPECT_THAT(histogram_tester.GetAllSamples(metrics_internal::kClientResult),
-              UnorderedElementsAre(
-                  Bucket(static_cast<int32_t>(ClientResult::kCanceled), 1),
-                  Bucket(static_cast<int32_t>(ClientResult::kSucceeded), 2)));
-}
-
-// Test that multiple concurrent requests are handled in the same batch.
-TEST(AnnotatorTest, ConcurrentSameBatch) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      3 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor[3];
-  std::optional<mojom::AnnotateImageError> error[3];
-  std::vector<mojom::Annotation> annotations[3];
-
-  // Request OCR for images 1, 2 and 3.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[0].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[0], &annotations[0]));
-  annotator.AnnotateImage(
-      kImage2Url, kDescLang, processor[1].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[1], &annotations[1]));
-  annotator.AnnotateImage(
-      kImage3Url, kDescLang, processor[2].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[2], &annotations[2]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 for image 1's pixels, processor
-  // 2 for image 2's pixels and processor 3 for image 3's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[2].callbacks(), SizeIs(1));
-
-  // Send back image data.
-  std::move(processor[0].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[0].callbacks().pop_back();
-  std::move(processor[1].callbacks()[0]).Run({4, 5, 6}, kDescDim, kDescDim);
-  processor[1].callbacks().pop_back();
-  std::move(processor[2].callbacks()[0]).Run({7, 8, 9}, kDescDim, kDescDim);
-  processor[2].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // A single HTTP request for all images should have been sent.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */, ReformatJson(kBatchRequest),
-      kBatchResponse, net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called each callback with its corresponding text or
-  // failure.
-  ASSERT_THAT(error, ElementsAre(std::nullopt, std::nullopt,
-                                 mojom::AnnotateImageError::kFailure));
-  EXPECT_THAT(annotations[0], UnorderedElementsAre(AnnotatorEq(
-                                  mojom::AnnotationType::kOcr, 1.0, "1")));
-  EXPECT_THAT(annotations[1], UnorderedElementsAre(AnnotatorEq(
-                                  mojom::AnnotationType::kOcr, 1.0, "2")));
-  EXPECT_THAT(annotations[2], IsEmpty());
-
-  // Metrics should have been logged for a single server response with multiple
-  // results included.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                      net::Error::OK, 1);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_OK, 1);
-  EXPECT_THAT(histogram_tester.GetAllSamples(base::StringPrintf(
-                  metrics_internal::kAnnotationStatus, "Ocr")),
-              UnorderedElementsAre(Bucket(8 /* Failed RPC status */, 1),
-                                   Bucket(0 /* OK RPC status */, 2)));
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence, "Ocr"), 100,
-      2);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "Ocr"), false, 2);
-  EXPECT_THAT(histogram_tester.GetAllSamples(metrics_internal::kClientResult),
-              UnorderedElementsAre(
-                  Bucket(static_cast<int32_t>(ClientResult::kFailed), 1),
-                  Bucket(static_cast<int32_t>(ClientResult::kSucceeded), 2)));
-}
-
-// Test that multiple concurrent requests are handled in separate batches.
-TEST(AnnotatorTest, ConcurrentSeparateBatches) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      3 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor[2];
-  std::optional<mojom::AnnotateImageError> error[2];
-  std::vector<mojom::Annotation> annotations[2];
-
-  // Request OCR for image 1.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[0].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[0], &annotations[0]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 for image 1's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-
-  // Send back image 1 data.
-  std::move(processor[0].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[0].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // Request OCR for image 2.
-  annotator.AnnotateImage(
-      kImage2Url, kDescLang, processor[1].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[1], &annotations[1]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 2 for image 2's pixels.
-  ASSERT_THAT(processor[0].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
-
-  // Send back image 2 data.
-  std::move(processor[1].callbacks()[0]).Run({4, 5, 6}, kDescDim, kDescDim);
-  processor[1].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // Only the HTTP request for image 1 should have been made (the service is
-  // still waiting to make the batch that will include the request for image
-  // 2).
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image1.jpg",
-             "engineResults": [
-               {
-                 "status": {},
-                 "ocrEngine": {
-                   "ocrRegions": [{
-                     "words": [{
-                       "detectedText": "1",
-                       "confidenceScore": 1.0
-                     }]
-                   }]
-                 }
-               },
-               {
-                 "status": {},
-                 "descriptionEngine": {
-                   "descriptionList": {}
-                 }
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // Now the HTTP request for image 2 should have been made.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage2Url, "BAUG")),
-      R"({
-           "results": [{
-             "imageId": "https://www.example.com/image2.jpg",
-             "engineResults": [
-               {
-                 "status": {},
-                 "ocrEngine": {
-                   "ocrRegions": [{
-                     "words": [{
-                       "detectedText": "2",
-                       "confidenceScore": 1.0
-                     }]
-                   }]
-                 }
-               },
-               {
-                 "status": {},
-                 "descriptionEngine": {
-                   "descriptionList": {}
-                 }
-               }
-             ]
-           }]
-         })",
-      net::HTTP_OK);
-
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called each callback with its corresponding text.
-  ASSERT_THAT(error, ElementsAre(std::nullopt, std::nullopt));
-  EXPECT_THAT(annotations[0], UnorderedElementsAre(AnnotatorEq(
-                                  mojom::AnnotationType::kOcr, 1.0, "1")));
-  EXPECT_THAT(annotations[1], UnorderedElementsAre(AnnotatorEq(
-                                  mojom::AnnotationType::kOcr, 1.0, "2")));
-
-  // Metrics should have been logged for two server responses.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerNetError,
-                                      net::Error::OK, 2);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kServerHttpResponseCode,
-                                      net::HTTP_OK, 2);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-      0 /* OK RPC status */, 2);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence, "Ocr"), 100,
-      2);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "Ocr"), false, 2);
-  histogram_tester.ExpectUniqueSample(metrics_internal::kClientResult,
-                                      ClientResult::kSucceeded, 2);
-}
-
-// Test that work is not duplicated if it is already ongoing.
-TEST(AnnotatorTest, DuplicateWork) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor[4];
-  std::optional<mojom::AnnotateImageError> error[4];
-  std::vector<mojom::Annotation> annotations[4];
-
-  // First request annotation of the image with processor 1.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[0].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[0], &annotations[0]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 for the image's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[3].callbacks(), IsEmpty());
-
-  // Now request annotation of the image with processor 2.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[1].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[1], &annotations[1]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator *should not* have asked processor 2 for the image's pixels (since
-  // processor 1 is already handling that).
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[3].callbacks(), IsEmpty());
-
-  // Get processor 1 to reply with bytes for the image.
-  std::move(processor[0].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[0].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // Now request annotation of the image with processor 3.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[2].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[2], &annotations[2]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator *should not* have asked processor 3 for the image's pixels (since
-  // it has already has the pixels in the HTTP request queue).
-  ASSERT_THAT(processor[0].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[3].callbacks(), IsEmpty());
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-
-  // Allow batch HTTP request to be sent off and then request annotation of the
-  // image with processor 4.
-  test_task_env.FastForwardBy(base::Seconds(1));
-  EXPECT_THAT(test_url_factory.requests(), SizeIs(1));
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[3].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[3], &annotations[3]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator *should not* have asked processor 4 for the image's pixels (since
-  // an HTTP request for the image is already in process).
-  ASSERT_THAT(processor[0].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[1].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[2].callbacks(), IsEmpty());
-  ASSERT_THAT(processor[3].callbacks(), IsEmpty());
-
-  // HTTP request for the image should have been made (with bytes obtained from
-  // processor 1).
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-      kOcrSuccessResponse, net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called all callbacks with annotation results.
-  ASSERT_THAT(error, ElementsAre(std::nullopt, std::nullopt, std::nullopt,
-                                 std::nullopt));
-  EXPECT_THAT(annotations[0],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-  EXPECT_THAT(annotations[1],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-  EXPECT_THAT(annotations[2],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-  EXPECT_THAT(annotations[3],
-              UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0,
-                                               "Region 1\nRegion 2")));
-
-  // Metrics should have been logged for a single pixel fetch.
-  histogram_tester.ExpectUniqueSample(metrics_internal::kPixelFetchSuccess,
-                                      true, 1);
-}
-
-// Test that the description engine is not requested for images that violate
-// model policy (i.e. are too small or have too-high an aspect ratio).
-TEST(AnnotatorTest, DescPolicy) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      3 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-
-  TestImageProcessor processor[3];
-  std::optional<mojom::AnnotateImageError> error[3];
-  std::vector<mojom::Annotation> annotations[3];
-
-  // Request annotation for images 1, 2 and 3.
-  annotator.AnnotateImage(
-      kImage1Url, kDescLang, processor[0].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[0], &annotations[0]));
-  annotator.AnnotateImage(
-      kImage2Url, kDescLang, processor[1].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[1], &annotations[1]));
-  annotator.AnnotateImage(
-      kImage3Url, kDescLang, processor[2].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[2], &annotations[2]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 for image 1's pixels, processor
-  // 2 for image 2's pixels and processor 3 for image 3's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[2].callbacks(), SizeIs(1));
-
-  // Send back image data.
-  //
-  // Image 1 is (just) within policy. Image 2 violates policy because it is too
-  // small. Image 3 is large enough, but violates policy because of its aspect
-  // ratio.
-  std::move(processor[0].callbacks()[0])
-      .Run({1, 2, 3}, Annotator::kDescMinDimension,
-           Annotator::kDescMinDimension);
-  processor[0].callbacks().pop_back();
-  std::move(processor[1].callbacks()[0])
-      .Run({4, 5, 6}, Annotator::kDescMinDimension,
-           Annotator::kDescMinDimension - 1);
-  processor[1].callbacks().pop_back();
-  std::move(processor[2].callbacks()[0])
-      .Run({7, 8, 9},
-           static_cast<int32_t>(Annotator::kDescMinDimension *
-                                Annotator::kDescMaxAspectRatio) +
-               1,
-           Annotator::kDescMinDimension);
-  processor[2].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // A single HTTP request for all images should have been sent.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      // Only image 1 includes a description request (as the other two violate
-      // one of the policies).
-      ReformatJson(R"(
-        {
-          "imageRequests": [
-            {
-              "imageId": "https://www.example.com/image3.jpg",
-              "imageBytes": "BwgJ",
-              "engineParameters": [
-                {"ocrParameters": {}}
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image2.jpg",
-              "imageBytes": "BAUG",
-              "engineParameters": [
-                {"ocrParameters": {}},
-                {"iconParameters": {}}
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image1.jpg",
-              "imageBytes": "AQID",
-              "engineParameters": [
-                {"ocrParameters": {}},
-                {"descriptionParameters": {}},
-                {"iconParameters": {}}
-              ]
-            }
-          ]
-        }
-      )"),
-      R"(
-        {
-          "results": [
-            {
-              "imageId": "https://www.example.com/image2.jpg",
-              "engineResults": [
-                {
-                  "status": {},
-                  "ocrEngine": {
-                    "ocrRegions": [{
-                      "words": [{
-                        "detectedText": "2",
-                        "confidenceScore": 1.0
-                      }]
-                    }]
-                  }
-                }
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image1.jpg",
-              "engineResults": [
-                {
-                  "status": {},
-                  "ocrEngine": {
-                    "ocrRegions": [{
-                      "words": [{
-                        "detectedText": "1",
-                        "confidenceScore": 1.0
-                      }]
-                    }]
-                  }
-                },
-                {
-                  "status": {},
-                  "descriptionEngine": {
-                    "descriptionList": {
-                      "descriptions": [{
-                        "type": "CAPTION",
-                        "text": "This is an example image.",
-                        "score": 1.0
-                      }]
-                    }
-                  }
-                }
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image3.jpg",
-              "engineResults": [
-                {
-                  "status": {},
-                  "ocrEngine": {
-                    "ocrRegions": [{
-                      "words": [{
-                        "detectedText": "3",
-                        "confidenceScore": 1.0
-                      }]
-                    }]
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      )",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called each callback with its corresponding results.
-  ASSERT_THAT(error, ElementsAre(std::nullopt, std::nullopt, std::nullopt));
-  EXPECT_THAT(
-      annotations[0],
-      UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0, "1"),
-                           AnnotatorEq(mojom::AnnotationType::kCaption, 1.0,
-                                       "This is an example image.")));
-  EXPECT_THAT(annotations[1], UnorderedElementsAre(AnnotatorEq(
-                                  mojom::AnnotationType::kOcr, 1.0, "2")));
-  EXPECT_THAT(annotations[2], UnorderedElementsAre(AnnotatorEq(
-                                  mojom::AnnotationType::kOcr, 1.0, "3")));
-
-  // Metrics should have been logged for the 3 OCR results and 1 description
-  // result.
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  metrics_internal::kImageRequestIncludesDesc),
-              UnorderedElementsAre(Bucket(false, 2), Bucket(true, 1)));
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
-      0 /* OK RPC status */, 3);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
-      0 /* OK RPC status */, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence, "Ocr"), 100,
-      3);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationConfidence,
-                         "DescCaption"),
-      100, 1);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "Ocr"), false, 3);
-  histogram_tester.ExpectUniqueSample(
-      base::StringPrintf(metrics_internal::kAnnotationEmpty, "DescCaption"),
-      false, 1);
-}
-
-// Test that description language preferences are sent to the server.
-TEST(AnnotatorTest, DescLanguage) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      3 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-  annotator.server_languages_ = {"en", "it", "fr"};
-
-  TestImageProcessor processor[3];
-  std::optional<mojom::AnnotateImageError> error[3];
-  std::vector<mojom::Annotation> annotations[3];
-
-  // Request annotation for one image in two languages, and one other image in
-  // one language.
-  annotator.AnnotateImage(
-      kImage1Url, "fr", processor[0].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[0], &annotations[0]));
-  annotator.AnnotateImage(
-      kImage1Url, "it", processor[1].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[1], &annotations[1]));
-  annotator.AnnotateImage(
-      kImage2Url, "en", processor[2].GetPendingRemote(),
-      base::BindOnce(&ReportResult, &error[2], &annotations[2]));
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have asked processor 1 and 2 for image 1's pixels and
-  // processor 3 for image 2's pixels.
-  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
-  ASSERT_THAT(processor[2].callbacks(), SizeIs(1));
-
-  // Send back image data. Image 2 is out of policy.
-  std::move(processor[0].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[0].callbacks().pop_back();
-  std::move(processor[1].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor[1].callbacks().pop_back();
-  std::move(processor[2].callbacks()[0])
-      .Run({4, 5, 6}, Annotator::kDescMinDimension - 1,
-           Annotator::kDescMinDimension);
-  processor[2].callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // No request should be sent yet (because service is waiting to batch up
-  // multiple requests).
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // A single HTTP request for all images should have been sent.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */,
-      // Image requests should include the preferred language in their image IDs
-      // and description parameters (except for image 2 which should not include
-      // description parameters).
-      ReformatJson(R"(
-        {
-          "imageRequests": [
-            {
-              "imageId": "https://www.example.com/image2.jpg en",
-              "imageBytes": "BAUG",
-              "engineParameters": [
-                {"ocrParameters": {}},
-                {"iconParameters": {}}
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image1.jpg it",
-              "imageBytes": "AQID",
-              "engineParameters": [
-                {"ocrParameters": {}},
-                {
-                  "descriptionParameters": {
-                    "preferredLanguages": ["it"]
-                  }
-                },
-                {"iconParameters": {}}
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image1.jpg fr",
-              "imageBytes": "AQID",
-              "engineParameters": [
-                {"ocrParameters": {}},
-                {
-                  "descriptionParameters": {
-                    "preferredLanguages": ["fr"]
-                  }
-                },
-                {"iconParameters": {}}
-              ]
-            }
-          ]
-        }
-      )"),
-      R"(
-        {
-          "results": [
-            {
-              "imageId": "https://www.example.com/image1.jpg it",
-              "engineResults": [
-                {
-                  "status": {},
-                  "ocrEngine": {
-                    "ocrRegions": [{
-                      "words": [{
-                        "detectedText": "1",
-                        "confidenceScore": 1.0
-                      }]
-                    }]
-                  }
-                },
-                {
-                  "status": {},
-                  "descriptionEngine": {
-                    "descriptionList": {
-                      "descriptions": [{
-                        "type": "CAPTION",
-                        "text": "This is an example image.",
-                        "score": 1.0
-                      }]
-                    }
-                  }
-                }
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image1.jpg fr",
-              "engineResults": [
-                {
-                  "status": {},
-                  "ocrEngine": {
-                    "ocrRegions": [{
-                      "words": [{
-                        "detectedText": "1",
-                        "confidenceScore": 1.0
-                      }]
-                    }]
-                  }
-                },
-                {
-                  "status": {},
-                  "descriptionEngine": {
-                    "descriptionList": {
-                      "descriptions": [{
-                        "type": "CAPTION",
-                        "text": "Ceci est un exemple d'image.",
-                        "score": 1.0
-                      }]
-                    }
-                  }
-                }
-              ]
-            },
-            {
-              "imageId": "https://www.example.com/image2.jpg en",
-              "engineResults": [
-                {
-                  "status": {},
-                  "ocrEngine": {
-                    "ocrRegions": [{
-                      "words": [{
-                        "detectedText": "2",
-                        "confidenceScore": 1.0
-                      }]
-                    }]
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      )",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called each callback with its corresponding results.
-  ASSERT_THAT(error, ElementsAre(std::nullopt, std::nullopt, std::nullopt));
-  EXPECT_THAT(
-      annotations[0],
-      UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0, "1"),
-                           AnnotatorEq(mojom::AnnotationType::kCaption, 1.0,
-                                       "Ceci est un exemple d'image.")));
-  EXPECT_THAT(
-      annotations[1],
-      UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0, "1"),
-                           AnnotatorEq(mojom::AnnotationType::kCaption, 1.0,
-                                       "This is an example image.")));
-  EXPECT_THAT(annotations[2], UnorderedElementsAre(AnnotatorEq(
-                                  mojom::AnnotationType::kOcr, 1.0, "2")));
-}
-
-// Test that annotation works properly when we need to fall back on a
-// different language because the page language isn't available.
-TEST(AnnotatorTest, LanguageFallback) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  TestServerURLLoaderFactory test_url_factory(
-      "https://ia-pa.googleapis.com/v1/");
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  base::HistogramTester histogram_tester;
-
-  Annotator annotator(
-      GURL(kTestServerUrl), GURL(""), std::string() /* api_key */, kThrottle,
-      1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-      test_url_factory.AsSharedURLLoaderFactory(), /*anchovy_provider=*/nullptr,
-      std::make_unique<TestAnnotatorClient>());
-  annotator.server_languages_ = {"en", "it", "fr"};
-
-  TestImageProcessor processor;
-  std::optional<mojom::AnnotateImageError> error;
-  std::vector<mojom::Annotation> annotations;
-
-  // Send a request in an unsupported language.
-  annotator.AnnotateImage(kImage1Url, "hu", processor.GetPendingRemote(),
-                          base::BindOnce(&ReportResult, &error, &annotations));
-  test_task_env.RunUntilIdle();
-
-  // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-  processor.callbacks().pop_back();
-  test_task_env.RunUntilIdle();
-
-  // Fast-forward time so that server sends batch.
-  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
-  test_task_env.FastForwardBy(base::Seconds(1));
-
-  // A single HTTP request for all images should have been sent.
-  test_url_factory.ExpectRequestAndSimulateResponse(
-      "annotation", {} /* expected_headers */, ReformatJson(R"(
-        {
-          "imageRequests": [
-            {
-              "imageId": "https://www.example.com/image1.jpg en",
-              "imageBytes": "AQID",
-              "engineParameters": [
-                {"ocrParameters": {}},
-                {
-                  "descriptionParameters": {
-                    "preferredLanguages": ["en"]
-                  }
-                },
-                {"iconParameters": {}}
-              ]
-            }
-          ]
-        }
-      )"),
-      R"(
-        {
-          "results": [
-            {
-              "imageId": "https://www.example.com/image1.jpg en",
-              "engineResults": [
-                {
-                  "status": {},
-                  "ocrEngine": {
-                    "ocrRegions": [{
-                      "words": [{
-                        "detectedText": "1",
-                        "confidenceScore": 1.0
-                      }]
-                    }]
-                  }
-                },
-                {
-                  "status": {},
-                  "descriptionEngine": {
-                    "descriptionList": {
-                      "descriptions": [{
-                        "type": "CAPTION",
-                        "text": "Result in fallback language.",
-                        "score": 1.0
-                      }]
-                    }
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      )",
-      net::HTTP_OK);
-  test_task_env.RunUntilIdle();
-
-  // Annotator should have called each callback with its corresponding results.
-  ASSERT_EQ(error, std::nullopt);
-  EXPECT_THAT(
-      annotations,
-      UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0, "1"),
-                           AnnotatorEq(mojom::AnnotationType::kCaption, 1.0,
-                                       "Result in fallback language.")));
-}
-
-// Test that the specified API key is sent, but only to Google-associated server
-// domains.
-TEST(AnnotatorTest, ApiKey) {
-  base::test::TaskEnvironment test_task_env(
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-
-  // A call to a secure Google-owner server URL should include the specified API
-  // key.
-  {
-    TestServerURLLoaderFactory test_url_factory(
-        "https://ia-pa.googleapis.com/v1/");
-
-    Annotator annotator(GURL(kTestServerUrl), GURL(""), "my_api_key", kThrottle,
-                        1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-                        test_url_factory.AsSharedURLLoaderFactory(),
-                        /*anchovy_provider=*/nullptr,
-                        std::make_unique<TestAnnotatorClient>());
-    TestImageProcessor processor;
-
-    annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                            base::DoNothing());
-    test_task_env.RunUntilIdle();
-
-    // Annotator should have asked processor for pixels.
-    ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-    // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-    processor.callbacks().pop_back();
-    test_task_env.FastForwardBy(base::Seconds(1));
-    test_task_env.RunUntilIdle();
-
-    // HTTP request should have been made with the API key included.
-    test_url_factory.ExpectRequestAndSimulateResponse(
-        "annotation", {{Annotator::kGoogApiKeyHeader, "my_api_key"}},
-        ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-        kOcrSuccessResponse, net::HTTP_OK);
-  }
-
-  // A call to a Google-owned server URL should not include the API key if the
-  // requests are made insecurely.
-  {
-    // Note: not HTTPS.
-    TestServerURLLoaderFactory test_url_factory(
-        "http://ia-pa.googleapis.com/v1/");
-
-    Annotator annotator(GURL("http://ia-pa.googleapis.com/v1/annotation"),
-                        GURL(""), "my_api_key", kThrottle, 1 /* batch_size */,
-                        1.0 /* min_ocr_confidence */,
-                        test_url_factory.AsSharedURLLoaderFactory(),
-                        /*anchovy_provider=*/nullptr,
-                        std::make_unique<TestAnnotatorClient>());
-    TestImageProcessor processor;
-
-    annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                            base::DoNothing());
-    test_task_env.RunUntilIdle();
-
-    // Annotator should have asked processor for pixels.
-    ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-    // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-    processor.callbacks().pop_back();
-    test_task_env.FastForwardBy(base::Seconds(1));
-    test_task_env.RunUntilIdle();
-
-    // HTTP request should have been made without the API key included.
-    test_url_factory.ExpectRequestAndSimulateResponse(
-        "annotation", {{Annotator::kGoogApiKeyHeader, std::nullopt}},
-        ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-        kOcrSuccessResponse, net::HTTP_OK);
-  }
-
-  // A call to a non-Google-owned URL should not include the API key.
-  {
-    TestServerURLLoaderFactory test_url_factory("https://datascraper.com/");
-
-    Annotator annotator(
-        GURL("https://datascraper.com/annotation"), GURL(""), "my_api_key",
-        kThrottle, 1 /* batch_size */, 1.0 /* min_ocr_confidence */,
-        test_url_factory.AsSharedURLLoaderFactory(),
-        /*anchovy_provider=*/nullptr, std::make_unique<TestAnnotatorClient>());
-    TestImageProcessor processor;
-
-    annotator.AnnotateImage(kImage1Url, kDescLang, processor.GetPendingRemote(),
-                            base::DoNothing());
-    test_task_env.RunUntilIdle();
-
-    // Annotator should have asked processor for pixels.
-    ASSERT_THAT(processor.callbacks(), SizeIs(1));
-
-    // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
-    processor.callbacks().pop_back();
-    test_task_env.FastForwardBy(base::Seconds(1));
-    test_task_env.RunUntilIdle();
-
-    // HTTP request should have been made without the API key included.
-    test_url_factory.ExpectRequestAndSimulateResponse(
-        "annotation", {{Annotator::kGoogApiKeyHeader, std::nullopt}},
-        ReformatJson(base::StringPrintf(kTemplateRequest, kImage1Url, "AQID")),
-        kOcrSuccessResponse, net::HTTP_OK);
-  }
-}
-
 // Tests that the Annotator computes a reasonable preferred language
 // based on the page language, top languages, accept languages, and
 // server languages.
@@ -2567,10 +405,6 @@
 void RunAnchovyAnnotatorTest(
     std::unique_ptr<manta::AnchovyProvider> fake_provider,
     std::vector<mojom::Annotation>* annotations) {
-  base::test::ScopedFeatureList enabled_features;
-  enabled_features.InitAndEnableFeature(
-      features::kImageDescriptionsAlternateRouting);
-
   base::test::TaskEnvironment test_task_env(
       base::test::TaskEnvironment::TimeSource::MOCK_TIME);
   TestServerURLLoaderFactory test_url_factory(
diff --git a/services/tracing/public/cpp/perfetto/metadata_data_source.cc b/services/tracing/public/cpp/perfetto/metadata_data_source.cc
index cd92940..0721274 100644
--- a/services/tracing/public/cpp/perfetto/metadata_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/metadata_data_source.cc
@@ -25,7 +25,15 @@
 
 void MetadataDataSource::OnStart(const StartArgs&) {}
 
+void MetadataDataSource::OnFlush(const FlushArgs&) {
+  WriteMetadata();
+}
+
 void MetadataDataSource::OnStop(const StopArgs&) {
+  WriteMetadata();
+}
+
+void MetadataDataSource::WriteMetadata() {
   Trace([&](TraceContext ctx) {
     auto packet = ctx.NewTracePacket();
     packet->set_timestamp(
@@ -60,6 +68,7 @@
     }
   });
 }
+
 }  // namespace tracing
 
 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(
diff --git a/services/tracing/public/cpp/perfetto/metadata_data_source.h b/services/tracing/public/cpp/perfetto/metadata_data_source.h
index 728c6997..56d4d9b 100644
--- a/services/tracing/public/cpp/perfetto/metadata_data_source.h
+++ b/services/tracing/public/cpp/perfetto/metadata_data_source.h
@@ -13,8 +13,8 @@
 // This class is a data source that populates a ChromeMetadataPacket
 // field in a perfetto trace. Currently only field trial hashes
 // and version code (for official Android builds) are recorded
-// when the tracing session is stopping.
-// This data source supports multiple concurrent sessions,
+// when the tracing session is flushed (to cover the cases when a session is
+// cloned) or stopped. This data source supports multiple concurrent sessions,
 // unlike TraceEventMetadataSource in trace_event_data_source.h
 class COMPONENT_EXPORT(TRACING_CPP) MetadataDataSource
     : public perfetto::DataSource<MetadataDataSource> {
@@ -22,7 +22,11 @@
   static void Register();
 
   void OnStart(const StartArgs&) override;
+  void OnFlush(const FlushArgs&) override;
   void OnStop(const StopArgs&) override;
+
+ private:
+  void WriteMetadata();
 };
 
 }  // namespace tracing
diff --git a/services/webnn/coreml/context_impl_coreml.h b/services/webnn/coreml/context_impl_coreml.h
index 5c721aa..19ce6df 100644
--- a/services/webnn/coreml/context_impl_coreml.h
+++ b/services/webnn/coreml/context_impl_coreml.h
@@ -41,10 +41,10 @@
       WebNNGraphImpl::ComputeResourceInfo compute_resource_info,
       CreateGraphImplCallback callback) override;
 
-  void CreateBufferImpl(
+  void CreateTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-      mojom::BufferInfoPtr buffer_info,
-      CreateBufferImplCallback callback) override;
+      mojom::TensorInfoPtr tensor_info,
+      CreateTensorImplCallback callback) override;
 
   base::WeakPtrFactory<ContextImplCoreml> weak_factory_{this};
 };
diff --git a/services/webnn/coreml/context_impl_coreml.mm b/services/webnn/coreml/context_impl_coreml.mm
index b817bdbc..b137378 100644
--- a/services/webnn/coreml/context_impl_coreml.mm
+++ b/services/webnn/coreml/context_impl_coreml.mm
@@ -42,12 +42,12 @@
       options().Clone(), properties(), std::move(callback));
 }
 
-void ContextImplCoreml::CreateBufferImpl(
+void ContextImplCoreml::CreateTensorImpl(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-    mojom::BufferInfoPtr buffer_info,
-    CreateBufferImplCallback callback) {
+    mojom::TensorInfoPtr tensor_info,
+    CreateTensorImplCallback callback) {
   std::move(callback).Run(TensorImplCoreml::Create(std::move(receiver), this,
-                                                   std::move(buffer_info)));
+                                                   std::move(tensor_info)));
 }
 
 }  // namespace webnn::coreml
diff --git a/services/webnn/coreml/tensor_impl_coreml.h b/services/webnn/coreml/tensor_impl_coreml.h
index bb9f7c7..84ce458 100644
--- a/services/webnn/coreml/tensor_impl_coreml.h
+++ b/services/webnn/coreml/tensor_impl_coreml.h
@@ -27,12 +27,12 @@
   static base::expected<std::unique_ptr<WebNNTensorImpl>, mojom::ErrorPtr>
   Create(mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
          WebNNContextImpl* context,
-         mojom::BufferInfoPtr buffer_info);
+         mojom::TensorInfoPtr tensor_info);
 
   TensorImplCoreml(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
       WebNNContextImpl* context,
-      mojom::BufferInfoPtr buffer_info,
+      mojom::TensorInfoPtr tensor_info,
       scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
       base::PassKey<TensorImplCoreml> pass_key);
 
@@ -41,8 +41,8 @@
   ~TensorImplCoreml() override;
 
   // WebNNTensorImpl:
-  void ReadBufferImpl(mojom::WebNNTensor::ReadBufferCallback callback) override;
-  void WriteBufferImpl(mojo_base::BigBuffer src_buffer) override;
+  void ReadTensorImpl(mojom::WebNNTensor::ReadTensorCallback callback) override;
+  void WriteTensorImpl(mojo_base::BigBuffer src_buffer) override;
 
   const scoped_refptr<QueueableResourceState<BufferContent>>& GetBufferState()
       const;
diff --git a/services/webnn/coreml/tensor_impl_coreml.mm b/services/webnn/coreml/tensor_impl_coreml.mm
index 4c45765..26f531c 100644
--- a/services/webnn/coreml/tensor_impl_coreml.mm
+++ b/services/webnn/coreml/tensor_impl_coreml.mm
@@ -48,13 +48,13 @@
 TensorImplCoreml::Create(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
     WebNNContextImpl* context,
-    mojom::BufferInfoPtr buffer_info) {
+    mojom::TensorInfoPtr tensor_info) {
   // TODO(crbug.com/343638938): Check `MLTensorUsageFlags` and use an
   // IOSurface to facilitate zero-copy buffer sharing with WebGPU when possible.
 
   // TODO(crbug.com/329482489): Move this check to the renderer and throw a
   // TypeError.
-  if (buffer_info->descriptor.Rank() > 5) {
+  if (tensor_info->descriptor.Rank() > 5) {
     LOG(ERROR) << "[WebNN] Buffer rank is too large.";
     return base::unexpected(mojom::Error::New(
         mojom::Error::Code::kNotSupportedError, "Buffer rank is too large."));
@@ -68,21 +68,21 @@
   // TODO(crbug.com/356670455): Consider moving this check to the renderer and
   // throwing a TypeError.
   if (!base::IsValueInRangeForNumericType<int>(
-          buffer_info->descriptor.PackedByteLength())) {
+          tensor_info->descriptor.PackedByteLength())) {
     LOG(ERROR) << "[WebNN] Buffer is too large to create.";
     return base::unexpected(mojom::Error::New(
         mojom::Error::Code::kUnknownError, "Buffer is too large to create."));
   }
 
   NSMutableArray<NSNumber*>* ns_shape = [[NSMutableArray alloc] init];
-  for (uint32_t dimension : buffer_info->descriptor.shape()) {
+  for (uint32_t dimension : tensor_info->descriptor.shape()) {
     [ns_shape addObject:[[NSNumber alloc] initWithUnsignedLong:dimension]];
   }
 
   NSError* error = nil;
   MLMultiArray* multi_array = [[MLMultiArray alloc]
       initWithShape:ns_shape
-           dataType:ToMLMultiArrayDataType(buffer_info->descriptor.data_type())
+           dataType:ToMLMultiArrayDataType(tensor_info->descriptor.data_type())
               error:&error];
   if (error) {
     LOG(ERROR) << "[WebNN] Failed to allocate buffer: " << error;
@@ -110,25 +110,25 @@
       base::MakeRefCounted<QueueableResourceState<BufferContent>>(
           std::move(buffer_content));
   return base::WrapUnique(new TensorImplCoreml(
-      std::move(receiver), context, std::move(buffer_info),
+      std::move(receiver), context, std::move(tensor_info),
       std::move(buffer_state), base::PassKey<TensorImplCoreml>()));
 }
 
 TensorImplCoreml::TensorImplCoreml(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
     WebNNContextImpl* context,
-    mojom::BufferInfoPtr buffer_info,
+    mojom::TensorInfoPtr tensor_info,
     scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
     base::PassKey<TensorImplCoreml> /*pass_key*/)
-    : WebNNTensorImpl(std::move(receiver), context, std::move(buffer_info)),
+    : WebNNTensorImpl(std::move(receiver), context, std::move(tensor_info)),
       buffer_state_(std::move(buffer_state)) {}
 
 TensorImplCoreml::~TensorImplCoreml() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void TensorImplCoreml::ReadBufferImpl(
-    mojom::WebNNTensor::ReadBufferCallback callback) {
+void TensorImplCoreml::ReadTensorImpl(
+    mojom::WebNNTensor::ReadTensorCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Lock the buffer contents as shared/read-only.
@@ -142,7 +142,7 @@
       base::BindOnce(
           [](size_t bytes_to_read,
              scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
-             ReadBufferCallback read_buffer_result_callback,
+             ReadTensorCallback read_buffer_result_callback,
              base::OnceClosure completion_closure) {
             mojo_base::BigBuffer output_buffer(bytes_to_read);
 
@@ -150,13 +150,13 @@
             // until `completion_closure` is run.
             buffer_state->GetSharedLockedResource().Read(base::BindOnce(
                 [](base::OnceClosure completion_closure,
-                   ReadBufferCallback read_buffer_result_callback,
+                   ReadTensorCallback read_buffer_result_callback,
                    mojo_base::BigBuffer output_buffer) {
                   // Unlock the buffer contents.
                   std::move(completion_closure).Run();
 
                   std::move(read_buffer_result_callback)
-                      .Run(mojom::ReadBufferResult::NewBuffer(
+                      .Run(mojom::ReadTensorResult::NewBuffer(
                           std::move(output_buffer)));
                 },
                 std::move(completion_closure),
@@ -167,7 +167,7 @@
   task->Enqueue();
 }
 
-void TensorImplCoreml::WriteBufferImpl(mojo_base::BigBuffer src_buffer) {
+void TensorImplCoreml::WriteTensorImpl(mojo_base::BigBuffer src_buffer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Take an exclusive lock to the buffer contents while writing.
diff --git a/services/webnn/dml/context_impl_dml.cc b/services/webnn/dml/context_impl_dml.cc
index ba1be17..336af7f 100644
--- a/services/webnn/dml/context_impl_dml.cc
+++ b/services/webnn/dml/context_impl_dml.cc
@@ -38,7 +38,7 @@
 
 void HandleBufferCreationFailure(
     const std::string& error_message,
-    WebNNContextImpl::CreateBufferImplCallback callback) {
+    WebNNContextImpl::CreateTensorImplCallback callback) {
   std::move(callback).Run(base::unexpected(
       CreateError(mojom::Error::Code::kUnknownError, error_message)));
 }
@@ -431,15 +431,15 @@
           gpu::DML_EXECUTION_DISABLE_META_COMMANDS));
 }
 
-void ContextImplDml::CreateBufferImpl(
+void ContextImplDml::CreateTensorImpl(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-    mojom::BufferInfoPtr buffer_info,
-    CreateBufferImplCallback callback) {
+    mojom::TensorInfoPtr tensor_info,
+    CreateTensorImplCallback callback) {
   // DML requires resources to be in multiple of 4 bytes.
   // https://learn.microsoft.com/en-us/windows/ai/directml/dml-helper-functions#dmlcalcbuffertensorsize
   constexpr uint64_t kDMLBufferAlignment = 4ull;
   if (std::numeric_limits<uint64_t>::max() - kDMLBufferAlignment <
-      static_cast<uint64_t>(buffer_info->descriptor.PackedByteLength())) {
+      static_cast<uint64_t>(tensor_info->descriptor.PackedByteLength())) {
     LOG(ERROR) << "[WebNN] Buffer is too large to create.";
     HandleBufferCreationFailure("Failed to create buffer.",
                                 std::move(callback));
@@ -447,7 +447,7 @@
   }
 
   const uint64_t aligned_buffer_byte_size = base::bits::AlignUp(
-      static_cast<uint64_t>(buffer_info->descriptor.PackedByteLength()),
+      static_cast<uint64_t>(tensor_info->descriptor.PackedByteLength()),
       kDMLBufferAlignment);
 
   HRESULT hr = S_OK;
@@ -458,14 +458,14 @@
   if (adapter_->IsUMA()) {
     // Create a buffer configured with memory properties based on
     // usage.
-    if (buffer_info->usage.Has(MLTensorUsageFlags::kWriteTo)) {
+    if (tensor_info->usage.Has(MLTensorUsageFlags::kWriteTo)) {
       // Upload buffer is used when the buffer mostly CPU writes but
       // could also CPU read. A upload buffer provides less bandwidth for CPU
       // reads in favor of GPU writes being optimal.
       hr = CreateCustomUploadBuffer(
           adapter_->d3d12_device(), aligned_buffer_byte_size,
           L"WebNN_Custom_Upload_Buffer_External", buffer);
-    } else if (buffer_info->usage.Has(MLTensorUsageFlags::kReadFrom)) {
+    } else if (tensor_info->usage.Has(MLTensorUsageFlags::kReadFrom)) {
       // Readback buffer is used when the buffer only requires CPU reads.
       hr = CreateCustomReadbackBuffer(
           adapter_->d3d12_device(), aligned_buffer_byte_size,
@@ -496,20 +496,20 @@
   // Safe to use ContextImplDml* because this context owns the buffer
   // being connected and that context cannot destruct before the buffer.
   std::move(callback).Run(std::make_unique<TensorImplDml>(
-      std::move(receiver), std::move(buffer), this, std::move(buffer_info)));
+      std::move(receiver), std::move(buffer), this, std::move(tensor_info)));
 }
 
-void ContextImplDml::ReadBuffer(
-    TensorImplDml* src_buffer,
-    mojom::WebNNTensor::ReadBufferCallback callback) {
-  const size_t src_buffer_size = src_buffer->PackedByteLength();
+void ContextImplDml::ReadTensor(
+    TensorImplDml* src_tensor,
+    mojom::WebNNTensor::ReadTensorCallback callback) {
+  const size_t src_tensor_size = src_tensor->PackedByteLength();
 
   HRESULT hr = S_OK;
 
   // Map entire buffer to readback the output data.
   if (adapter_->IsUMA() && adapter_->command_queue()->GetCompletedValue() >=
-                               src_buffer->last_submission_fence_value()) {
-    ContextImplDml::OnReadbackComplete(src_buffer->buffer(), src_buffer_size,
+                               src_tensor->last_submission_fence_value()) {
+    ContextImplDml::OnReadbackComplete(src_tensor->buffer(), src_tensor_size,
                                        std::move(callback), hr);
     return;
   }
@@ -517,10 +517,10 @@
   // Copy the buffer into a staging buffer to readback the output data.
   ComPtr<ID3D12Resource> download_buffer;
   hr = CreateReadbackBuffer(adapter_->d3d12_device(),
-                            static_cast<uint64_t>(src_buffer_size),
+                            static_cast<uint64_t>(src_tensor_size),
                             L"WebNN_Readback_Buffer", download_buffer);
   if (FAILED(hr)) {
-    std::move(callback).Run(ToError<mojom::ReadBufferResult>(
+    std::move(callback).Run(ToError<mojom::ReadTensorResult>(
         mojom::Error::Code::kUnknownError, "Failed to read buffer."));
     HandleContextLostOrCrash("Failed to create the download buffer.", hr);
     return;
@@ -528,19 +528,19 @@
 
   hr = StartRecordingIfNecessary();
   if (FAILED(hr)) {
-    std::move(callback).Run(ToError<mojom::ReadBufferResult>(
+    std::move(callback).Run(ToError<mojom::ReadTensorResult>(
         mojom::Error::Code::kUnknownError, "Failed to read buffer."));
     HandleRecordingError("Failed to start recording.", hr);
     return;
   }
 
-  command_recorder_->ReadbackBufferWithBarrier(download_buffer, src_buffer,
-                                               src_buffer_size);
+  command_recorder_->ReadbackBufferWithBarrier(download_buffer, src_tensor,
+                                               src_tensor_size);
 
   // Submit copy and schedule GPU wait.
   hr = command_recorder_->CloseAndExecute();
   if (FAILED(hr)) {
-    std::move(callback).Run(ToError<mojom::ReadBufferResult>(
+    std::move(callback).Run(ToError<mojom::ReadTensorResult>(
         mojom::Error::Code::kUnknownError, "Failed to read buffer."));
     HandleRecordingError("Failed to close and execute the command list.", hr);
     return;
@@ -551,16 +551,16 @@
   // CommandRecorder::CloseAndExecute().
   adapter_->command_queue()->WaitAsync(base::BindOnce(
       &ContextImplDml::OnReadbackComplete, weak_factory_.GetWeakPtr(),
-      std::move(download_buffer), src_buffer_size, std::move(callback)));
+      std::move(download_buffer), src_tensor_size, std::move(callback)));
 }
 
 void ContextImplDml::OnReadbackComplete(
     ComPtr<ID3D12Resource> download_buffer,
     size_t read_byte_size,
-    mojom::WebNNTensor::ReadBufferCallback callback,
+    mojom::WebNNTensor::ReadTensorCallback callback,
     HRESULT hr) {
   if (FAILED(hr)) {
-    std::move(callback).Run(ToError<mojom::ReadBufferResult>(
+    std::move(callback).Run(ToError<mojom::ReadTensorResult>(
         mojom::Error::Code::kUnknownError, "Failed to read buffer."));
     HandleRecordingError("Failed to download the buffer.", hr);
     return;
@@ -572,7 +572,7 @@
   void* mapped_download_data = nullptr;
   hr = download_buffer->Map(0, nullptr, &mapped_download_data);
   if (FAILED(hr)) {
-    std::move(callback).Run(ToError<mojom::ReadBufferResult>(
+    std::move(callback).Run(ToError<mojom::ReadTensorResult>(
         mojom::Error::Code::kUnknownError, "Failed to read buffer."));
     HandleContextLostOrCrash("Failed to map the download buffer.", hr);
     return;
@@ -584,18 +584,18 @@
   download_buffer->Unmap(0, nullptr);
 
   std::move(callback).Run(
-      mojom::ReadBufferResult::NewBuffer(std::move(dst_buffer)));
+      mojom::ReadTensorResult::NewBuffer(std::move(dst_buffer)));
 }
 
-void ContextImplDml::WriteBuffer(TensorImplDml* dst_buffer,
+void ContextImplDml::WriteTensor(TensorImplDml* dst_tensor,
                                  mojo_base::BigBuffer src_buffer) {
   HRESULT hr = S_OK;
-  ComPtr<ID3D12Resource> buffer_to_map = dst_buffer->buffer();
+  ComPtr<ID3D12Resource> buffer_to_map = dst_tensor->buffer();
 
   // Create a staging buffer to upload data into when the existing buffer
   // cannot be updated by the CPU.
   if (!adapter_->IsUMA() || adapter_->command_queue()->GetCompletedValue() <
-                                dst_buffer->last_submission_fence_value()) {
+                                dst_tensor->last_submission_fence_value()) {
     hr = CreateUploadBuffer(adapter_->d3d12_device(), src_buffer.size(),
                             L"WebNN_Upload_Buffer", buffer_to_map);
     if (FAILED(hr)) {
@@ -624,7 +624,7 @@
   buffer_to_map->Unmap(0, nullptr);
 
   // Uploads are only required when the mapped buffer was a staging buffer.
-  if (dst_buffer->buffer() != buffer_to_map.Get()) {
+  if (dst_tensor->buffer() != buffer_to_map.Get()) {
     hr = StartRecordingIfNecessary();
     if (FAILED(hr)) {
       HandleRecordingError("Failed to start recording.", hr);
@@ -632,7 +632,7 @@
     }
 
     command_recorder_->UploadBufferWithBarrier(
-        dst_buffer, std::move(buffer_to_map), src_buffer.size());
+        dst_tensor, std::move(buffer_to_map), src_buffer.size());
 
     // TODO(crbug.com/40278771): consider not submitting after every write.
     // CloseAndExecute() only needs to be called once, when the buffer is read
diff --git a/services/webnn/dml/context_impl_dml.h b/services/webnn/dml/context_impl_dml.h
index bc847cf..58519e7e 100644
--- a/services/webnn/dml/context_impl_dml.h
+++ b/services/webnn/dml/context_impl_dml.h
@@ -44,10 +44,10 @@
   // WebNNContextImpl:
   base::WeakPtr<WebNNContextImpl> AsWeakPtr() override;
 
-  void ReadBuffer(TensorImplDml* src_buffer,
-                  mojom::WebNNTensor::ReadBufferCallback callback);
+  void ReadTensor(TensorImplDml* src_tensor,
+                  mojom::WebNNTensor::ReadTensorCallback callback);
 
-  void WriteBuffer(TensorImplDml* dst_buffer, mojo_base::BigBuffer src_buffer);
+  void WriteTensor(TensorImplDml* dst_tensor, mojo_base::BigBuffer src_buffer);
 
   // Some errors like `E_OUTOFMEMORY`, `DXGI_ERROR_DEVICE_REMOVED` and
   // `DXGI_ERROR_DEVICE_RESET` are treated as `context lost` errors, other
@@ -63,10 +63,10 @@
       WebNNGraphImpl::ComputeResourceInfo compute_resource_info,
       CreateGraphImplCallback callback) override;
 
-  void CreateBufferImpl(
+  void CreateTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-      mojom::BufferInfoPtr buffer_info,
-      CreateBufferImplCallback callback) override;
+      mojom::TensorInfoPtr tensor_info,
+      CreateTensorImplCallback callback) override;
 
   // Begins recording commands needed for context operations.
   // If recording failed, calling this function will recreate the recorder to
@@ -83,7 +83,7 @@
   void OnReadbackComplete(
       Microsoft::WRL::ComPtr<ID3D12Resource> download_buffer,
       size_t read_byte_size,
-      mojom::WebNNTensor::ReadBufferCallback callback,
+      mojom::WebNNTensor::ReadTensorCallback callback,
       HRESULT hr);
 
   // After the upload completes, tell the queue to immediately
diff --git a/services/webnn/dml/tensor_impl_dml.cc b/services/webnn/dml/tensor_impl_dml.cc
index e25d6eb..05efe5d 100644
--- a/services/webnn/dml/tensor_impl_dml.cc
+++ b/services/webnn/dml/tensor_impl_dml.cc
@@ -14,20 +14,20 @@
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
     Microsoft::WRL::ComPtr<ID3D12Resource> buffer,
     ContextImplDml* context,
-    mojom::BufferInfoPtr buffer_info)
-    : WebNNTensorImpl(std::move(receiver), context, std::move(buffer_info)),
+    mojom::TensorInfoPtr tensor_info)
+    : WebNNTensorImpl(std::move(receiver), context, std::move(tensor_info)),
       buffer_(std::move(buffer)) {}
 
 TensorImplDml::~TensorImplDml() = default;
 
-void TensorImplDml::ReadBufferImpl(ReadBufferCallback callback) {
+void TensorImplDml::ReadTensorImpl(ReadTensorCallback callback) {
   static_cast<ContextImplDml*>(context_.get())
-      ->ReadBuffer(this, std::move(callback));
+      ->ReadTensor(this, std::move(callback));
 }
 
-void TensorImplDml::WriteBufferImpl(mojo_base::BigBuffer src_buffer) {
+void TensorImplDml::WriteTensorImpl(mojo_base::BigBuffer src_buffer) {
   static_cast<ContextImplDml*>(context_.get())
-      ->WriteBuffer(this, std::move(src_buffer));
+      ->WriteTensor(this, std::move(src_buffer));
 }
 
 void TensorImplDml::SetLastSubmissionFenceValue(
diff --git a/services/webnn/dml/tensor_impl_dml.h b/services/webnn/dml/tensor_impl_dml.h
index 1e68942..fa68883 100644
--- a/services/webnn/dml/tensor_impl_dml.h
+++ b/services/webnn/dml/tensor_impl_dml.h
@@ -21,7 +21,7 @@
   TensorImplDml(mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
                 Microsoft::WRL::ComPtr<ID3D12Resource> buffer,
                 ContextImplDml* context,
-                mojom::BufferInfoPtr buffer_info);
+                mojom::TensorInfoPtr tensor_info);
 
   TensorImplDml(const TensorImplDml&) = delete;
   TensorImplDml& operator=(const TensorImplDml&) = delete;
@@ -40,8 +40,8 @@
   }
 
  private:
-  void ReadBufferImpl(ReadBufferCallback callback) override;
-  void WriteBufferImpl(mojo_base::BigBuffer src_buffer) override;
+  void ReadTensorImpl(ReadTensorCallback callback) override;
+  void WriteTensorImpl(mojo_base::BigBuffer src_buffer) override;
 
   // The D3D12 resource that holds the buffer data.
   // The buffer must always remain valid after creation and could outlive
diff --git a/services/webnn/public/cpp/ml_tensor_usage.h b/services/webnn/public/cpp/ml_tensor_usage.h
index 39f65ee..88521a56 100644
--- a/services/webnn/public/cpp/ml_tensor_usage.h
+++ b/services/webnn/public/cpp/ml_tensor_usage.h
@@ -13,10 +13,10 @@
   // This buffer may be imported/rented to WebGPU.
   kWebGpuInterop,
 
-  // This buffer can be used with readBuffer().
+  // This buffer can be used with readTensor().
   kReadFrom,
 
-  // This buffer can be used with writeBuffer().
+  // This buffer can be used with writeTensor().
   kWriteTo,
 
   kMinValue = kWebGpuInterop,
diff --git a/services/webnn/public/mojom/BUILD.gn b/services/webnn/public/mojom/BUILD.gn
index df3dc6d..7153f5a 100644
--- a/services/webnn/public/mojom/BUILD.gn
+++ b/services/webnn/public/mojom/BUILD.gn
@@ -29,11 +29,6 @@
     {
       types = [
         {
-          mojom = "webnn.mojom.BufferUsage"
-          cpp = "::webnn::MLTensorUsage"
-          copyable_pass_by_value = true
-        },
-        {
           mojom = "webnn.mojom.ContextProperties"
           cpp = "::webnn::ContextProperties"
           default_constructible = false
@@ -52,13 +47,18 @@
           mojom = "webnn.mojom.SupportedDataTypes"
           cpp = "::webnn::SupportedDataTypes"
         },
+        {
+          mojom = "webnn.mojom.TensorUsage"
+          cpp = "::webnn::MLTensorUsage"
+          copyable_pass_by_value = true
+        },
       ]
       traits_headers = [
-        "buffer_usage_mojom_traits.h",
         "context_properties_mojom_traits.h",
         "data_type_limits_mojom_traits.h",
         "operand_descriptor_mojom_traits.h",
         "supported_data_types_mojom_traits.h",
+        "tensor_usage_mojom_traits.h",
       ]
       traits_public_deps = [ ":webnn_mojom_traits" ]
     },
diff --git a/services/webnn/public/mojom/operand_descriptor_mojom_traits_unittest.cc b/services/webnn/public/mojom/operand_descriptor_mojom_traits_unittest.cc
index 142dbc7..fa2fe47 100644
--- a/services/webnn/public/mojom/operand_descriptor_mojom_traits_unittest.cc
+++ b/services/webnn/public/mojom/operand_descriptor_mojom_traits_unittest.cc
@@ -9,7 +9,7 @@
 #include "mojo/public/cpp/test_support/test_utils.h"
 #include "services/webnn/public/cpp/ml_tensor_usage.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
-#include "services/webnn/public/mojom/buffer_usage_mojom_traits.h"
+#include "services/webnn/public/mojom/tensor_usage_mojom_traits.h"
 #include "services/webnn/public/mojom/webnn_graph.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/services/webnn/public/mojom/buffer_usage_mojom_traits.h b/services/webnn/public/mojom/tensor_usage_mojom_traits.h
similarity index 78%
rename from services/webnn/public/mojom/buffer_usage_mojom_traits.h
rename to services/webnn/public/mojom/tensor_usage_mojom_traits.h
index 6043900..2beaf7f 100644
--- a/services/webnn/public/mojom/buffer_usage_mojom_traits.h
+++ b/services/webnn/public/mojom/tensor_usage_mojom_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SERVICES_WEBNN_PUBLIC_MOJOM_BUFFER_USAGE_MOJOM_TRAITS_H_
-#define SERVICES_WEBNN_PUBLIC_MOJOM_BUFFER_USAGE_MOJOM_TRAITS_H_
+#ifndef SERVICES_WEBNN_PUBLIC_MOJOM_TENSOR_USAGE_MOJOM_TRAITS_H_
+#define SERVICES_WEBNN_PUBLIC_MOJOM_TENSOR_USAGE_MOJOM_TRAITS_H_
 
 #include "mojo/public/cpp/bindings/struct_traits.h"
 #include "services/webnn/public/cpp/ml_tensor_usage.h"
@@ -12,7 +12,7 @@
 namespace mojo {
 
 template <>
-struct StructTraits<webnn::mojom::BufferUsageDataView, webnn::MLTensorUsage> {
+struct StructTraits<webnn::mojom::TensorUsageDataView, webnn::MLTensorUsage> {
   static bool web_gpu_interop(const webnn::MLTensorUsage& usage) {
     return usage.Has(webnn::MLTensorUsageFlags::kWebGpuInterop);
   }
@@ -25,7 +25,7 @@
     return usage.Has(webnn::MLTensorUsageFlags::kReadFrom);
   }
 
-  static bool Read(webnn::mojom::BufferUsageDataView data,
+  static bool Read(webnn::mojom::TensorUsageDataView data,
                    webnn::MLTensorUsage* out) {
     out->Clear();
 
@@ -47,4 +47,4 @@
 
 }  // namespace mojo
 
-#endif  // SERVICES_WEBNN_PUBLIC_MOJOM_BUFFER_USAGE_MOJOM_TRAITS_H_
+#endif  // SERVICES_WEBNN_PUBLIC_MOJOM_TENSOR_USAGE_MOJOM_TRAITS_H_
diff --git a/services/webnn/public/mojom/webnn_context.mojom b/services/webnn/public/mojom/webnn_context.mojom
index d80c926..8cf41e1 100644
--- a/services/webnn/public/mojom/webnn_context.mojom
+++ b/services/webnn/public/mojom/webnn_context.mojom
@@ -10,20 +10,20 @@
 import "services/webnn/public/mojom/webnn_graph_builder.mojom";
 import "third_party/blink/public/mojom/tokens/tokens.mojom";
 
-// Represents a successful call to `WebNNContext::CreateBuffer()`.
-struct CreateBufferSuccess {
-  pending_associated_remote<WebNNTensor> buffer_remote;
-  // buffer_handle is a generated token used as a handle to identify the buffer
+// Represents a successful call to `WebNNContext::CreateTensor()`.
+struct CreateTensorSuccess {
+  pending_associated_remote<WebNNTensor> tensor_remote;
+  // tensor_handle is a generated token used as a handle to identify the tensor
   // from the renderer. The token is only valid for the lifetime
-  // of the buffer and is used by context operations in the service using the
-  // buffer corresponding to this handle.
-  blink.mojom.WebNNTensorToken buffer_handle;
+  // of the tensor and is used by context operations in the service using the
+  // tensor corresponding to this handle.
+  blink.mojom.WebNNTensorToken tensor_handle;
 };
 
-// Represents the return value of `WebNNContext::CreateBuffer()`. Let it be
-// `success` if the buffer was successfully created and `error` otherwise.
-union CreateBufferResult {
-  CreateBufferSuccess success;
+// Represents the return value of `WebNNContext::CreateTensor()`. Let it be
+// `success` if the tensor was successfully created and `error` otherwise.
+union CreateTensorResult {
+  CreateTensorSuccess success;
   Error error;
 };
 
@@ -36,7 +36,7 @@
   CreateGraphBuilder(pending_associated_receiver<WebNNGraphBuilder> receiver);
 
   // Called by the renderer process to create `WebNNTensor` message pipe for
-  // creating platform specific buffers, the WebNN buffer will be validated and
+  // creating platform specific tensors, the WebNN tensor will be validated and
   // created. This method guarantees memory allocation on the device.
-  CreateBuffer(BufferInfo buffer_info) => (CreateBufferResult result);
+  CreateTensor(TensorInfo tensor_info) => (CreateTensorResult result);
 };
\ No newline at end of file
diff --git a/services/webnn/public/mojom/webnn_tensor.mojom b/services/webnn/public/mojom/webnn_tensor.mojom
index 0238d32..b2df23f 100644
--- a/services/webnn/public/mojom/webnn_tensor.mojom
+++ b/services/webnn/public/mojom/webnn_tensor.mojom
@@ -10,38 +10,38 @@
 
 // A struct is used to represent MLTensorUsageFlags since Mojo does not have
 // the concept of an enum set (see https://crbug.com/40130879#comment11).
-struct BufferUsage {
+struct TensorUsage {
   bool web_gpu_interop;
-  // This buffer can be used with readBuffer().
+  // This tensor can be used with readTensor().
   bool read_from;
-  // This buffer can be used with writeBuffer().
+  // This tensor can be used with writeTensor().
   bool write_to;
 };
 
 // Description of the WebNNTensor to create.
-struct BufferInfo {
+struct TensorInfo {
   OperandDescriptor descriptor;
-  BufferUsage usage;
+  TensorUsage usage;
 };
 
-// Represents the return value of `ReadBuffer()`. Let it be
+// Represents the return value of `ReadTensor()`. Let it be
 // `buffer` if the buffer was successfully read back and `error` otherwise.
-union ReadBufferResult {
+union ReadTensorResult {
   mojo_base.mojom.BigBuffer buffer;
   Error error;
 };
 
 // WebNNTensor creates memory in the GPU process and is used by the renderer
 // process to execute or transfer data for the computational graph.
-// Buffer creation is performed by calling hardware accelerated OS machine
+// Tensor creation is performed by calling hardware accelerated OS machine
 // learning APIs.
 interface WebNNTensor {
   // Called by the renderer process to carryout reading data from a
   // `WebNNTensor`. The result callback contains a copy of the data being
   // read.
-  ReadBuffer() => (ReadBufferResult result);
+  ReadTensor() => (ReadTensorResult result);
 
   // Called by the renderer process to carryout writing to a `WebNNTensor`.
   // The src_buffer is a BigBuffer representing the data to write from.
-  WriteBuffer(mojo_base.mojom.BigBuffer src_buffer);
+  WriteTensor(mojo_base.mojom.BigBuffer src_buffer);
 };
diff --git a/services/webnn/tflite/context_impl_cros.cc b/services/webnn/tflite/context_impl_cros.cc
index 675d313..1ba1115 100644
--- a/services/webnn/tflite/context_impl_cros.cc
+++ b/services/webnn/tflite/context_impl_cros.cc
@@ -100,12 +100,12 @@
                                 std::move(callback));
 }
 
-void ContextImplCrOS::CreateBufferImpl(
+void ContextImplCrOS::CreateTensorImpl(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-    mojom::BufferInfoPtr buffer_info,
-    CreateBufferImplCallback callback) {
+    mojom::TensorInfoPtr tensor_info,
+    CreateTensorImplCallback callback) {
   std::move(callback).Run(TensorImplTflite::Create(std::move(receiver), this,
-                                                   std::move(buffer_info)));
+                                                   std::move(tensor_info)));
 }
 
 }  // namespace webnn::tflite
diff --git a/services/webnn/tflite/context_impl_cros.h b/services/webnn/tflite/context_impl_cros.h
index 4e5bda1..f2489ff3 100644
--- a/services/webnn/tflite/context_impl_cros.h
+++ b/services/webnn/tflite/context_impl_cros.h
@@ -42,10 +42,10 @@
       WebNNGraphImpl::ComputeResourceInfo compute_resource_info,
       CreateGraphImplCallback callback) override;
 
-  void CreateBufferImpl(
+  void CreateTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-      mojom::BufferInfoPtr buffer_info,
-      CreateBufferImplCallback callback) override;
+      mojom::TensorInfoPtr tensor_info,
+      CreateTensorImplCallback callback) override;
 
   // The TFLite model will be loaded in the callback when creating `ModelLoader`
   // interface successfully.
diff --git a/services/webnn/tflite/context_impl_tflite.cc b/services/webnn/tflite/context_impl_tflite.cc
index 2164e49..e612ff0 100644
--- a/services/webnn/tflite/context_impl_tflite.cc
+++ b/services/webnn/tflite/context_impl_tflite.cc
@@ -40,12 +40,12 @@
       std::move(graph_info), std::move(compute_resource_info), this));
 }
 
-void ContextImplTflite::CreateBufferImpl(
+void ContextImplTflite::CreateTensorImpl(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-    mojom::BufferInfoPtr buffer_info,
-    CreateBufferImplCallback callback) {
+    mojom::TensorInfoPtr tensor_info,
+    CreateTensorImplCallback callback) {
   std::move(callback).Run(TensorImplTflite::Create(std::move(receiver), this,
-                                                   std::move(buffer_info)));
+                                                   std::move(tensor_info)));
 }
 
 }  // namespace webnn::tflite
diff --git a/services/webnn/tflite/context_impl_tflite.h b/services/webnn/tflite/context_impl_tflite.h
index ca5078a..72dc529 100644
--- a/services/webnn/tflite/context_impl_tflite.h
+++ b/services/webnn/tflite/context_impl_tflite.h
@@ -33,10 +33,10 @@
       WebNNGraphImpl::ComputeResourceInfo compute_resource_info,
       CreateGraphImplCallback callback) override;
 
-  void CreateBufferImpl(
+  void CreateTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-      mojom::BufferInfoPtr buffer_info,
-      CreateBufferImplCallback callback) override;
+      mojom::TensorInfoPtr tensor_info,
+      CreateTensorImplCallback callback) override;
 
   base::WeakPtrFactory<ContextImplTflite> weak_factory_{this};
 };
diff --git a/services/webnn/tflite/tensor_impl_tflite.cc b/services/webnn/tflite/tensor_impl_tflite.cc
index 78427da..3a96284 100644
--- a/services/webnn/tflite/tensor_impl_tflite.cc
+++ b/services/webnn/tflite/tensor_impl_tflite.cc
@@ -24,8 +24,8 @@
 TensorImplTflite::Create(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
     WebNNContextImpl* context,
-    mojom::BufferInfoPtr buffer_info) {
-  size_t size = buffer_info->descriptor.PackedByteLength();
+    mojom::TensorInfoPtr tensor_info) {
+  size_t size = tensor_info->descriptor.PackedByteLength();
 
   // Limit to INT_MAX for security reasons (similar to PartitionAlloc).
   //
@@ -42,17 +42,17 @@
       base::MakeRefCounted<QueueableResourceState<BufferContent>>(
           std::move(buffer_content));
   return std::make_unique<TensorImplTflite>(
-      std::move(receiver), context, std::move(buffer_info),
+      std::move(receiver), context, std::move(tensor_info),
       std::move(buffer_state), base::PassKey<TensorImplTflite>());
 }
 
 TensorImplTflite::TensorImplTflite(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
     WebNNContextImpl* context,
-    mojom::BufferInfoPtr buffer_info,
+    mojom::TensorInfoPtr tensor_info,
     scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
     base::PassKey<TensorImplTflite>)
-    : WebNNTensorImpl(std::move(receiver), context, std::move(buffer_info)),
+    : WebNNTensorImpl(std::move(receiver), context, std::move(tensor_info)),
       buffer_state_(std::move(buffer_state)) {}
 
 TensorImplTflite::~TensorImplTflite() {
@@ -65,7 +65,7 @@
   return buffer_state_;
 }
 
-void TensorImplTflite::ReadBufferImpl(ReadBufferCallback callback) {
+void TensorImplTflite::ReadTensorImpl(ReadTensorCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Lock the buffer contents as shared/read-only.
   std::vector<scoped_refptr<QueueableResourceStateBase>> shared_resources = {
@@ -78,12 +78,12 @@
       base::BindOnce(
           [](scoped_refptr<QueueableResourceState<BufferContent>>
                  content_handle,
-             ReadBufferCallback callback,
+             ReadTensorCallback callback,
              base::OnceClosure completion_closure) {
             // Memory copies are fast, avoid the overhead of posting a task
             // to the thread pool and do the work synchronously.
             std::move(callback).Run(
-                mojom::ReadBufferResult::NewBuffer(mojo_base::BigBuffer(
+                mojom::ReadTensorResult::NewBuffer(mojo_base::BigBuffer(
                     content_handle->GetSharedLockedResource().AsSpan())));
             std::move(completion_closure).Run();
           },
@@ -91,7 +91,7 @@
   task->Enqueue();
 }
 
-void TensorImplTflite::WriteBufferImpl(mojo_base::BigBuffer src_buffer) {
+void TensorImplTflite::WriteTensorImpl(mojo_base::BigBuffer src_buffer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Take an exclusive lock to the buffer contents while reading.
   std::vector<scoped_refptr<QueueableResourceStateBase>> exclusive_resources = {
diff --git a/services/webnn/tflite/tensor_impl_tflite.h b/services/webnn/tflite/tensor_impl_tflite.h
index fa6cea6..e52e85f7 100644
--- a/services/webnn/tflite/tensor_impl_tflite.h
+++ b/services/webnn/tflite/tensor_impl_tflite.h
@@ -28,12 +28,12 @@
   static base::expected<std::unique_ptr<WebNNTensorImpl>, mojom::ErrorPtr>
   Create(mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
          WebNNContextImpl* context,
-         mojom::BufferInfoPtr buffer_info);
+         mojom::TensorInfoPtr tensor_info);
 
   TensorImplTflite(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
       WebNNContextImpl* context,
-      mojom::BufferInfoPtr buffer_info,
+      mojom::TensorInfoPtr tensor_info,
       scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
       base::PassKey<TensorImplTflite>);
 
@@ -46,8 +46,8 @@
       const;
 
  private:
-  void ReadBufferImpl(ReadBufferCallback callback) override;
-  void WriteBufferImpl(mojo_base::BigBuffer src_buffer) override;
+  void ReadTensorImpl(ReadTensorCallback callback) override;
+  void WriteTensorImpl(mojo_base::BigBuffer src_buffer) override;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/services/webnn/webnn_context_impl.cc b/services/webnn/webnn_context_impl.cc
index 6f372ad7..fbe6623 100644
--- a/services/webnn/webnn_context_impl.cc
+++ b/services/webnn/webnn_context_impl.cc
@@ -80,38 +80,38 @@
   graph_builder_ptr->SetId(id, base::PassKey<WebNNContextImpl>());
 }
 
-void WebNNContextImpl::CreateBuffer(
-    mojom::BufferInfoPtr buffer_info,
-    mojom::WebNNContext::CreateBufferCallback callback) {
+void WebNNContextImpl::CreateTensor(
+    mojom::TensorInfoPtr tensor_info,
+    mojom::WebNNContext::CreateTensorCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (!ValidateBuffer(properties_, buffer_info->descriptor).has_value()) {
+  if (!ValidateBuffer(properties_, tensor_info->descriptor).has_value()) {
     receiver_.ReportBadMessage(kBadMessageInvalidBuffer);
     return;
   }
 
   mojo::PendingAssociatedRemote<mojom::WebNNTensor> remote;
   auto receiver = remote.InitWithNewEndpointAndPassReceiver();
-  CreateBufferImpl(
-      std::move(receiver), std::move(buffer_info),
+  CreateTensorImpl(
+      std::move(receiver), std::move(tensor_info),
       base::BindOnce(&WebNNContextImpl::DidCreateWebNNTensorImpl, AsWeakPtr(),
                      std::move(callback), std::move(remote)));
 }
 
 void WebNNContextImpl::DidCreateWebNNTensorImpl(
-    mojom::WebNNContext::CreateBufferCallback callback,
+    mojom::WebNNContext::CreateTensorCallback callback,
     mojo::PendingAssociatedRemote<mojom::WebNNTensor> remote,
     base::expected<std::unique_ptr<WebNNTensorImpl>, mojom::ErrorPtr> result) {
   if (!result.has_value()) {
     std::move(callback).Run(
-        mojom::CreateBufferResult::NewError(std::move(result.error())));
+        mojom::CreateTensorResult::NewError(std::move(result.error())));
     return;
   }
 
-  auto success = mojom::CreateBufferSuccess::New(std::move(remote),
+  auto success = mojom::CreateTensorSuccess::New(std::move(remote),
                                                  result.value()->handle());
   std::move(callback).Run(
-      mojom::CreateBufferResult::NewSuccess(std::move(success)));
+      mojom::CreateTensorResult::NewSuccess(std::move(success)));
 
   // Associates a `WebNNTensor` instance with this context so the WebNN service
   // can access the implementation.
@@ -133,8 +133,8 @@
 }
 
 base::optional_ref<WebNNTensorImpl> WebNNContextImpl::GetWebNNTensorImpl(
-    const blink::WebNNTensorToken& buffer_handle) {
-  const auto it = buffer_impls_.find(buffer_handle);
+    const blink::WebNNTensorToken& tensor_handle) {
+  const auto it = buffer_impls_.find(tensor_handle);
   if (it == buffer_impls_.end()) {
     receiver_.ReportBadMessage(kBadMessageInvalidBuffer);
     return std::nullopt;
diff --git a/services/webnn/webnn_context_impl.h b/services/webnn/webnn_context_impl.h
index c95dfcd0..d29f0d0 100644
--- a/services/webnn/webnn_context_impl.h
+++ b/services/webnn/webnn_context_impl.h
@@ -45,7 +45,7 @@
   using CreateGraphImplCallback = base::OnceCallback<void(
       base::expected<std::unique_ptr<WebNNGraphImpl>, mojom::ErrorPtr>)>;
 
-  using CreateBufferImplCallback = base::OnceCallback<void(
+  using CreateTensorImplCallback = base::OnceCallback<void(
       base::expected<std::unique_ptr<WebNNTensorImpl>, mojom::ErrorPtr>)>;
 
   WebNNContextImpl(mojo::PendingReceiver<mojom::WebNNContext> receiver,
@@ -124,19 +124,19 @@
   void CreateGraphBuilder(
       mojo::PendingAssociatedReceiver<mojom::WebNNGraphBuilder> receiver)
       override;
-  void CreateBuffer(mojom::BufferInfoPtr buffer_info,
-                    CreateBufferCallback callback) override;
+  void CreateTensor(mojom::TensorInfoPtr tensor_info,
+                    CreateTensorCallback callback) override;
 
-  // This method will be called by `CreateBuffer()` after the buffer info is
+  // This method will be called by `CreateTensor()` after the buffer info is
   // validated. A backend subclass should implement this method to create and
   // initialize a platform specific buffer asynchronously.
-  virtual void CreateBufferImpl(
+  virtual void CreateTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-      mojom::BufferInfoPtr buffer_info,
-      CreateBufferImplCallback callback) = 0;
+      mojom::TensorInfoPtr tensor_info,
+      CreateTensorImplCallback callback) = 0;
 
   void DidCreateWebNNTensorImpl(
-      CreateBufferCallback callback,
+      CreateTensorCallback callback,
       mojo::PendingAssociatedRemote<mojom::WebNNTensor> remote,
       base::expected<std::unique_ptr<WebNNTensorImpl>, mojom::ErrorPtr> result);
 
diff --git a/services/webnn/webnn_graph_builder_impl_unittest.cc b/services/webnn/webnn_graph_builder_impl_unittest.cc
index be9c837..5bec859a 100644
--- a/services/webnn/webnn_graph_builder_impl_unittest.cc
+++ b/services/webnn/webnn_graph_builder_impl_unittest.cc
@@ -104,10 +104,10 @@
             std::move(callback)));
   }
 
-  void CreateBufferImpl(
+  void CreateTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-      mojom::BufferInfoPtr buffer_info,
-      CreateBufferImplCallback callback) override {
+      mojom::TensorInfoPtr tensor_info,
+      CreateTensorImplCallback callback) override {
     NOTIMPLEMENTED();
   }
 
diff --git a/services/webnn/webnn_graph_impl.cc b/services/webnn/webnn_graph_impl.cc
index 20a5a8e7..0b161ffa 100644
--- a/services/webnn/webnn_graph_impl.cc
+++ b/services/webnn/webnn_graph_impl.cc
@@ -160,9 +160,9 @@
   std::vector<std::pair<std::string_view, WebNNTensorImpl*>>
       name_to_input_buffers;
   name_to_input_buffers.reserve(named_inputs.size());
-  for (const auto& [name, buffer_handle] : named_inputs) {
+  for (const auto& [name, tensor_handle] : named_inputs) {
     base::optional_ref<WebNNTensorImpl> input_buffer =
-        context_->GetWebNNTensorImpl(buffer_handle);
+        context_->GetWebNNTensorImpl(tensor_handle);
     if (!input_buffer.has_value()) {
       return;
     }
@@ -182,9 +182,9 @@
   std::vector<std::pair<std::string_view, WebNNTensorImpl*>>
       name_to_output_buffers;
   name_to_output_buffers.reserve(named_outputs.size());
-  for (const auto& [name, buffer_handle] : named_outputs) {
+  for (const auto& [name, tensor_handle] : named_outputs) {
     base::optional_ref<WebNNTensorImpl> output_buffer =
-        context_->GetWebNNTensorImpl(buffer_handle);
+        context_->GetWebNNTensorImpl(tensor_handle);
     if (!output_buffer.has_value()) {
       return;
     }
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc
index 109cd78..d1a0773 100644
--- a/services/webnn/webnn_graph_impl_unittest.cc
+++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -87,15 +87,15 @@
   FakeWebNNTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
       WebNNContextImpl* context,
-      mojom::BufferInfoPtr buffer_info)
-      : WebNNTensorImpl(std::move(receiver), context, std::move(buffer_info)) {}
+      mojom::TensorInfoPtr tensor_info)
+      : WebNNTensorImpl(std::move(receiver), context, std::move(tensor_info)) {}
   ~FakeWebNNTensorImpl() override = default;
 
  private:
   // Read/write nothing for testing the validation of inputs and outputs in
   // `WebNNGraphImpl::Dispatch()` function.
-  void ReadBufferImpl(ReadBufferCallback callback) override {}
-  void WriteBufferImpl(mojo_base::BigBuffer src_buffer) override {}
+  void ReadTensorImpl(ReadTensorCallback callback) override {}
+  void WriteTensorImpl(mojo_base::BigBuffer src_buffer) override {}
 };
 
 // A fake WebNNContext Mojo interface implementation that binds a pipe for
@@ -126,12 +126,12 @@
                                        std::move(callback));
   }
 
-  void CreateBufferImpl(
+  void CreateTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
-      mojom::BufferInfoPtr buffer_info,
-      CreateBufferImplCallback callback) override {
+      mojom::TensorInfoPtr tensor_info,
+      CreateTensorImplCallback callback) override {
     std::move(callback).Run(std::make_unique<FakeWebNNTensorImpl>(
-        std::move(receiver), this, std::move(buffer_info)));
+        std::move(receiver), this, std::move(tensor_info)));
   }
 
   base::WeakPtrFactory<FakeWebNNContextImpl> weak_factory_{this};
@@ -209,28 +209,28 @@
   return valid;
 }
 
-struct CreateBufferSuccess {
+struct CreateTensorSuccess {
   std::optional<mojo::AssociatedRemote<mojom::WebNNTensor>> webnn_buffer;
   blink::WebNNTensorToken webnn_handle;
 };
 
-CreateBufferSuccess CreateWebNNTensor(
+CreateTensorSuccess CreateWebNNTensor(
     mojo::Remote<mojom::WebNNContext>& webnn_context,
     OperandDataType data_type,
     std::vector<uint32_t> shape) {
-  base::test::TestFuture<mojom::CreateBufferResultPtr> create_buffer_future;
-  webnn_context->CreateBuffer(
-      mojom::BufferInfo::New(*OperandDescriptor::Create(data_type, shape),
+  base::test::TestFuture<mojom::CreateTensorResultPtr> create_buffer_future;
+  webnn_context->CreateTensor(
+      mojom::TensorInfo::New(*OperandDescriptor::Create(data_type, shape),
                              MLTensorUsage()),
       create_buffer_future.GetCallback());
-  mojom::CreateBufferResultPtr create_buffer_result =
+  mojom::CreateTensorResultPtr create_buffer_result =
       create_buffer_future.Take();
   mojo::AssociatedRemote<mojom::WebNNTensor> webnn_buffer;
   webnn_buffer.Bind(
-      std::move(create_buffer_result->get_success()->buffer_remote));
-  return CreateBufferSuccess{
+      std::move(create_buffer_result->get_success()->tensor_remote));
+  return CreateTensorSuccess{
       std::move(webnn_buffer),
-      std::move(create_buffer_result->get_success()->buffer_handle)};
+      std::move(create_buffer_result->get_success()->tensor_handle)};
 }
 
 mojo::Remote<mojom::WebNNContext> CreateWebNNContext(
@@ -250,8 +250,8 @@
 bool ValidateDispatch(
     mojo::Remote<mojom::WebNNContext>& webnn_context,
     mojom::GraphInfoPtr graph_info,
-    base::flat_map<std::string, CreateBufferSuccess> inputs,
-    base::flat_map<std::string, CreateBufferSuccess> outputs) {
+    base::flat_map<std::string, CreateTensorSuccess> inputs,
+    base::flat_map<std::string, CreateTensorSuccess> outputs) {
   mojo::AssociatedRemote<mojom::WebNNGraphBuilder> graph_builder_remote;
   webnn_context->CreateGraphBuilder(
       graph_builder_remote.BindNewEndpointAndPassReceiver());
@@ -276,17 +276,17 @@
 
   // Assign buffers for the inputs.
   base::flat_map<std::string, blink::WebNNTensorToken> dispatch_inputs;
-  for (const auto& [name, buffer_info] : inputs) {
-    dispatch_inputs.emplace(name, buffer_info.webnn_handle);
+  for (const auto& [name, tensor_info] : inputs) {
+    dispatch_inputs.emplace(name, tensor_info.webnn_handle);
   }
 
   // Assign buffers for the outputs.
   base::flat_map<std::string, blink::WebNNTensorToken> dispatch_outputs;
-  for (const auto& [name, buffer_info] : outputs) {
-    dispatch_outputs.emplace(name, buffer_info.webnn_handle);
+  for (const auto& [name, tensor_info] : outputs) {
+    dispatch_outputs.emplace(name, tensor_info.webnn_handle);
   }
 
-  // Ensure CreateBuffer messages have a chance to finish before calling
+  // Ensure CreateTensor messages have a chance to finish before calling
   // Dispatch().
   webnn_context.FlushForTesting();
   webnn_graph->Dispatch(dispatch_inputs, dispatch_outputs);
@@ -6986,10 +6986,10 @@
     // Validate the inputs match the expected.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_TRUE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -6999,9 +6999,9 @@
     // Test the invalid inputs for invalid input size.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7011,10 +7011,10 @@
     // Test the invalid outputs for invalid output size.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["a_different_output_name"] =
@@ -7026,11 +7026,11 @@
     // Test the invalid inputs for invalid input name.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["a_different_input_name"] =
         CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7040,10 +7040,10 @@
     // Test the invalid outputs for invalid input name.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["a_different_output_name"] =
         CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
@@ -7054,10 +7054,10 @@
     // Test the invalid inputs for invalid first input shape.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, {2, 5});
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7067,11 +7067,11 @@
     // Test the invalid inputs for invalid first input data type.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] =
         CreateWebNNTensor(webnn_context, OperandDataType::kInt8, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7081,10 +7081,10 @@
     // Test the invalid outputs for invalid first output shape.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, {3, 4});
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7094,11 +7094,11 @@
     // Test the invalid inputs for invalid second input data type.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] =
         CreateWebNNTensor(webnn_context, OperandDataType::kInt32, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7108,10 +7108,10 @@
     // Test the invalid outputs for invalid second output shape.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, {2, 5});
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7121,10 +7121,10 @@
     // Test the inputs using the same buffer more than once.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = {/*webnn_buffer=*/std::nullopt, inputs["lhs"].webnn_handle};
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_TRUE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7134,10 +7134,10 @@
     // Test the invalid outputs when using the same buffer more than once.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = {/*webnn_buffer=*/std::nullopt,
                           outputs["output1"].webnn_handle};
@@ -7148,10 +7148,10 @@
     // Test the inputs and outputs are invalid when using the same buffer.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = {/*webnn_buffer=*/std::nullopt,
                           inputs["lhs"].webnn_handle};
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
@@ -7162,10 +7162,10 @@
     // Test the inputs are invalid when using a invalid buffer.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = {/*webnn_buffer=*/std::nullopt};
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
@@ -7175,10 +7175,10 @@
     // Test the outputs are invalid when using a invalid buffer.
     mojo::Remote<mojom::WebNNContext> webnn_context =
         CreateWebNNContext(provider_remote);
-    base::flat_map<std::string, CreateBufferSuccess> inputs;
+    base::flat_map<std::string, CreateTensorSuccess> inputs;
     inputs["lhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     inputs["rhs"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
-    base::flat_map<std::string, CreateBufferSuccess> outputs;
+    base::flat_map<std::string, CreateTensorSuccess> outputs;
     outputs["output1"] = CreateWebNNTensor(webnn_context, kDataType, kShape);
     outputs["output2"] = {/*webnn_buffer=*/std::nullopt};
     EXPECT_FALSE(ValidateDispatch(webnn_context, builder.CloneGraphInfo(),
diff --git a/services/webnn/webnn_tensor_impl.cc b/services/webnn/webnn_tensor_impl.cc
index 9da37b6..8337912 100644
--- a/services/webnn/webnn_tensor_impl.cc
+++ b/services/webnn/webnn_tensor_impl.cc
@@ -14,10 +14,10 @@
 WebNNTensorImpl::WebNNTensorImpl(
     mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
     WebNNContextImpl* context,
-    mojom::BufferInfoPtr buffer_info)
+    mojom::TensorInfoPtr tensor_info)
     : context_(context),
-      descriptor_(std::move(buffer_info->descriptor)),
-      usage_(std::move(buffer_info->usage)),
+      descriptor_(std::move(tensor_info->descriptor)),
+      usage_(std::move(tensor_info->usage)),
       receiver_(this, std::move(receiver)) {
   // Safe to use base::Unretained because `this` owns `receiver_`.
   receiver_.set_disconnect_handler(
@@ -26,17 +26,17 @@
 
 WebNNTensorImpl::~WebNNTensorImpl() = default;
 
-void WebNNTensorImpl::ReadBuffer(ReadBufferCallback callback) {
+void WebNNTensorImpl::ReadTensor(ReadTensorCallback callback) {
   if (!usage().Has(MLTensorUsageFlags::kReadFrom)) {
     receiver_.ReportBadMessage(kBadMessageInvalidBuffer);
     return;
   }
 
-  // Call ReadBufferImpl() implemented by a backend.
-  ReadBufferImpl(std::move(callback));
+  // Call ReadTensorImpl() implemented by a backend.
+  ReadTensorImpl(std::move(callback));
 }
 
-void WebNNTensorImpl::WriteBuffer(mojo_base::BigBuffer src_buffer) {
+void WebNNTensorImpl::WriteTensor(mojo_base::BigBuffer src_buffer) {
   if (!usage().Has(MLTensorUsageFlags::kWriteTo)) {
     receiver_.ReportBadMessage(kBadMessageInvalidBuffer);
     return;
@@ -48,8 +48,8 @@
     return;
   }
 
-  // Call WriteBufferImpl() implemented by a backend.
-  WriteBufferImpl(std::move(src_buffer));
+  // Call WriteTensorImpl() implemented by a backend.
+  WriteTensorImpl(std::move(src_buffer));
 }
 
 void WebNNTensorImpl::OnDisconnect() {
diff --git a/services/webnn/webnn_tensor_impl.h b/services/webnn/webnn_tensor_impl.h
index fbd2268..aa51618 100644
--- a/services/webnn/webnn_tensor_impl.h
+++ b/services/webnn/webnn_tensor_impl.h
@@ -26,7 +26,7 @@
   explicit WebNNTensorImpl(
       mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver,
       WebNNContextImpl* context,
-      mojom::BufferInfoPtr buffer_info);
+      mojom::TensorInfoPtr tensor_info);
   ~WebNNTensorImpl() override;
 
   WebNNTensorImpl(const WebNNTensorImpl&) = delete;
@@ -44,24 +44,24 @@
   }
 
  protected:
-  // This method will be called by `ReadBuffer()` after the read info is
+  // This method will be called by `ReadTensor()` after the read info is
   // validated. A backend subclass should implement this method to read data
   // from a platform specific buffer.
-  virtual void ReadBufferImpl(
-      mojom::WebNNTensor::ReadBufferCallback callback) = 0;
+  virtual void ReadTensorImpl(
+      mojom::WebNNTensor::ReadTensorCallback callback) = 0;
 
-  // This method will be called by `WriteBuffer()` after the write info is
+  // This method will be called by `WriteTensor()` after the write info is
   // validated. A backend subclass should implement this method to write data
   // to a platform specific buffer.
-  virtual void WriteBufferImpl(mojo_base::BigBuffer src_buffer) = 0;
+  virtual void WriteTensorImpl(mojo_base::BigBuffer src_buffer) = 0;
 
   // WebNNContextImpl owns this object.
   const raw_ptr<WebNNContextImpl> context_;
 
  private:
   // mojom::WebNNTensor
-  void ReadBuffer(ReadBufferCallback callback) override;
-  void WriteBuffer(mojo_base::BigBuffer src_buffer) override;
+  void ReadTensor(ReadTensorCallback callback) override;
+  void WriteTensor(mojo_base::BigBuffer src_buffer) override;
 
   // `OnDisconnect` is called from two places.
   //  - When the buffer is explicitly destroyed by the WebNN
diff --git a/services/webnn/webnn_tensor_impl_backend_test.cc b/services/webnn/webnn_tensor_impl_backend_test.cc
index 9e3124dc..a654882e 100644
--- a/services/webnn/webnn_tensor_impl_backend_test.cc
+++ b/services/webnn/webnn_tensor_impl_backend_test.cc
@@ -73,9 +73,9 @@
   blink::WebNNContextToken webnn_context_handle;
 };
 
-struct CreateBufferSuccess {
-  mojo::AssociatedRemote<mojom::WebNNTensor> webnn_buffer_remote;
-  blink::WebNNTensorToken webnn_buffer_handle;
+struct CreateTensorSuccess {
+  mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote;
+  blink::WebNNTensorToken webnn_tensor_handle;
 };
 
 #if BUILDFLAG(IS_WIN)
@@ -203,21 +203,21 @@
   }
 }
 
-base::expected<CreateBufferSuccess, webnn::mojom::Error::Code>
+base::expected<CreateTensorSuccess, webnn::mojom::Error::Code>
 CreateWebNNTensor(mojo::Remote<mojom::WebNNContext>& webnn_context_remote,
-                  mojom::BufferInfoPtr buffer_info) {
-  base::test::TestFuture<mojom::CreateBufferResultPtr> create_buffer_future;
-  webnn_context_remote->CreateBuffer(std::move(buffer_info),
+                  mojom::TensorInfoPtr tensor_info) {
+  base::test::TestFuture<mojom::CreateTensorResultPtr> create_buffer_future;
+  webnn_context_remote->CreateTensor(std::move(tensor_info),
                                      create_buffer_future.GetCallback());
-  mojom::CreateBufferResultPtr create_buffer_result =
+  mojom::CreateTensorResultPtr create_buffer_result =
       create_buffer_future.Take();
   if (create_buffer_result->is_success()) {
-    mojo::AssociatedRemote<mojom::WebNNTensor> webnn_buffer_remote;
-    webnn_buffer_remote.Bind(
-        std::move(create_buffer_result->get_success()->buffer_remote));
-    return CreateBufferSuccess{
-        std::move(webnn_buffer_remote),
-        std::move(create_buffer_result->get_success()->buffer_handle)};
+    mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote;
+    webnn_tensor_remote.Bind(
+        std::move(create_buffer_result->get_success()->tensor_remote));
+    return CreateTensorSuccess{
+        std::move(webnn_tensor_remote),
+        std::move(create_buffer_result->get_success()->tensor_handle)};
   } else {
     return base::unexpected(create_buffer_result->get_error()->code);
   }
@@ -228,7 +228,7 @@
   return base::span(a) == base::span(b);
 }
 
-TEST_F(WebNNTensorImplBackendTest, CreateBufferImplTest) {
+TEST_F(WebNNTensorImplBackendTest, CreateTensorImplTest) {
   BadMessageTestHelper bad_message_helper;
 
   mojo::Remote<mojom::WebNNContext> webnn_context_remote;
@@ -246,7 +246,7 @@
 
   EXPECT_TRUE(CreateWebNNTensor(
                   webnn_context_remote,
-                  mojom::BufferInfo::New(
+                  mojom::TensorInfo::New(
                       *OperandDescriptor::Create(OperandDataType::kFloat32,
                                                  std::array<uint32_t, 2>{3, 4}),
                       MLTensorUsage()))
@@ -258,7 +258,7 @@
 
 // Creating two or more WebNNTensor(s) with separate tokens should always
 // succeed.
-TEST_F(WebNNTensorImplBackendTest, CreateBufferImplManyTest) {
+TEST_F(WebNNTensorImplBackendTest, CreateTensorImplManyTest) {
   BadMessageTestHelper bad_message_helper;
 
   mojo::Remote<mojom::WebNNContext> webnn_context_remote;
@@ -272,15 +272,15 @@
         std::move(context_result.value().webnn_context_remote);
   }
 
-  const auto buffer_info = mojom::BufferInfo::New(
+  const auto tensor_info = mojom::TensorInfo::New(
       *OperandDescriptor::Create(OperandDataType::kInt32,
                                  std::array<uint32_t, 2>{4, 3}),
       MLTensorUsage());
 
-  EXPECT_TRUE(CreateWebNNTensor(webnn_context_remote, buffer_info->Clone())
+  EXPECT_TRUE(CreateWebNNTensor(webnn_context_remote, tensor_info->Clone())
                   .has_value());
 
-  EXPECT_TRUE(CreateWebNNTensor(webnn_context_remote, buffer_info->Clone())
+  EXPECT_TRUE(CreateWebNNTensor(webnn_context_remote, tensor_info->Clone())
                   .has_value());
 
   webnn_context_remote.FlushForTesting();
@@ -289,7 +289,7 @@
 
 // TODO(https://crbug.com/40278771): Test the buffer gets destroyed.
 
-TEST_F(WebNNTensorImplBackendTest, WriteBufferImplTest) {
+TEST_F(WebNNTensorImplBackendTest, WriteTensorImplTest) {
   BadMessageTestHelper bad_message_helper;
 
   mojo::Remote<mojom::WebNNContext> webnn_context_remote;
@@ -303,37 +303,37 @@
         std::move(context_result.value().webnn_context_remote);
   }
 
-  mojo::AssociatedRemote<mojom::WebNNTensor> webnn_buffer_remote;
-  base::expected<CreateBufferSuccess, webnn::mojom::Error::Code> buffer_result =
+  mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote;
+  base::expected<CreateTensorSuccess, webnn::mojom::Error::Code> buffer_result =
       CreateWebNNTensor(
           webnn_context_remote,
-          mojom::BufferInfo::New(
+          mojom::TensorInfo::New(
               *OperandDescriptor::Create(OperandDataType::kUint8,
                                          std::array<uint32_t, 2>{2, 2}),
               MLTensorUsage{MLTensorUsageFlags::kWriteTo,
                             MLTensorUsageFlags::kReadFrom}));
   if (buffer_result.has_value()) {
-    webnn_buffer_remote = std::move(buffer_result.value().webnn_buffer_remote);
+    webnn_tensor_remote = std::move(buffer_result.value().webnn_tensor_remote);
   }
 
-  EXPECT_TRUE(webnn_buffer_remote.is_bound());
+  EXPECT_TRUE(webnn_tensor_remote.is_bound());
 
   const std::array<const uint8_t, 4> input_data{0xAA, 0xAA, 0xAA, 0xAA};
-  webnn_buffer_remote->WriteBuffer(mojo_base::BigBuffer(input_data));
+  webnn_tensor_remote->WriteTensor(mojo_base::BigBuffer(input_data));
 
   webnn_context_remote.FlushForTesting();
   EXPECT_FALSE(bad_message_helper.GetLastBadMessage().has_value());
 
-  base::test::TestFuture<mojom::ReadBufferResultPtr> future;
-  webnn_buffer_remote->ReadBuffer(future.GetCallback());
-  mojom::ReadBufferResultPtr result = future.Take();
+  base::test::TestFuture<mojom::ReadTensorResultPtr> future;
+  webnn_tensor_remote->ReadTensor(future.GetCallback());
+  mojom::ReadTensorResultPtr result = future.Take();
   ASSERT_FALSE(result->is_error());
   EXPECT_TRUE(IsBufferDataEqual(mojo_base::BigBuffer(input_data),
                                 std::move(result->get_buffer())));
 }
 
 // Test writing to a WebNNTensor smaller than the data being written fails.
-TEST_F(WebNNTensorImplBackendTest, WriteBufferImplTooLargeTest) {
+TEST_F(WebNNTensorImplBackendTest, WriteTensorImplTooLargeTest) {
   BadMessageTestHelper bad_message_helper;
 
   mojo::Remote<mojom::WebNNContext> webnn_context_remote;
@@ -347,21 +347,21 @@
         std::move(context_result.value().webnn_context_remote);
   }
 
-  mojo::AssociatedRemote<mojom::WebNNTensor> webnn_buffer_remote;
-  base::expected<CreateBufferSuccess, webnn::mojom::Error::Code> buffer_result =
+  mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote;
+  base::expected<CreateTensorSuccess, webnn::mojom::Error::Code> buffer_result =
       CreateWebNNTensor(
           webnn_context_remote,
-          mojom::BufferInfo::New(
+          mojom::TensorInfo::New(
               *OperandDescriptor::Create(OperandDataType::kUint8,
                                          std::array<uint32_t, 2>{2, 2}),
               MLTensorUsage{MLTensorUsageFlags::kWriteTo}));
   if (buffer_result.has_value()) {
-    webnn_buffer_remote = std::move(buffer_result.value().webnn_buffer_remote);
+    webnn_tensor_remote = std::move(buffer_result.value().webnn_tensor_remote);
   }
 
-  EXPECT_TRUE(webnn_buffer_remote.is_bound());
+  EXPECT_TRUE(webnn_tensor_remote.is_bound());
 
-  webnn_buffer_remote->WriteBuffer(mojo_base::BigBuffer(
+  webnn_tensor_remote->WriteTensor(mojo_base::BigBuffer(
       std::array<const uint8_t, 5>({0xBB, 0xBB, 0xBB, 0xBB, 0xBB})));
 
   webnn_context_remote.FlushForTesting();
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json
index 1c5bdae..ba46711 100644
--- a/testing/buildbot/chromium.dawn.json
+++ b/testing/buildbot/chromium.dawn.json
@@ -6418,6 +6418,35 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "arm64",
+            "display_attached": "1",
+            "gpu": "apple:m2",
+            "hidpi": "1",
+            "mac_model": "Mac14,7",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
@@ -7147,6 +7176,35 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "arm64",
+            "display_attached": "1",
+            "gpu": "apple:m2",
+            "hidpi": "1",
+            "mac_model": "Mac14,7",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
@@ -7837,6 +7895,34 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:67ef",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
@@ -8073,6 +8159,85 @@
       },
       {
         "args": [
+          "webgpu_cts",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--jobs=4",
+          "--use-webgpu-power-preference=default-high-performance"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgpu_cts_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:67ef",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 14
+        },
+        "test": "telemetry_gpu_integration_test",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgpu_cts",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--enable-dawn-backend-validation",
+          "--jobs=4",
+          "--use-webgpu-power-preference=default-high-performance"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgpu_cts_with_validation_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:67ef",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 14
+        },
+        "test": "telemetry_gpu_integration_test",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
           "--flag-specific=webgpu-swiftshader",
           "--initialize-webgpu-adapter-at-startup-timeout-ms=60000",
           "--platform=mac-mac11"
@@ -8306,6 +8471,32 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "8086:3e9b",
+            "os": "Mac-14.5"
+          },
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
@@ -8835,6 +9026,35 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:7340",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "expiration": 21600,
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
@@ -9079,6 +9299,87 @@
       },
       {
         "args": [
+          "webgpu_cts",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--jobs=4",
+          "--use-webgpu-power-preference=default-high-performance"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgpu_cts_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:7340",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "expiration": 21600,
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 14
+        },
+        "test": "telemetry_gpu_integration_test",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgpu_cts",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--enable-dawn-backend-validation",
+          "--jobs=4",
+          "--use-webgpu-power-preference=default-high-performance"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgpu_cts_with_validation_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:7340",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "expiration": 21600,
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 14
+        },
+        "test": "telemetry_gpu_integration_test",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
           "--flag-specific=webgpu-swiftshader",
           "--initialize-webgpu-adapter-at-startup-timeout-ms=60000",
           "--platform=mac-mac11"
@@ -9319,6 +9620,33 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "8086:3e9b",
+            "os": "Mac-15.0"
+          },
+          "expiration": 21600,
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
@@ -9859,6 +10187,34 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:67ef",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
@@ -10095,6 +10451,85 @@
       },
       {
         "args": [
+          "webgpu_cts",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--jobs=4",
+          "--use-webgpu-power-preference=default-high-performance"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgpu_cts_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:67ef",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 14
+        },
+        "test": "telemetry_gpu_integration_test",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgpu_cts",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--enable-dawn-backend-validation",
+          "--jobs=4",
+          "--use-webgpu-power-preference=default-high-performance"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgpu_cts_with_validation_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "1002:67ef",
+            "hidpi": "1",
+            "os": "Mac-14.4.1",
+            "pool": "chromium.tests.gpu"
+          },
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 14
+        },
+        "test": "telemetry_gpu_integration_test",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
           "--flag-specific=webgpu-swiftshader",
           "--initialize-webgpu-adapter-at-startup-timeout-ms=60000",
           "--platform=mac-mac11"
@@ -10328,6 +10763,32 @@
       },
       {
         "args": [
+          "--enable-toggles=use_tint_ir",
+          "--use-gpu-in-tests",
+          "--exclusive-device-type-preference=discrete,integrated",
+          "--test-launcher-retry-limit=0",
+          "--test-launcher-batch-limit=512"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_use_tint_ir_tests",
+        "swarming": {
+          "dimensions": {
+            "cpu": "x86-64",
+            "display_attached": "1",
+            "gpu": "8086:3e9b",
+            "os": "Mac-14.5"
+          },
+          "hard_timeout": 1800,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/dawn/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
           "--enable-backend-validation",
           "--use-gpu-in-tests",
           "--exclusive-device-type-preference=discrete,integrated",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 7c9ec849..b486a06 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -5000,12 +5000,6 @@
     ],
   },
   'webgpu_cts_tests': {
-    'remove_from': [
-      # Tests kill Swarming on Mac AMD machines crbug.com/365027668
-      'Dawn Mac x64 DEPS Release (AMD)',
-      'Dawn Mac x64 Experimental Release (AMD)',
-      'Dawn Mac x64 Release (AMD)',
-    ],
     'modifications': {
       'Dawn Android arm DEPS Release (Pixel 4)': {
         'ci_only': True,
@@ -5061,10 +5055,6 @@
   },
   'webgpu_cts_with_validation_tests': {
     'remove_from': [
-      # Tests kill Swarming on Mac AMD machines crbug.com/365027668
-      'Dawn Mac x64 DEPS Release (AMD)',
-      'Dawn Mac x64 Experimental Release (AMD)',
-      'Dawn Mac x64 Release (AMD)',
       # Remove from bots where capacity is constrained.
       'Dawn Win10 x64 DEPS Release (Intel)',
       'Dawn Win10 x64 Experimental Release (Intel)',
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index 7d877e2..935820d 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -78,6 +78,12 @@
       "ui/webui/resources/.*(css|html|js)"
     ]
   },
+  "dawn_chromium_presubmit": {
+    "exclusions": [
+      "third_party/dawn/webgpu-cts/compat-expectations.txt",
+      "third_party/dawn/webgpu-cts/expectations.txt"
+    ]
+  },
   "fuchsia": {
     "exclusions": [
       "build/fuchsia/.*py"
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 08671507..cfafce2 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2236,7 +2236,7 @@
         ],
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
@@ -2262,7 +2262,7 @@
         ],
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
@@ -2276,7 +2276,7 @@
         ],
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
@@ -2288,7 +2288,7 @@
         ],
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
@@ -2304,7 +2304,7 @@
         # should have the same test_suites as 'Dawn Mac x64 Release (AMD)'.
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
@@ -2320,7 +2320,7 @@
         # should have the same test_suites as 'Dawn Mac x64 Release (Intel)'.
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
@@ -2332,7 +2332,7 @@
         ],
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
@@ -2348,7 +2348,7 @@
         ],
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_dawn_telemetry_tests',
-          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough_macos',
           'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index ad8fb03..31945fb 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -9701,25 +9701,6 @@
             ]
         }
     ],
-    "ExtensionSafetyHubNoPrivacyPracticesTrigger": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SafetyHubExtensionsNoPrivacyPracticesTrigger"
-                    ]
-                }
-            ]
-        }
-    ],
     "ExtensionsServiceWorkerOptimizedEventDispatch": [
         {
             "platforms": [
@@ -12161,6 +12142,21 @@
             ]
         }
     ],
+    "IOSSegmentationPlatformEphemeralCardRanker": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "SegmentationPlatformEphemeralCardRanker"
+                    ]
+                }
+            ]
+        }
+    ],
     "IOSSharedHighlightingColorChange": [
         {
             "platforms": [
@@ -12447,25 +12443,6 @@
             ]
         }
     ],
-    "IncludeJSCallStackInExtensionApiRequestStudy": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "IncludeJSCallStackInExtensionApiRequest"
-                    ]
-                }
-            ]
-        }
-    ],
     "IncognitoReauthenticationForAndroid": [
         {
             "platforms": [
@@ -19238,36 +19215,6 @@
             ]
         }
     ],
-    "ReadAnythingReadAloudRollout": [
-        {
-            "platforms": [
-                "chromeos"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ReadAnythingReadAloud"
-                    ]
-                },
-                {
-                    "name": "LanguageDownloads_Enabled",
-                    "enable_features": [
-                        "ReadAloudLanguagePackDownloading",
-                        "ReadAnythingReadAloud"
-                    ]
-                },
-                {
-                    "name": "LanguageDownloadsAndVoiceSwitching_Enabled",
-                    "enable_features": [
-                        "ReadAloudAutoVoiceSwitching",
-                        "ReadAloudLanguagePackDownloading",
-                        "ReadAnythingReadAloud"
-                    ]
-                }
-            ]
-        }
-    ],
     "ReadAnythingReadAloudWordHighlighting": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index 67b3149..53476d6 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 67b3149f2cf0fe38cbdd7bf1c7b2ab8e7d95ebea
+Subproject commit 53476d6ff2740267db0c0573644378621c4e7d78
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index b2448d2..65d975b0 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -619,10 +619,12 @@
     {TaskDeferralPolicy::kAllTypes,
      kDeferRendererTasksAfterInputAllTypesPolicyName}};
 
-const base::FeatureParam<TaskDeferralPolicy> kTaskDeferralPolicyParam{
-    &kDeferRendererTasksAfterInput,
-    kDeferRendererTasksAfterInputPolicyParamName,
-    TaskDeferralPolicy::kAllDeferrableTypes, &kTaskDeferralOptions};
+BASE_FEATURE_ENUM_PARAM(TaskDeferralPolicy,
+                        kTaskDeferralPolicyParam,
+                        &kDeferRendererTasksAfterInput,
+                        kDeferRendererTasksAfterInputPolicyParamName,
+                        TaskDeferralPolicy::kAllDeferrableTypes,
+                        &kTaskDeferralOptions);
 
 BASE_FEATURE(kDelayAsyncScriptExecution,
              "DelayAsyncScriptExecution",
@@ -2414,8 +2416,11 @@
 BASE_FEATURE(kThrottleInstallingServiceWorker,
              "ThrottleInstallingServiceWorker",
              base::FEATURE_ENABLED_BY_DEFAULT);
-const base::FeatureParam<int> kInstallingServiceWorkerOutstandingThrottledLimit{
-    &kThrottleInstallingServiceWorker, "limit", 3};
+BASE_FEATURE_PARAM(int,
+                   kInstallingServiceWorkerOutstandingThrottledLimit,
+                   &kThrottleInstallingServiceWorker,
+                   "limit",
+                   3);
 
 // Throttles Javascript timer wake ups of unimportant frames (cross origin
 // frames with small proportion of the page's visible area and no user
@@ -2426,15 +2431,18 @@
 // Interval between Javascript timer wake ups for unimportant frames (small
 // cross origin frames with no user activation) when the
 // "ThrottleUnimportantFrameTimers" feature is enabled.
-const base::FeatureParam<int>
-    kUnimportantFrameTimersThrottledWakeUpIntervalMills{
-        &features::kThrottleUnimportantFrameTimers,
-        "unimportant_frame_timers_throttled_wake_up_interval_millis", 32};
+BASE_FEATURE_PARAM(int,
+                   kUnimportantFrameTimersThrottledWakeUpIntervalMills,
+                   &features::kThrottleUnimportantFrameTimers,
+                   "unimportant_frame_timers_throttled_wake_up_interval_millis",
+                   32);
 // The percentage of the page's visible area below which a frame is considered
 // small. Only small frames can be throttled by ThrottleUnimportantFrameTimers.
-const base::FeatureParam<int> kLargeFrameSizePercentThreshold{
-    &features::kThrottleUnimportantFrameTimers,
-    "large_frame_size_percent_threshold", 75};
+BASE_FEATURE_PARAM(int,
+                   kLargeFrameSizePercentThreshold,
+                   &features::kThrottleUnimportantFrameTimers,
+                   "large_frame_size_percent_threshold",
+                   75);
 
 BASE_FEATURE(kTimedHTMLParserBudget,
              "TimedHTMLParserBudget",
@@ -2503,8 +2511,11 @@
 // - Roughly as fast as snappy, with a better compression ratio.
 //
 // And even -3 should be smaller *and* faster than snappy.
-const base::FeatureParam<int> kZstdCompressionLevel{
-    &features::kUseZstdForParkableStrings, "compression_level", 1};
+BASE_FEATURE_PARAM(int,
+                   kZstdCompressionLevel,
+                   &features::kUseZstdForParkableStrings,
+                   "compression_level",
+                   1);
 
 BASE_FEATURE(kUseThreadPoolForMediaStreamVideoTaskRunner,
              "UseThreadPoolForMediaStreamVideoTaskRunner",
@@ -2513,9 +2524,11 @@
 BASE_FEATURE(kVSyncDecoding,
              "VSyncDecoding",
              base::FEATURE_DISABLED_BY_DEFAULT);
-const base::FeatureParam<base::TimeDelta>
-    kVSyncDecodingHiddenOccludedTickDuration{
-        &kVSyncDecoding, "occluded_tick_duration", base::Hertz(10)};
+BASE_FEATURE_PARAM(base::TimeDelta,
+                   kVSyncDecodingHiddenOccludedTickDuration,
+                   &kVSyncDecoding,
+                   "occluded_tick_duration",
+                   base::Hertz(10));
 
 BASE_FEATURE(kVSyncEncoding,
              "VSyncEncoding",
@@ -2703,14 +2716,21 @@
 BASE_FEATURE(kExpandCompositedCullRect,
              "ExpandCompositedCullRect",
              base::FEATURE_ENABLED_BY_DEFAULT);
-const base::FeatureParam<int>
-    kCullRectPixelDistanceToExpand(&kExpandCompositedCullRect, "pixels", 4000);
-const base::FeatureParam<double>
-    kCullRectExpansionDPRCoef(&kExpandCompositedCullRect, "dpr_coef", 0);
-const base::FeatureParam<bool> kSmallScrollersUseMinCullRect(
-    &kExpandCompositedCullRect,
-    "small_scroller_opt",
-    false);
+BASE_FEATURE_PARAM(int,
+                   kCullRectPixelDistanceToExpand,
+                   &kExpandCompositedCullRect,
+                   "pixels",
+                   4000);
+BASE_FEATURE_PARAM(double,
+                   kCullRectExpansionDPRCoef,
+                   &kExpandCompositedCullRect,
+                   "dpr_coef",
+                   0);
+BASE_FEATURE_PARAM(bool,
+                   kSmallScrollersUseMinCullRect,
+                   &kExpandCompositedCullRect,
+                   "small_scroller_opt",
+                   false);
 
 BASE_FEATURE(kTreatHTTPExpiresHeaderValueZeroAsExpiredInBlink,
              "TreatHTTPExpiresHeaderValueZeroAsExpiredInBlink",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index b29d992..129d2d27 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -321,8 +321,8 @@
   // All per-frame task types are deferrable.
   kAllTypes,
 };
-BLINK_COMMON_EXPORT extern const base::FeatureParam<TaskDeferralPolicy>
-    kTaskDeferralPolicyParam;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(TaskDeferralPolicy,
+                                               kTaskDeferralPolicyParam);
 // Constants to expose the policy in about:flags.
 BLINK_COMMON_EXPORT extern const char
     kDeferRendererTasksAfterInputPolicyParamName[];
@@ -1671,14 +1671,16 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kThreadedPreloadScanner);
 
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kThrottleInstallingServiceWorker);
-BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
-    kInstallingServiceWorkerOutstandingThrottledLimit;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(
+    int,
+    kInstallingServiceWorkerOutstandingThrottledLimit);
 
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kThrottleUnimportantFrameTimers);
-BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
-    kUnimportantFrameTimersThrottledWakeUpIntervalMills;
-BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
-    kLargeFrameSizePercentThreshold;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(
+    int,
+    kUnimportantFrameTimersThrottledWakeUpIntervalMills);
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(int,
+                                               kLargeFrameSizePercentThreshold);
 
 // If enabled, the HTMLDocumentParser will use a budget based on elapsed time
 // rather than token count.
@@ -1701,7 +1703,7 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kUseSnappyForParkableStrings);
 
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kUseZstdForParkableStrings);
-BLINK_COMMON_EXPORT extern const base::FeatureParam<int> kZstdCompressionLevel;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(int, kZstdCompressionLevel);
 
 // Causes MediaStreamVideoSource video frames to be transported on a
 // SequencedTaskRunner backed by the threadpool instead of the normal IO thread.
@@ -1719,8 +1721,9 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kVSyncDecoding);
 // Feature parameter controlling WebRTC VSyncDecoding tick durations during
 // occluded tabs.
-BLINK_COMMON_EXPORT extern const base::FeatureParam<base::TimeDelta>
-    kVSyncDecodingHiddenOccludedTickDuration;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(
+    base::TimeDelta,
+    kVSyncDecodingHiddenOccludedTickDuration);
 
 // Feature flag for driving encoding with the Metronome by VSyncs.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kVSyncEncoding);
@@ -1821,14 +1824,14 @@
 // If kCullRectExpansionDPRCoef equals 1, the expansion will be
 // kCullRectPixelDistanceToExpand in device coordinates.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kExpandCompositedCullRect);
-BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
-    kCullRectPixelDistanceToExpand;
-BLINK_COMMON_EXPORT extern const base::FeatureParam<double>
-    kCullRectExpansionDPRCoef;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(int,
+                                               kCullRectPixelDistanceToExpand);
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(double,
+                                               kCullRectExpansionDPRCoef);
 // If this is enabled, a non-root scroller with an area below a threshold will
 // use a minimal cull rect expansion instead of the above expansion.
-BLINK_COMMON_EXPORT extern const base::FeatureParam<bool>
-    kSmallScrollersUseMinCullRect;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(bool,
+                                               kSmallScrollersUseMinCullRect);
 
 // Treat HTTP header `Expires: "0"` as expired value according section 5.3 on
 // RFC 9111.
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
index 8430369..cbd14fa 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
@@ -155,10 +155,10 @@
   DCHECK(!GetExecutionContext()->IsContextDestroyed());
   DCHECK(!GetExecutionContext()->IsContextPaused());
 
-  probe::WillHandlePromise(GetExecutionContext(), script_state_,
-                           state_ == kResolving,
-                           exception_context_.GetClassName(),
-                           exception_context_.GetPropertyName(), script_url_);
+  probe::WillHandlePromise(
+      GetExecutionContext(), script_state_, state_ == kResolving,
+      exception_context_.GetClassName(),
+      exception_context_.GetPropertyNameVariant(), script_url_);
 
   v8::MicrotasksScope microtasks_scope(
       script_state_->GetIsolate(), ToMicrotaskQueue(script_state_),
diff --git a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
index dc76ba5..b72547e3 100644
--- a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
+++ b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
@@ -129,7 +129,8 @@
             line = re.sub(r"\s{2,}", " ", line).strip()  # Collapse whitespace
             if len(line) == 0:
                 continue
-            elif line.startswith("class ") or line.startswith("struct "):
+            elif line.startswith("class ") or line.startswith(
+                    "struct ") or line.startswith("using "):
                 self.forward_declarations.append(line)
             else:
                 self.declarations.append(Method(line))
diff --git a/third_party/blink/renderer/core/css/color_function.h b/third_party/blink/renderer/core/css/color_function.h
index 5f34c957..7c415c3 100644
--- a/third_party/blink/renderer/core/css/color_function.h
+++ b/third_party/blink/renderer/core/css/color_function.h
@@ -102,6 +102,14 @@
           {Color::ColorSpace::kHSL, MetadataEntry::kHsl},
           {Color::ColorSpace::kHWB, MetadataEntry::kHwb},
       });
+
+  static const Metadata& MetadataForColorSpace(Color::ColorSpace color_space) {
+    auto function_entry = kColorSpaceMap.find(color_space);
+    CHECK(function_entry != ColorFunction::kColorSpaceMap.end());
+    auto function_metadata_entry = kMetadataMap.find(function_entry->second);
+    CHECK(function_metadata_entry != kMetadataMap.end());
+    return function_metadata_entry->second;
+  }
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc
index 2824ca5d..c11ff7c 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node.cc
+++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -843,6 +843,13 @@
       return PixelsAndPercent(value_->GetFloatValue() * length_resolver.Zoom(),
                               0.0f, /*has_explicit_pixels=*/true,
                               /*has_explicit_percent=*/false);
+    case kCalcAngle:
+      // Treat angles as pixels to support calc() expressions on hue angles in
+      // relative color syntax. This allows converting such expressions to
+      // CalculationValues.
+      return PixelsAndPercent(value_->GetFloatValue(), 0.0f,
+                              /*has_explicit_pixels=*/true,
+                              /*has_explicit_percent=*/false);
     default:
       NOTREACHED_IN_MIGRATION();
       return {};
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node_test.cc b/third_party/blink/renderer/core/css/css_math_expression_node_test.cc
index 3f422d8..7be4b74 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node_test.cc
+++ b/third_party/blink/renderer/core/css/css_math_expression_node_test.cc
@@ -694,7 +694,7 @@
 }
 
 TEST(CSSMathExpressionNode, TestColorChannelExpressionWithoutSubstitution) {
-  const String input = "h / 2";
+  const String input = "(h / 360) * 360deg";
 
   const CSSColorChannelMap color_channel_map = {
       {CSSValueID::kH, std::nullopt},
@@ -710,14 +710,18 @@
       CSSMathExpressionNode::ParseMathFunction(
           CSSValueID::kCalc, stream, *context, Flags({Flag::AllowPercent}),
           kCSSAnchorQueryTypesNone, color_channel_map);
-  EXPECT_EQ(css_node->Category(), CalculationResultCategory::kCalcNumber);
+  EXPECT_EQ(css_node->Category(), CalculationResultCategory::kCalcAngle);
   EXPECT_TRUE(css_node->IsOperation());
   const CSSMathExpressionOperation* css_op =
       To<CSSMathExpressionOperation>(css_node);
   const CSSMathExpressionNode* operand = css_op->GetOperands()[0];
-  EXPECT_TRUE(operand->IsKeywordLiteral());
+  EXPECT_TRUE(operand->IsOperation());
+  const CSSMathExpressionOperation* inner_css_op =
+      To<CSSMathExpressionOperation>(operand);
+  const CSSMathExpressionNode* inner_operand = inner_css_op->GetOperands()[0];
+  EXPECT_TRUE(inner_operand->IsKeywordLiteral());
   const CSSMathExpressionKeywordLiteral* keyword =
-      To<CSSMathExpressionKeywordLiteral>(operand);
+      To<CSSMathExpressionKeywordLiteral>(inner_operand);
   EXPECT_EQ(keyword->GetValue(), CSSValueID::kH);
   EXPECT_EQ(keyword->GetContext(),
             CSSMathExpressionKeywordLiteral::Context::kColorChannel);
@@ -732,13 +736,29 @@
   const CalculationExpressionOperationNode::Children& operands =
       operation_node->GetChildren();
   EXPECT_EQ(operands.size(), 2u);
-  EXPECT_TRUE(operands[0]->IsColorChannelKeyword());
-  EXPECT_EQ(To<CalculationExpressionColorChannelKeywordNode>(operands[0].get())
-                ->Value(),
-            ColorChannelKeyword::kH);
-  EXPECT_TRUE(operands[1]->IsNumber());
-  EXPECT_EQ(To<CalculationExpressionNumberNode>(operands[1].get())->Value(),
-            0.5);
+  EXPECT_TRUE(operands[0]->IsOperation());
+
+  const CalculationExpressionOperationNode* inner_operation_node =
+      To<CalculationExpressionOperationNode>(operands[0].get());
+  const CalculationExpressionOperationNode::Children& inner_operands =
+      inner_operation_node->GetChildren();
+  EXPECT_EQ(inner_operation_node->GetOperator(),
+            CalculationOperator::kMultiply);
+  EXPECT_EQ(inner_operands.size(), 2u);
+  EXPECT_TRUE(inner_operands[0]->IsColorChannelKeyword());
+  EXPECT_EQ(
+      To<CalculationExpressionColorChannelKeywordNode>(inner_operands[0].get())
+          ->Value(),
+      ColorChannelKeyword::kH);
+  EXPECT_TRUE(inner_operands[1]->IsNumber());
+  EXPECT_EQ(
+      To<CalculationExpressionNumberNode>(inner_operands[1].get())->Value(),
+      (1.f / 360.f));
+
+  EXPECT_TRUE(operands[1]->IsPixelsAndPercent());
+  EXPECT_EQ(To<CalculationExpressionPixelsAndPercentNode>(operands[1].get())
+                ->Pixels(),
+            360.f);
 }
 
 }  // anonymous namespace
diff --git a/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc b/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc
index e4e2ba0..66f2a4f 100644
--- a/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc
+++ b/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc
@@ -231,12 +231,7 @@
     color_space_ = ColorSpaceFromFunctionName(function_id);
   }
 
-  auto function_entry = ColorFunction::kColorSpaceMap.find(color_space_);
-  CHECK(function_entry != ColorFunction::kColorSpaceMap.end());
-  auto function_metadata_entry =
-      ColorFunction::kMetadataMap.find(function_entry->second);
-  CHECK(function_metadata_entry != ColorFunction::kMetadataMap.end());
-  function_metadata_ = &function_metadata_entry->second;
+  function_metadata_ = &ColorFunction::MetadataForColorSpace(color_space_);
 
   if (unresolved_origin_color_) {
     origin_color_ = TryResolveAtParseTime(*unresolved_origin_color_);
diff --git a/third_party/blink/renderer/core/css/style_color.cc b/third_party/blink/renderer/core/css/style_color.cc
index da6a7bc..57d219b 100644
--- a/third_party/blink/renderer/core/css/style_color.cc
+++ b/third_party/blink/renderer/core/css/style_color.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "third_party/blink/renderer/core/css/color_function.h"
 #include "third_party/blink/renderer/core/css/css_color.h"
 #include "third_party/blink/renderer/core/css/css_color_channel_keywords.h"
 #include "third_party/blink/renderer/core/css/css_color_mix_value.h"
@@ -229,10 +230,100 @@
 
 Color StyleColor::UnresolvedRelativeColor::Resolve(
     const Color& current_color) const {
-  // TODO(crbug.com/325309578): Fully resolve the relative color.
-  const Color resolved_origin =
+  Color resolved_origin =
       ResolveColorOperand(origin_color_, origin_color_type_, current_color);
-  return resolved_origin;
+  resolved_origin.ConvertToColorSpace(color_interpolation_space_);
+
+  const ColorFunction::Metadata& function_metadata =
+      ColorFunction::MetadataForColorSpace(color_interpolation_space_);
+
+  std::vector<std::pair<ColorChannelKeyword, float>> keyword_values = {
+      {{CSSValueIDToColorChannelKeyword(function_metadata.channel_name[0]),
+        resolved_origin.Param0()},
+       {CSSValueIDToColorChannelKeyword(function_metadata.channel_name[1]),
+        resolved_origin.Param1()},
+       {CSSValueIDToColorChannelKeyword(function_metadata.channel_name[2]),
+        resolved_origin.Param2()},
+       {ColorChannelKeyword::kAlpha, resolved_origin.Alpha()}}};
+
+  // We need to make value adjustments for certain color spaces.
+  //
+  // https://www.w3.org/TR/css-color-4/#the-hsl-notation
+  // https://www.w3.org/TR/css-color-4/#the-hwb-notation
+  // hsl and hwb are specified with percent reference ranges of 0..100 in
+  // channels 1 and 2, but blink::Color represents these values over 0..1.
+  // We scale up the origin values so that they pass through computation
+  // correctly, then later, scale them down in the final result.
+  //
+  // https://www.w3.org/TR/css-color-4/#hue-syntax
+  // Channels representing <hue> are normalized to the range [0,360).
+  const bool is_hxx_color_space =
+      (color_interpolation_space_ == Color::ColorSpace::kHSL) ||
+      (color_interpolation_space_ == Color::ColorSpace::kHWB);
+  const bool is_lch_color_space =
+      (color_interpolation_space_ == Color::ColorSpace::kLch) ||
+      (color_interpolation_space_ == Color::ColorSpace::kOklch);
+
+  if (is_hxx_color_space) {
+    keyword_values[1].second *= 100.;
+    keyword_values[2].second *= 100.;
+  }
+
+  EvaluationInput evaluation_input;
+  evaluation_input.color_channel_keyword_values =
+      base::flat_map(std::move(keyword_values));
+
+  auto to_channel_value =
+      [&evaluation_input](const CalculationValue* calculation_value,
+                          double channel_percentage) -> std::optional<float> {
+    // The color function metadata table uses NaN to indicate that percentages
+    // are not applicable to a given channel. NaN is not suitable as a clamp
+    // limit for evaluating a CalculationValue, so translate it into float max.
+    const float max_value = (std::isnan(channel_percentage))
+                                ? std::numeric_limits<float>::max()
+                                : channel_percentage;
+    if (calculation_value != nullptr) {
+      return calculation_value->Evaluate(max_value, evaluation_input);
+    }
+    return std::nullopt;
+  };
+
+  std::array<std::optional<float>, 3> params = {
+      to_channel_value(channel0_.get(),
+                       function_metadata.channel_percentage[0]),
+      to_channel_value(channel1_.get(),
+                       function_metadata.channel_percentage[1]),
+      to_channel_value(channel2_.get(),
+                       function_metadata.channel_percentage[2])};
+  std::optional<float> param_alpha = to_channel_value(alpha_.get(), 1.f);
+
+  auto wrap_hue_channel = [](std::optional<float>& param) {
+    if (param.has_value()) {
+      // Perform the wrap at double precision to avoid floating-point rounding
+      // drift which is observable at single precision for some values.
+      param.value() =
+          fmod(fmod(static_cast<double>(param.value()), 360.0) + 360.0, 360.0);
+    }
+  };
+  auto scale_down_channel = [](std::optional<float>& param) {
+    if (param.has_value()) {
+      param.value() /= 100.f;
+    }
+  };
+  if (is_hxx_color_space) {
+    wrap_hue_channel(params[0]);
+    scale_down_channel(params[1]);
+    scale_down_channel(params[2]);
+  } else if (is_lch_color_space) {
+    wrap_hue_channel(params[2]);
+  }
+
+  Color result = Color::FromColorSpace(color_interpolation_space_, params[0],
+                                       params[1], params[2], param_alpha);
+  if (Color::IsLegacyColorSpace(result.GetColorSpace())) {
+    result.ConvertToColorSpace(Color::ColorSpace::kSRGB);
+  }
+  return result;
 }
 
 bool StyleColor::UnresolvedRelativeColor::operator==(
diff --git a/third_party/blink/renderer/core/css/style_color_test.cc b/third_party/blink/renderer/core/css/style_color_test.cc
index 22ef5e79..4ab6bd6 100644
--- a/third_party/blink/renderer/core/css/style_color_test.cc
+++ b/third_party/blink/renderer/core/css/style_color_test.cc
@@ -241,4 +241,47 @@
   EXPECT_EQ(value_2->CssText(), "color(from currentcolor srgb r 25% none)");
 }
 
+TEST(StyleColorTest, UnresolvedRelativeColor_Resolve) {
+  StyleColor currentcolor;
+  Color rebeccapurple(102, 51, 153);
+
+  // Note: This test compares serializations to allow tolerance for
+  // floating-point rounding error.
+
+  using UnresolvedRelativeColor = StyleColor::UnresolvedRelativeColor;
+  UnresolvedRelativeColor* rgb = MakeGarbageCollected<UnresolvedRelativeColor>(
+      currentcolor, Color::ColorSpace::kSRGB,
+      *CreateCalcAddValue(CSSValueID::kR, CSSValueID::kG),
+      *CSSNumericLiteralValue::Create(0, CSSPrimitiveValue::UnitType::kNumber),
+      *CSSIdentifierValue::Create(CSSValueID::kNone), nullptr);
+  EXPECT_EQ(
+      rgb->Resolve(rebeccapurple).SerializeAsCSSColor(),
+      Color::FromColorSpace(Color::ColorSpace::kSRGB, 0.6, 0, std::nullopt, 1.0)
+          .SerializeAsCSSColor());
+
+  UnresolvedRelativeColor* hsl = MakeGarbageCollected<UnresolvedRelativeColor>(
+      currentcolor, Color::ColorSpace::kHSL,
+      *CSSIdentifierValue::Create(CSSValueID::kH),
+      *CSSNumericLiteralValue::Create(20,
+                                      CSSPrimitiveValue::UnitType::kPercentage),
+      *CSSIdentifierValue::Create(CSSValueID::kL),
+      CSSIdentifierValue::Create(CSSValueID::kAlpha));
+  EXPECT_EQ(
+      hsl->Resolve(rebeccapurple).SerializeAsCSSColor(),
+      Color::FromColorSpace(Color::ColorSpace::kSRGB, 0.4, 0.32, 0.48, 1.0)
+          .SerializeAsCSSColor());
+
+  UnresolvedRelativeColor* lch = MakeGarbageCollected<UnresolvedRelativeColor>(
+      currentcolor, Color::ColorSpace::kLch,
+      *CSSIdentifierValue::Create(CSSValueID::kL),
+      *CSSIdentifierValue::Create(CSSValueID::kC),
+      *CSSIdentifierValue::Create(CSSValueID::kH),
+      CSSIdentifierValue::Create(CSSValueID::kAlpha));
+  EXPECT_EQ(lch->Resolve(Color::FromColorSpace(Color::ColorSpace::kLch, 200,
+                                               300, 400, 5))
+                .SerializeAsCSSColor(),
+            Color::FromColorSpace(Color::ColorSpace::kLch, 100, 300, 40, 1)
+                .SerializeAsCSSColor());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index ab51deaa..2f03a6a0 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1617,8 +1617,7 @@
 
 using AllowState = blink::Document::DeclarativeShadowRootAllowState;
 void Document::SetContentFromDOMParser(const String& content) {
-  if (RuntimeEnabledFeatures::DOMParserUsesHTMLFastPathParserEnabled() &&
-      contentType() == "text/html" && IsA<HTMLDocument>(this)) {
+  if (contentType() == "text/html" && IsA<HTMLDocument>(this)) {
     auto* body = MakeGarbageCollected<HTMLBodyElement>(*this);
     HTMLFragmentParsingBehaviorSet parser_behavior(
         {HTMLFragmentParsingBehavior::kStripInitialWhitespaceForBody});
diff --git a/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc b/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc
index 8df41cb7..11959b7 100644
--- a/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc
+++ b/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc
@@ -561,9 +561,15 @@
         AtomicString(script_info->class_like_name));
   }
 
-  if (!script_info->property_like_name.IsNull()) {
-    script_timing_info->SetPropertyLikeName(
-        AtomicString(script_info->property_like_name));
+  if (const auto* property_name =
+          std::get_if<const char*>(&script_info->property_like_name)) {
+    script_timing_info->SetPropertyLikeName(AtomicString(*property_name));
+  } else if (auto* property_name_string =
+                 std::get_if<String>(&script_info->property_like_name)) {
+    if (!property_name_string->IsNull()) {
+      script_timing_info->SetPropertyLikeName(
+          AtomicString(*property_name_string));
+    }
   }
 
   script_timing_info->SetPauseDuration(script_info->pause_duration);
@@ -576,7 +582,7 @@
     ScriptState* script_state,
     bool resolving,
     const char* class_like_name,
-    const String& property_like_name,
+    std::variant<const char*, String> property_like_name,
     const String& script_url) {
   // Unlike other script entry points, promise resolvers don't have a "Did"
   // probe, so we keep its depth at 1 and reset only at task end.
diff --git a/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.h b/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.h
index 9705806..c1148e1b 100644
--- a/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.h
+++ b/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.h
@@ -72,7 +72,7 @@
   void WillHandlePromise(ScriptState*,
                          bool resolving,
                          const char* class_like,
-                         const String& property_like,
+                         std::variant<const char*, String> property_like,
                          const String& script_url);
   void Will(const probe::EvaluateScriptBlock&);
   void Did(const probe::EvaluateScriptBlock& probe_data) {
@@ -113,7 +113,7 @@
     base::TimeDelta pause_duration;
     int layout_depth = 0;
     const char* class_like_name = nullptr;
-    String property_like_name;
+    std::variant<const char*, String> property_like_name;
     ScriptTimingInfo::ScriptSourceLocation source_location;
   };
 
diff --git a/third_party/blink/renderer/core/html/forms/type_ahead.cc b/third_party/blink/renderer/core/html/forms/type_ahead.cc
index 86e2e18..c8aee43 100644
--- a/third_party/blink/renderer/core/html/forms/type_ahead.cc
+++ b/third_party/blink/renderer/core/html/forms/type_ahead.cc
@@ -98,30 +98,10 @@
     int index = (selected < 0 ? 0 : selected) + search_start_offset;
     index %= option_count;
 
-    if (RuntimeEnabledFeatures::SelectTypeToSearchIgnoreAccentsEnabled()) {
-      for (int i = 0; i < option_count;
-           ++i, index = (index + 1) % option_count) {
-        String text =
-            StripLeadingWhiteSpace(data_source_->OptionAtIndex(index));
-        if (text.StartsWithIgnoringCaseAndAccents(prefix)) {
-          return index;
-        }
-      }
-    } else {
-      // Compute a case-folded copy of the prefix string before beginning the
-      // search for a matching element. This code uses foldCase to work around
-      // the fact that String::startWith does not fold non-ASCII characters.
-      // This code can be changed to use startWith once that is fixed.
-      String prefix_with_case_folded(prefix.FoldCase());
-      for (int i = 0; i < option_count;
-           ++i, index = (index + 1) % option_count) {
-        // Fold the option string and check if its prefix is equal to the folded
-        // prefix.
-        String text = data_source_->OptionAtIndex(index);
-        if (StripLeadingWhiteSpace(text).FoldCase().StartsWith(
-                prefix_with_case_folded)) {
-          return index;
-        }
+    for (int i = 0; i < option_count; ++i, index = (index + 1) % option_count) {
+      String text = StripLeadingWhiteSpace(data_source_->OptionAtIndex(index));
+      if (text.StartsWithIgnoringCaseAndAccents(prefix)) {
+        return index;
       }
     }
   }
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
index 91fa912..5e127fef 100644
--- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -928,6 +928,10 @@
     case HTMLTag::kSelect:
       if (RuntimeEnabledFeatures::SelectParserRelaxationEnabled() &&
           tree_.OpenElements()->InScope(HTMLTag::kSelect)) {
+        tree_.OpenElements()->TopNode()->AddConsoleMessage(
+            mojom::blink::ConsoleMessageSource::kJavaScript,
+            mojom::blink::ConsoleMessageLevel::kWarning,
+            "A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.");
         // Don't allow nested <select>s. This is the exact same logic as
         // <button>s.
         ParseError(token);
@@ -1522,6 +1526,10 @@
           tree_.InsertSelfClosingHTMLElementDestroyingToken(token);
           return;
         case HTMLTag::kSelect: {
+        tree_.OpenElements()->TopNode()->AddConsoleMessage(
+            mojom::blink::ConsoleMessageSource::kJavaScript,
+            mojom::blink::ConsoleMessageLevel::kError,
+            "A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.");
           ParseError(token);
           AtomicHTMLToken end_select(HTMLToken::kEndTag, HTMLTag::kSelect);
           ProcessEndTag(&end_select);
diff --git a/third_party/blink/renderer/core/paint/cull_rect_updater.cc b/third_party/blink/renderer/core/paint/cull_rect_updater.cc
index 6618be8..16a05e5 100644
--- a/third_party/blink/renderer/core/paint/cull_rect_updater.cc
+++ b/third_party/blink/renderer/core/paint/cull_rect_updater.cc
@@ -28,7 +28,7 @@
 namespace {
 
 float ExpansionRatio(const LayoutObject& object) {
-  static const int dpr_coef = features::kCullRectExpansionDPRCoef.Get();
+  const int dpr_coef = features::kCullRectExpansionDPRCoef.Get();
   float device_pixel_ratio =
       object.GetFrame()->LocalFrameRoot().GetDocument()->DevicePixelRatio();
   return 1 + (device_pixel_ratio - 1) * dpr_coef;
diff --git a/third_party/blink/renderer/core/probe/core_probes.pidl b/third_party/blink/renderer/core/probe/core_probes.pidl
index bf2831cf..d76b1e0d 100644
--- a/third_party/blink/renderer/core/probe/core_probes.pidl
+++ b/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -65,6 +65,7 @@
   class ScriptState;
   class SpeculationCandidate;
   class XMLHttpRequest;
+  using PropertyName = std::variant<const char*, String>;
 
   void DidClearDocumentOfWindowObject([Keep] LocalFrame*);
   void DidCreateMainWorldContext([Keep] LocalFrame*);
@@ -164,7 +165,7 @@
   void DocumentWriteFetchScript([Keep] Document*);
   void DidChangeViewport(LocalFrame* document);
   void BreakableLocation(ExecutionContext* context, const char* name);
-  void WillHandlePromise(ExecutionContext* context, ScriptState* script_state, bool resolving, const char* class_like_name, const String& property_like_name, const String& script_url);
+  void WillHandlePromise(ExecutionContext* context, ScriptState* script_state, bool resolving, const char* class_like_name, PropertyName property_like_name, const String& script_url);
   RecalculateStyle(Document* document);
   UpdateLayout(Document* document);
 
diff --git a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc
index 16b52749..3ddda88 100644
--- a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc
+++ b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc
@@ -62,6 +62,14 @@
 
 }  // namespace
 
+BASE_FEATURE(kScriptedIdleTaskControllerOOMFix,
+             "ScriptedIdleTaskControllerOOMFix",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+IdleTask::~IdleTask() {
+  CHECK(!delayed_task_handle_.IsValid());
+}
+
 ScriptedIdleTaskController::DelayedTaskCanceler::DelayedTaskCanceler() =
     default;
 ScriptedIdleTaskController::DelayedTaskCanceler::DelayedTaskCanceler(
@@ -100,7 +108,9 @@
   UpdateStateIfNeeded();
 }
 
-ScriptedIdleTaskController::~ScriptedIdleTaskController() = default;
+ScriptedIdleTaskController::~ScriptedIdleTaskController() {
+  CHECK(idle_tasks_.empty(), base::NotFatalUntil::M135);
+}
 
 void ScriptedIdleTaskController::Trace(Visitor* visitor) const {
   visitor->Trace(idle_tasks_);
@@ -120,6 +130,10 @@
   }
 }
 
+void ScriptedIdleTaskController::Dispose() {
+  RemoveAllIdleTasks();
+}
+
 ScriptedIdleTaskController::CallbackId
 ScriptedIdleTaskController::RegisterCallback(
     IdleTask* idle_task,
@@ -137,15 +151,16 @@
   idle_task->async_task_context()->Schedule(GetExecutionContext(),
                                             "requestIdleCallback");
 
-  ScheduleCallback(id, timeout_millis);
+  PostSchedulerIdleAndTimeoutTasks(id, timeout_millis);
   DEVTOOLS_TIMELINE_TRACE_EVENT_INSTANT(
       "RequestIdleCallback", inspector_idle_callback_request_event::Data,
       GetExecutionContext(), id, timeout_millis);
   return id;
 }
 
-void ScriptedIdleTaskController::ScheduleCallback(CallbackId id,
-                                                  uint32_t timeout_millis) {
+void ScriptedIdleTaskController::PostSchedulerIdleAndTimeoutTasks(
+    CallbackId id,
+    uint32_t timeout_millis) {
   // Note: be careful about memory usage of this method.
   // 1. In certain corner case scenarios, millions of callbacks per minute could
   //    be processed. The memory usage per callback should be minimized as much
@@ -155,17 +170,26 @@
   //    task from the queue. Failure to do so is likely to result in OOM.
   base::DelayedTaskHandle delayed_task_handle;
   if (timeout_millis > 0) {
-    auto callback = WTF::BindOnce(&ScriptedIdleTaskController::TimeoutFired,
-                                  WrapWeakPersistent(this), id);
+    auto callback =
+        WTF::BindOnce(&ScriptedIdleTaskController::SchedulerTimeoutTask,
+                      WrapWeakPersistent(this), id);
     delayed_task_handle =
         GetExecutionContext()
             ->GetTaskRunner(TaskType::kIdleTask)
             ->PostCancelableDelayedTask(base::subtle::PostDelayedTaskPassKey(),
                                         FROM_HERE, std::move(callback),
                                         base::Milliseconds(timeout_millis));
+
+    if (base::FeatureList::IsEnabled(kScriptedIdleTaskControllerOOMFix)) {
+      auto it = idle_tasks_.find(id);
+      CHECK_NE(it, idle_tasks_.end());
+      CHECK(!it->value->delayed_task_handle_.IsValid());
+      it->value->delayed_task_handle_ = std::move(delayed_task_handle);
+    }
   }
 
-  PostIdleTask(id, DelayedTaskCanceler(std::move(delayed_task_handle)));
+  PostSchedulerIdleTask(id,
+                        DelayedTaskCanceler(std::move(delayed_task_handle)));
 }
 
 void ScriptedIdleTaskController::CancelCallback(CallbackId id) {
@@ -180,62 +204,77 @@
     return;
   }
 
-  idle_tasks_.erase(id);
+  RemoveIdleTask(id);
 }
 
-void ScriptedIdleTaskController::PostIdleTask(CallbackId id,
-                                              DelayedTaskCanceler canceler) {
+void ScriptedIdleTaskController::PostSchedulerIdleTask(
+    CallbackId id,
+    DelayedTaskCanceler canceler) {
   ++num_pending_scheduler_idle_tasks_;
   UpdateMaxSchedulerIdleTasksCrashKey(num_pending_scheduler_idle_tasks_);
 
   scheduler_->PostIdleTask(
       FROM_HERE,
-      WTF::BindOnce(&ScriptedIdleTaskController::IdleTaskFired,
+      WTF::BindOnce(&ScriptedIdleTaskController::SchedulerIdleTask,
                     WrapWeakPersistent(this), id, std::move(canceler)));
 }
 
-void ScriptedIdleTaskController::IdleTaskFired(
+void ScriptedIdleTaskController::SchedulerIdleTask(
     CallbackId id,
     ScriptedIdleTaskController::DelayedTaskCanceler /* canceler */,
     base::TimeTicks deadline) {
   CHECK_GT(num_pending_scheduler_idle_tasks_, 0u, base::NotFatalUntil::M135);
   --num_pending_scheduler_idle_tasks_;
 
-  // If we are going to yield immediately, reschedule the callback for
-  // later.
-  if (ThreadScheduler::Current()->ShouldYieldForHighPriorityWork()) {
-    ScheduleCallback(id, /* timeout_millis */ 0);
+  if (!idle_tasks_.Contains(id)) {
     return;
   }
-  CallbackFired(id, deadline, IdleDeadline::CallbackType::kCalledWhenIdle);
-}
-
-void ScriptedIdleTaskController::TimeoutFired(CallbackId id) {
-  CallbackFired(id, base::TimeTicks::Now(),
-                IdleDeadline::CallbackType::kCalledByTimeout);
-}
-
-void ScriptedIdleTaskController::CallbackFired(
-    CallbackId id,
-    base::TimeTicks deadline,
-    IdleDeadline::CallbackType callback_type) {
-  if (!idle_tasks_.Contains(id))
-    return;
 
   if (paused_) {
-    if (callback_type == IdleDeadline::CallbackType::kCalledByTimeout) {
-      // Queue for execution when we are resumed.
-      pending_timeouts_.push_back(id);
+    if (base::FeatureList::IsEnabled(kScriptedIdleTaskControllerOOMFix)) {
+      // Reschedule when unpaused.
+      idle_tasks_to_reschedule_.emplace_back(id);
+    } else {
+      // All `IdleTask`s are rescheduled when unpaused.
     }
-    // Just drop callbacks called while suspended, these will be reposted on the
-    // idle task queue when we are resumed.
     return;
   }
 
-  RunCallback(id, deadline, callback_type);
+  // If we are going to yield immediately, reschedule the callback for later.
+  if (ThreadScheduler::Current()->ShouldYieldForHighPriorityWork()) {
+    // Note: `canceler` is implicitly deleted in this code path, which means
+    // that the timeout will not be honored when the
+    // "ScriptedIdleTaskControllerOOMFix" feature is disabled (when the feature
+    // is enabled, the `DelayedTaskHandle` is stored on the `IdleTask`).
+    PostSchedulerIdleTask(id, DelayedTaskCanceler());
+    return;
+  }
+
+  RunIdleTask(id, deadline, IdleDeadline::CallbackType::kCalledWhenIdle);
 }
 
-void ScriptedIdleTaskController::RunCallback(
+void ScriptedIdleTaskController::SchedulerTimeoutTask(CallbackId id) {
+  if (!idle_tasks_.Contains(id)) {
+    return;
+  }
+
+  // This task uses `blink::TaskType::kIdleTask` which has freezable and
+  // pauseable `blink::scheduler::MainThreadTaskQueue::QueueTraits`, so it
+  // shouldn't be scheduled while paused.
+  CHECK(!paused_, base::NotFatalUntil::M133);
+
+  // TODO(crbug.com/365114039): Remove this in M133 if the above CHECK holds.
+  if (paused_) {
+    // Reschedule when unpaused.
+    idle_tasks_with_expired_timeout_.push_back(id);
+    return;
+  }
+
+  RunIdleTask(id, /*deadline=*/base::TimeTicks::Now(),
+              IdleDeadline::CallbackType::kCalledByTimeout);
+}
+
+void ScriptedIdleTaskController::RunIdleTask(
     CallbackId id,
     base::TimeTicks deadline,
     IdleDeadline::CallbackType callback_type) {
@@ -245,6 +284,7 @@
   // TODO(https://crbug.com/796145): Remove this hack once on-stack objects
   // get supported by either of wrapper-tracing or unified GC.
   auto idle_task_iter = idle_tasks_.find(id);
+  CHECK_NE(idle_task_iter, idle_tasks_.end(), base::NotFatalUntil::M133);
   if (idle_task_iter == idle_tasks_.end())
     return;
   IdleTask* idle_task = idle_task_iter->value;
@@ -272,11 +312,29 @@
   // Finally there is no need to keep the idle task alive.
   //
   // Do not use the iterator because the idle task might update |idle_tasks_|.
-  idle_tasks_.erase(id);
+  RemoveIdleTask(id);
+}
+
+void ScriptedIdleTaskController::RemoveIdleTask(CallbackId id) {
+  auto it = idle_tasks_.find(id);
+  if (it == idle_tasks_.end()) {
+    return;
+  }
+  // A `base::DelayedTaskHandle` must be explicitly canceled before deletion.
+  it->value->delayed_task_handle_.CancelTask();
+  idle_tasks_.erase(it);
+}
+
+void ScriptedIdleTaskController::RemoveAllIdleTasks() {
+  for (auto& idle_task : idle_tasks_) {
+    // A `base::DelayedTaskHandle` must be explicitly canceled before deletion.
+    idle_task.value->delayed_task_handle_.CancelTask();
+  }
+  idle_tasks_.clear();
 }
 
 void ScriptedIdleTaskController::ContextDestroyed() {
-  idle_tasks_.clear();
+  RemoveAllIdleTasks();
 }
 
 void ScriptedIdleTaskController::ContextLifecycleStateChanged(
@@ -295,20 +353,28 @@
   DCHECK(paused_);
   paused_ = false;
 
-  // Run any pending timeouts as separate tasks, since it's not allowed to
-  // execute script from lifecycle callbacks.
-  for (auto& id : pending_timeouts_) {
+  // Reschedule `IdleTask`s for which `SchedulerTimeoutTask` ran while paused.
+  for (auto& id : idle_tasks_with_expired_timeout_) {
     GetExecutionContext()
         ->GetTaskRunner(TaskType::kIdleTask)
-        ->PostTask(FROM_HERE,
-                   WTF::BindOnce(&ScriptedIdleTaskController::TimeoutFired,
-                                 WrapWeakPersistent(this), id));
+        ->PostTask(
+            FROM_HERE,
+            WTF::BindOnce(&ScriptedIdleTaskController::SchedulerTimeoutTask,
+                          WrapWeakPersistent(this), id));
   }
-  pending_timeouts_.clear();
+  idle_tasks_with_expired_timeout_.clear();
 
-  // Repost idle tasks for any remaining callbacks.
-  for (auto& idle_task : idle_tasks_) {
-    PostIdleTask(idle_task.key, DelayedTaskCanceler());
+  if (base::FeatureList::IsEnabled(kScriptedIdleTaskControllerOOMFix)) {
+    // Reschedule `IdleTask`s for which `SchedulerIdleTask` ran while paused.
+    for (auto& idle_task : idle_tasks_to_reschedule_) {
+      PostSchedulerIdleTask(idle_task, DelayedTaskCanceler());
+    }
+    idle_tasks_to_reschedule_.clear();
+  } else {
+    // Reschedule all `IdleTask`s.
+    for (auto& idle_task : idle_tasks_) {
+      PostSchedulerIdleTask(idle_task.key, DelayedTaskCanceler());
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.h b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.h
index e19985d..3b9c45f 100644
--- a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.h
+++ b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCHEDULER_SCRIPTED_IDLE_TASK_CONTROLLER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SCHEDULER_SCRIPTED_IDLE_TASK_CONTROLLER_H_
 
+#include "base/feature_list.h"
 #include "base/task/delayed_task_handle.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -14,27 +15,45 @@
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
+CORE_EXPORT BASE_DECLARE_FEATURE(kScriptedIdleTaskControllerOOMFix);
+
 class IdleRequestOptions;
+class ScriptedIdleTaskController;
 class ThreadScheduler;
 
-// `IdleTask` is an interface type which generalizes tasks which are invoked
-// on idle. The tasks need to define what to do on idle in `invoke`.
+// Terminology used in this file:
+//
+// - `IdleTask`: An externally provided task to run on idle time or after a
+//   deadline
+// - "Scheduler idle task": A task posted to the scheduler which runs on idle
+//   time. May run an `IdleTask` when scheduled.
+// - "Scheduler timeout task": A task posted to the scheduler which runs after a
+//   delay. May run an `IdleTask` when scheduled.
+
+// A task to run on idle time or after a deadline. Subclasses must define what
+// to do when the task runs in `invoke`.
 class CORE_EXPORT IdleTask : public GarbageCollected<IdleTask>,
                              public NameClient {
  public:
   virtual void Trace(Visitor* visitor) const {}
   const char* NameInHeapSnapshot() const override { return "IdleTask"; }
-  ~IdleTask() override = default;
+  ~IdleTask() override;
   virtual void invoke(IdleDeadline*) = 0;
   probe::AsyncTaskContext* async_task_context() { return &async_task_context_; }
 
  private:
+  friend class ScriptedIdleTaskController;
+
   probe::AsyncTaskContext async_task_context_;
+  // Handle to the associated "scheduler timeout task" (only used when the
+  // "ScriptedIdleTaskControllerOOMFix" feature is enabled).
+  base::DelayedTaskHandle delayed_task_handle_;
 };
 
 // `ScriptedIdleTaskController` manages scheduling and running `IdleTask`s. This
@@ -46,6 +65,8 @@
       public ExecutionContextLifecycleStateObserver,
       public Supplement<ExecutionContext>,
       public NameClient {
+  USING_PRE_FINALIZER(ScriptedIdleTaskController, Dispose);
+
  public:
   static const char kSupplementName[];
 
@@ -58,6 +79,7 @@
   const char* NameInHeapSnapshot() const override {
     return "ScriptedIdleTaskController";
   }
+  void Dispose();
 
   using CallbackId = int;
 
@@ -69,8 +91,8 @@
   void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
 
  private:
-  // A helper class to cancel timeout tasks. Calls `CancelTask()` for
-  // the passed `delayed_task_handle` in dtor.
+  // A helper class to cancel a "scheduler timeout task". Calls `CancelTask()`
+  // for the passed `delayed_task_handle` in dtor.
   class DelayedTaskCanceler {
    public:
     DelayedTaskCanceler();
@@ -84,18 +106,30 @@
     base::DelayedTaskHandle delayed_task_handle_;
   };
 
-  void PostIdleTask(CallbackId id, DelayedTaskCanceler canceler);
-  void IdleTaskFired(CallbackId id,
-                     DelayedTaskCanceler canceler,
-                     base::TimeTicks deadline);
-  void TimeoutFired(CallbackId id);
-  void CallbackFired(CallbackId,
-                     base::TimeTicks deadline,
-                     IdleDeadline::CallbackType);
+  // Posts a "scheduler idle task" and a "scheduler timeout task" to run the
+  // `IdleTask` identified by `id`.
+  void PostSchedulerIdleAndTimeoutTasks(CallbackId id, uint32_t timeout_millis);
+
+  // Posts a "scheduler idle task" to run the `IdleTask` identified by `id`.
+  // `canceler` is bound to that task (only used when the
+  // "ScriptedIdleTaskControllerOOMFix" feature is disabled).
+  void PostSchedulerIdleTask(CallbackId id, DelayedTaskCanceler canceler);
+
+  void SchedulerIdleTask(CallbackId id,
+                         DelayedTaskCanceler canceler,
+                         base::TimeTicks deadline);
+  void SchedulerTimeoutTask(CallbackId id);
+
+  void RunIdleTask(CallbackId id,
+                   base::TimeTicks deadline,
+                   IdleDeadline::CallbackType callback_type);
+
+  // Removes an/all `IdleTask`(s) from `idle_tasks_`.
+  void RemoveIdleTask(CallbackId id);
+  void RemoveAllIdleTasks();
 
   void ContextPaused();
   void ContextUnpaused();
-  void ScheduleCallback(CallbackId id, uint32_t timeout_millis);
 
   int NextCallbackId();
 
@@ -104,20 +138,31 @@
     return !WTF::IsHashTraitsEmptyOrDeletedValue<Traits, CallbackId>(id);
   }
 
-  void RunCallback(CallbackId,
-                   base::TimeTicks deadline,
-                   IdleDeadline::CallbackType);
+  // Not owned.
+  ThreadScheduler* scheduler_;
 
-  ThreadScheduler* scheduler_;  // Not owned.
+  // Pending `IdleTask`s.
   HeapHashMap<CallbackId, Member<IdleTask>> idle_tasks_;
-  Vector<CallbackId> pending_timeouts_;
+
+  // `IdleTask`s for which `SchedulerTimeoutTask` ran while paused. They'll be
+  // rescheduled when unpaused.
+  Vector<CallbackId> idle_tasks_with_expired_timeout_;
+
+  // `IdleTask`s for which `SchedulerIdleTask` ran while paused. They'll be
+  // rescheduled when unpaused. Only used when the
+  // "ScriptedIdleTaskControllerOOMFix" feature is enabled.
+  Vector<CallbackId> idle_tasks_to_reschedule_;
+
+  // Id that will be assigned to the `IdleTask` registered with this.
   CallbackId next_callback_id_ = 0;
+
+  // Whether the execution context is paused.
   bool paused_ = false;
-  // Number of idle tasks posted to `scheduler_` which are not executed yet.
-  //
-  // Note: This is not necessarily equal to the size of `idle_tasks_`
-  // (e.g. `ContextUnpaused` may cause multiple idle tasks to be posted to the
-  // `scheduler_` for the same `idle_tasks_` entry).
+
+  // Number of "scheduler idle tasks" posted to `scheduler_` which did not run
+  // yet. Not necessarily equal to the size of `idle_tasks_`
+  // (e.g. `ContextUnpaused` may cause multiple "scheduler idle tasks" for the
+  // same `idle_tasks_` entry).
   size_t num_pending_scheduler_idle_tasks_ = 0;
 };
 
diff --git a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc
index 3d2f7c2..6cd2f87 100644
--- a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc
+++ b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc
@@ -4,7 +4,10 @@
 
 #include "third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.h"
 
+#include <deque>
+
 #include "base/task/single_thread_task_runner.h"
+#include "base/test/scoped_feature_list.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
@@ -93,7 +96,7 @@
   bool ShouldYieldForHighPriorityWork() override { return should_yield_; }
   void PostIdleTask(const base::Location&,
                     Thread::IdleTask idle_task) override {
-    idle_task_ = std::move(idle_task);
+    idle_tasks_.push_back(std::move(idle_task));
   }
   void PostDelayedIdleTask(const base::Location&,
                            base::TimeDelta,
@@ -112,9 +115,14 @@
 
   void SetV8Isolate(v8::Isolate* isolate) override { isolate_ = isolate; }
 
-  void RunIdleTask() { std::move(idle_task_).Run(base::TimeTicks()); }
-  bool HasIdleTask() const { return !!idle_task_; }
-  Thread::IdleTask TakeIdleTask() { return std::move(idle_task_); }
+  void RunIdleTask() { TakeIdleTask().Run(base::TimeTicks()); }
+  size_t GetNumIdleTasks() const { return idle_tasks_.size(); }
+  Thread::IdleTask TakeIdleTask() {
+    CHECK(!idle_tasks_.empty());
+    auto idle_task = std::move(idle_tasks_.front());
+    idle_tasks_.pop_front();
+    return idle_task;
+  }
 
   scoped_refptr<TestTaskRunner> TaskRunner() { return task_runner_; }
 
@@ -127,7 +135,7 @@
  private:
   v8::Isolate* isolate_;
   bool should_yield_;
-  Thread::IdleTask idle_task_;
+  std::deque<Thread::IdleTask> idle_tasks_;
   scoped_refptr<TestTaskRunner> task_runner_ =
       base::MakeRefCounted<TestTaskRunner>();
 };
@@ -236,148 +244,172 @@
 };
 }  // namespace
 
-TEST(ScriptedIdleTaskControllerTest, RunCallback) {
-  test::TaskEnvironment task_environment;
-  MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield(false));
-  ScopedSchedulerOverrider scheduler_overrider(&scheduler,
-                                               scheduler.TaskRunner());
-  ScopedNullExecutionContext execution_context(
-      std::make_unique<IdleTaskControllerFrameScheduler>(&scheduler));
-  ScriptedIdleTaskController* controller = &ScriptedIdleTaskController::From(
-      execution_context.GetExecutionContext());
+class ScriptedIdleTaskControllerTest
+    : public testing::Test,
+      public testing::WithParamInterface<bool> {
+ public:
+  ScriptedIdleTaskControllerTest() {
+    if (IsOOMFixEnabled()) {
+      scoped_feature_list_.InitAndEnableFeature(
+          kScriptedIdleTaskControllerOOMFix);
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(
+          kScriptedIdleTaskControllerOOMFix);
+    }
+  }
+
+  void InitializeScheduler(ShouldYield should_yield) {
+    scheduler_.emplace(should_yield);
+    scheduler_overrider_.emplace(&scheduler_.value(), scheduler_->TaskRunner());
+    execution_context_.emplace(
+        std::make_unique<IdleTaskControllerFrameScheduler>(
+            &scheduler_.value()));
+  }
+
+  void DeleteScheduler() {
+    execution_context_.reset();
+    scheduler_overrider_.reset();
+    scheduler_.reset();
+  }
+
+  ScriptedIdleTaskController* GetController() {
+    return &ScriptedIdleTaskController::From(
+        execution_context_->GetExecutionContext());
+  }
+
+  bool IsOOMFixEnabled() { return GetParam(); }
+
+ protected:
+  test::TaskEnvironment task_environment_;
+  std::optional<MockScriptedIdleTaskControllerScheduler> scheduler_;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  std::optional<ScopedSchedulerOverrider> scheduler_overrider_;
+  std::optional<ScopedNullExecutionContext> execution_context_;
+};
+
+TEST_P(ScriptedIdleTaskControllerTest, RunCallback) {
+  InitializeScheduler(ShouldYield(false));
 
   Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
   IdleRequestOptions* options = IdleRequestOptions::Create();
-  EXPECT_FALSE(scheduler.HasIdleTask());
-  int id = controller->RegisterCallback(idle_task, options);
-  EXPECT_TRUE(scheduler.HasIdleTask());
+  EXPECT_EQ(0u, scheduler_->GetNumIdleTasks());
+  int id = GetController()->RegisterCallback(idle_task, options);
   EXPECT_NE(id, 0);
+  EXPECT_EQ(1u, scheduler_->GetNumIdleTasks());
 
   EXPECT_CALL(*idle_task, invoke(testing::_));
-  scheduler.RunIdleTask();
+  scheduler_->RunIdleTask();
   testing::Mock::VerifyAndClearExpectations(idle_task);
-  EXPECT_FALSE(scheduler.HasIdleTask());
+  EXPECT_EQ(0u, scheduler_->GetNumIdleTasks());
 }
 
-TEST(ScriptedIdleTaskControllerTest, DontRunCallbackWhenAskedToYield) {
-  test::TaskEnvironment task_environment;
-  MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield(true));
-  ScopedSchedulerOverrider scheduler_overrider(&scheduler,
-                                               scheduler.TaskRunner());
-  ScopedNullExecutionContext execution_context(
-      std::make_unique<IdleTaskControllerFrameScheduler>(&scheduler));
-  ScriptedIdleTaskController* controller = &ScriptedIdleTaskController::From(
-      execution_context.GetExecutionContext());
+TEST_P(ScriptedIdleTaskControllerTest, DontRunCallbackWhenAskedToYield) {
+  InitializeScheduler(ShouldYield(true));
 
   Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
   IdleRequestOptions* options = IdleRequestOptions::Create();
-  int id = controller->RegisterCallback(idle_task, options);
+  int id = GetController()->RegisterCallback(idle_task, options);
   EXPECT_NE(0, id);
 
   EXPECT_CALL(*idle_task, invoke(testing::_)).Times(0);
-  scheduler.RunIdleTask();
+  scheduler_->RunIdleTask();
   testing::Mock::VerifyAndClearExpectations(idle_task);
 
   // The idle task should have been reposted.
-  EXPECT_TRUE(scheduler.HasIdleTask());
+  EXPECT_EQ(1u, scheduler_->GetNumIdleTasks());
 }
 
-TEST(ScriptedIdleTaskControllerTest, RunCallbacksAsyncWhenUnpaused) {
-  test::TaskEnvironment task_environment;
-  MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield(true));
-  ScopedSchedulerOverrider scheduler_overrider(&scheduler,
-                                               scheduler.TaskRunner());
-  ScopedNullExecutionContext execution_context(
-      std::make_unique<IdleTaskControllerFrameScheduler>(&scheduler));
-  ScriptedIdleTaskController* controller = &ScriptedIdleTaskController::From(
-      execution_context.GetExecutionContext());
-
-  // Register an idle task with a deadline.
-  Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
-  IdleRequestOptions* options = IdleRequestOptions::Create();
-  options->setTimeout(1);
-  int id = controller->RegisterCallback(idle_task, options);
-  EXPECT_NE(0, id);
-
-  // Hitting the deadline while the frame is paused shouldn't cause any tasks to
-  // run.
-  controller->ContextLifecycleStateChanged(mojom::FrameLifecycleState::kPaused);
-  EXPECT_CALL(*idle_task, invoke(testing::_)).Times(0);
-  scheduler.AdvanceTimeAndRun(base::Milliseconds(1));
-  testing::Mock::VerifyAndClearExpectations(idle_task);
-
-  // Even if we unpause, no tasks should run immediately.
-  EXPECT_CALL(*idle_task, invoke(testing::_)).Times(0);
-  controller->ContextLifecycleStateChanged(
-      mojom::FrameLifecycleState::kRunning);
-  testing::Mock::VerifyAndClearExpectations(idle_task);
-
-  // Idle callback should have been scheduled as an asynchronous task.
-  EXPECT_CALL(*idle_task, invoke(testing::_)).Times(1);
-  scheduler.AdvanceTimeAndRun(base::Milliseconds(0));
-  testing::Mock::VerifyAndClearExpectations(idle_task);
-}
-
-TEST(ScriptedIdleTaskControllerTest, LongTimeoutShouldBeRemoveFromQueue) {
-  test::TaskEnvironment task_environment;
-  MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield(false));
-  ScopedSchedulerOverrider scheduler_overrider(&scheduler,
-                                               scheduler.TaskRunner());
-  ScopedNullExecutionContext execution_context(
-      std::make_unique<IdleTaskControllerFrameScheduler>(&scheduler));
-  ScriptedIdleTaskController* controller = &ScriptedIdleTaskController::From(
-      execution_context.GetExecutionContext());
+TEST_P(ScriptedIdleTaskControllerTest, LongTimeoutShouldBeRemoveFromQueue) {
+  InitializeScheduler(ShouldYield(false));
 
   // Register an idle task with a deadline.
   Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
   IdleRequestOptions* options = IdleRequestOptions::Create();
   options->setTimeout(1000000);
-  int id = controller->RegisterCallback(idle_task, options);
+  int id = GetController()->RegisterCallback(idle_task, options);
   EXPECT_NE(id, 0);
-  EXPECT_EQ(scheduler.TaskRunner()->GetTaskCanceledCount(), 0);
+  EXPECT_EQ(scheduler_->TaskRunner()->GetTaskCanceledCount(), 0);
 
   // Run the task.
   EXPECT_CALL(*idle_task, invoke(testing::_));
-  scheduler.RunIdleTask();
+  scheduler_->RunIdleTask();
   testing::Mock::VerifyAndClearExpectations(idle_task);
 
   // The timeout task should be removed from the task queue.
   // Failure to do so is likely to result in OOM.
-  EXPECT_EQ(scheduler.TaskRunner()->GetTaskCanceledCount(), 1);
+  EXPECT_EQ(scheduler_->TaskRunner()->GetTaskCanceledCount(), 1);
 }
 
-TEST(ScriptedIdleTaskControllerTest, RunAfterSchedulerWasDeleted) {
-  test::TaskEnvironment task_environment;
-  scoped_refptr<TestTaskRunner> task_runner;
-  Thread::IdleTask thead_idle_task;
+TEST_P(ScriptedIdleTaskControllerTest, RunAfterSchedulerWasDeleted) {
+  InitializeScheduler(ShouldYield(false));
+
+  scoped_refptr<TestTaskRunner> task_runner = scheduler_->TaskRunner();
 
   Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
   IdleRequestOptions* options = IdleRequestOptions::Create();
   options->setTimeout(1);
 
-  {
-    MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield(false));
-    task_runner = scheduler.TaskRunner();
-    ScopedSchedulerOverrider scheduler_overrider(&scheduler, task_runner);
-    ScopedNullExecutionContext execution_context(
-        std::make_unique<IdleTaskControllerFrameScheduler>(&scheduler));
-    ScriptedIdleTaskController* controller = &ScriptedIdleTaskController::From(
-        execution_context.GetExecutionContext());
-
     // Register an idle task with a deadline.
-    int id = controller->RegisterCallback(idle_task, options);
-    EXPECT_NE(id, 0);
+  int id = GetController()->RegisterCallback(idle_task, options);
+  EXPECT_NE(id, 0);
 
-    thead_idle_task = scheduler.TakeIdleTask();
+  Thread::IdleTask thread_idle_task = scheduler_->TakeIdleTask();
 
-    // `scheduler` is deleted here.
-  }
+  DeleteScheduler();
 
   EXPECT_CALL(*idle_task, invoke(testing::_)).Times(0);
-  std::move(thead_idle_task).Run(base::TimeTicks());
+  std::move(thread_idle_task).Run(base::TimeTicks());
   testing::Mock::VerifyAndClearExpectations(idle_task);
 
   EXPECT_EQ(task_runner->GetTaskCanceledCount(), 1);
 }
 
+TEST_P(ScriptedIdleTaskControllerTest, NoUnnecessaryRepostOnUnpause) {
+  InitializeScheduler(ShouldYield(false));
+
+  // Register an idle task.
+  Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
+  GetController()->RegisterCallback(idle_task, IdleRequestOptions::Create());
+
+  // Pause/unpause the context a few times.
+  for (int i = 0; i < 3; ++i) {
+    GetController()->ContextLifecycleStateChanged(
+        mojom::FrameLifecycleState::kPaused);
+    GetController()->ContextLifecycleStateChanged(
+        mojom::FrameLifecycleState::kRunning);
+  }
+
+  // Pausing/unpausing the context should not cause more scheduler idle tasks to
+  // be posted. That would unnecessarily use memory.
+  if (IsOOMFixEnabled()) {
+    EXPECT_EQ(scheduler_->GetNumIdleTasks(), 1u);
+  } else {
+    EXPECT_GT(scheduler_->GetNumIdleTasks(), 1u);
+  }
+}
+
+TEST_P(ScriptedIdleTaskControllerTest,
+       SchedulerTimeoutTaskCanceledOnIdleTaskCanceled) {
+  InitializeScheduler(ShouldYield(false));
+
+  // Register and cancel an idle task with a timeout.
+  Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
+  IdleRequestOptions* options = IdleRequestOptions::Create();
+  options->setTimeout(1);
+  const int id = GetController()->RegisterCallback(idle_task, options);
+  GetController()->CancelCallback(id);
+
+  // The scheduler timeout task should be canceled. Otherwise, it stays in the
+  // queue until the timeout expires which unnecessarily uses memory.
+  if (IsOOMFixEnabled()) {
+    EXPECT_EQ(scheduler_->TaskRunner()->GetTaskCanceledCount(), 1);
+  } else {
+    EXPECT_EQ(scheduler_->TaskRunner()->GetTaskCanceledCount(), 0);
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(, ScriptedIdleTaskControllerTest, ::testing::Bool());
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/stream_promise_resolver.cc b/third_party/blink/renderer/core/streams/stream_promise_resolver.cc
index 6fd76ab3..41a4c1d 100644
--- a/third_party/blink/renderer/core/streams/stream_promise_resolver.cc
+++ b/third_party/blink/renderer/core/streams/stream_promise_resolver.cc
@@ -79,7 +79,7 @@
   probe::WillHandlePromise(
       ToExecutionContext(script_state), script_state,
       /*resolving=*/true, class_like_name_,
-      property_like_name_.IsNull() ? String("resolve") : property_like_name_,
+      property_like_name_.IsNull() ? "resolve" : property_like_name_,
       script_url_);
 
   is_settled_ = true;
@@ -112,7 +112,7 @@
   probe::WillHandlePromise(
       ToExecutionContext(script_state), script_state,
       /*resolving=*/false, class_like_name_,
-      property_like_name_.IsNull() ? String("reject") : property_like_name_,
+      property_like_name_.IsNull() ? "reject" : property_like_name_,
       script_url_);
   is_settled_ = true;
   v8::Isolate* isolate = script_state->GetIsolate();
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 6b54171d..f59e469 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -722,10 +722,6 @@
   document_->Fetcher()->EnableIsPreloadedForTest();
 }
 
-Internals::~Internals() {
-  ResetMockOverlayScrollbars();
-}
-
 LocalFrame* Internals::GetFrame() const {
   if (!document_)
     return nullptr;
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index 1defbd1..662b4e64 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -100,7 +100,6 @@
   static void ResetToConsistentState(Page*);
 
   explicit Internals(ExecutionContext*);
-  ~Internals() override;
 
   String elementLayoutTreeAsText(Element*, ExceptionState&);
 
diff --git a/third_party/blink/renderer/core/timing/third_party_script_detector.cc b/third_party/blink/renderer/core/timing/third_party_script_detector.cc
index 40c1af40..fb0045e 100644
--- a/third_party/blink/renderer/core/timing/third_party_script_detector.cc
+++ b/third_party/blink/renderer/core/timing/third_party_script_detector.cc
@@ -70,6 +70,8 @@
     "|(googlesyndication\\.com/[^\"]+/(?:ufs_web_display|reactive_library_fy))"
     // Funding Choices
     "|(fundingchoicesmessages\\.google\\.com)"
+    // Slider Revolution
+    "|(/wp-content/plugins/revslider)"
     // WordPress
     "|(/wp-(?:content|includes)/"
     "|wp-embed\\.min\\.js)";
@@ -98,6 +100,7 @@
                             Technology::kGooglePublisherTag,
                             Technology::kGoogleAdsLibraries,
                             Technology::kFundingChoices,
+                            Technology::kSliderRevolution,
                             Technology::kWordPress};
                         return vector;
                       }()));
diff --git a/third_party/blink/renderer/core/timing/third_party_script_detector.h b/third_party/blink/renderer/core/timing/third_party_script_detector.h
index f7bd8a9..d8a1102 100644
--- a/third_party/blink/renderer/core/timing/third_party_script_detector.h
+++ b/third_party/blink/renderer/core/timing/third_party_script_detector.h
@@ -47,10 +47,13 @@
     kGoogleAdsLibraries = 1 << 12,
     kFundingChoices = 1 << 13,
     kElementor = 1 << 14,
-    kLast = kElementor
+    kSliderRevolution = 1 << 15,
+    kLast = kSliderRevolution
     // If adding new technologies, add above kLast and shift kLast accordingly.
     // Keep in sync with `ThirdPartyTechnology` in
     // base/tracing/protos/chrome_track_event.proto.
+    // The enum value (n) here is converted to the proto value (m) by
+    // m = bit_width(n) + 1.
     // Max value allowed: 1 << 63. Limited by UKM bitfield.
   };
 
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_change_record.cc b/third_party/blink/renderer/modules/file_system_access/file_system_change_record.cc
index a8ed5e46..129d29dc 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_change_record.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_change_record.cc
@@ -6,7 +6,6 @@
 
 #include <optional>
 
-#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_change_type.h"
 #include "third_party/blink/renderer/modules/file_system_access/file_system_handle.h"
 
 namespace blink {
@@ -57,8 +56,8 @@
       relative_path_components_(relative_path),
       type_(std::move(type)) {}
 
-const char* FileSystemChangeRecord::type() const {
-  return V8FileSystemChangeType(ToChangeTypeEnum(type_->which())).AsCStr();
+V8FileSystemChangeType FileSystemChangeRecord::type() const {
+  return V8FileSystemChangeType(ToChangeTypeEnum(type_->which()));
 }
 
 std::optional<Vector<String>> FileSystemChangeRecord::relativePathMovedFrom()
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_change_record.h b/third_party/blink/renderer/modules/file_system_access/file_system_change_record.h
index 18e3ceb1..b88529b 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_change_record.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_change_record.h
@@ -8,6 +8,7 @@
 #include <optional>
 
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_observer.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_change_type.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
@@ -30,7 +31,7 @@
   const Vector<String>& relativePathComponents() const {
     return relative_path_components_;
   }
-  const char* type() const;
+  V8FileSystemChangeType type() const;
   std::optional<Vector<String>> relativePathMovedFrom() const;
 
   void Trace(Visitor* visitor) const override;
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
index ab2f80b..0bfbf85 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
@@ -38,10 +38,10 @@
 
   virtual bool isFile() const { return false; }
   virtual bool isDirectory() const { return false; }
-  const char* kind() const {
-    const auto kind = isFile() ? V8FileSystemHandleKind::Enum::kFile
-                               : V8FileSystemHandleKind::Enum::kDirectory;
-    return V8FileSystemHandleKind(kind).AsCStr();
+  V8FileSystemHandleKind kind() const {
+    return V8FileSystemHandleKind(
+        isFile() ? V8FileSystemHandleKind::Enum::kFile
+                 : V8FileSystemHandleKind::Enum::kDirectory);
   }
   const String& name() const { return name_; }
 
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc
index f395641..4b3c54a 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc
@@ -230,8 +230,8 @@
   return bytes_written;
 }
 
-const char* FileSystemSyncAccessHandle::mode() {
-  return lock_mode_.AsCStr();
+String FileSystemSyncAccessHandle::mode() {
+  return lock_mode_.AsString();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.h
index dedd782..eaf410b 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.h
@@ -51,7 +51,7 @@
                  FileSystemReadWriteOptions* options,
                  ExceptionState&);
 
-  const char* mode();
+  String mode();
 
  private:
   FileSystemAccessFileDelegate* file_delegate() { return file_delegate_.Get(); }
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc b/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc
index 79a2481..c5ddb65 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc
@@ -130,8 +130,8 @@
   visitor->Trace(underlying_sink_);
 }
 
-const char* FileSystemWritableFileStream::mode() const {
-  return lock_mode_.AsCStr();
+String FileSystemWritableFileStream::mode() const {
+  return lock_mode_.AsString();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h b/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h
index 528ff64..831b1b8a 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h
@@ -45,7 +45,7 @@
   ScriptPromise<IDLUndefined> seek(ScriptState*,
                                    uint64_t offset,
                                    ExceptionState&);
-  const char* mode() const;
+  String mode() const;
 
  private:
   Member<FileSystemUnderlyingSink> underlying_sink_;
diff --git a/third_party/blink/renderer/modules/ml/ml_context.cc b/third_party/blink/renderer/modules/ml/ml_context.cc
index d0b2012bc..66d8f80 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.cc
+++ b/third_party/blink/renderer/modules/ml/ml_context.cc
@@ -879,11 +879,11 @@
   graphs_.insert(graph);
 }
 
-ScriptPromise<MLTensor> MLContext::createBuffer(
+ScriptPromise<MLTensor> MLContext::createTensor(
     ScriptState* script_state,
     const MLTensorDescriptor* descriptor,
     ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLContext::createBuffer");
+  ScopedMLTrace scoped_trace("MLContext::createTensor");
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid script state");
@@ -924,16 +924,16 @@
     usage = webnn::MLTensorUsage::FromEnumBitmask(descriptor->usage());
   }
 
-  auto buffer_info =
-      webnn::mojom::blink::BufferInfo::New(validated_descriptor, usage);
+  auto tensor_info =
+      webnn::mojom::blink::TensorInfo::New(validated_descriptor, usage);
 
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver<MLTensor>>(
       script_state, exception_state.GetContext());
   pending_resolvers_.insert(resolver);
 
   // Use `WebNNContext` to create `WebNNTensor` message pipe.
-  context_remote_->CreateBuffer(
-      std::move(buffer_info),
+  context_remote_->CreateTensor(
+      std::move(tensor_info),
       WTF::BindOnce(&MLContext::DidCreateWebNNTensor, WrapPersistent(this),
                     std::move(scoped_trace), WrapPersistent(resolver),
                     std::move(validated_descriptor), usage));
@@ -941,7 +941,7 @@
   return resolver->Promise();
 }
 
-void MLContext::writeBuffer(
+void MLContext::writeTensor(
     ScriptState* script_state,
     MLTensor* dst_buffer,
     const MaybeShared<DOMArrayBufferView>& src_data_view,
@@ -953,7 +953,7 @@
                    /*src_element_count=*/std::nullopt, exception_state);
 }
 
-void MLContext::writeBuffer(
+void MLContext::writeTensor(
     ScriptState* script_state,
     MLTensor* dst_buffer,
     const MaybeShared<DOMArrayBufferView>& src_data_view,
@@ -966,7 +966,7 @@
                    exception_state);
 }
 
-void MLContext::writeBuffer(ScriptState* script_state,
+void MLContext::writeTensor(ScriptState* script_state,
                             MLTensor* dst_buffer,
                             const DOMArrayBufferBase* src_data_base,
                             uint64_t src_byte_offset,
@@ -977,7 +977,7 @@
                    /*src_element_count=*/std::nullopt, exception_state);
 }
 
-void MLContext::writeBuffer(ScriptState* script_state,
+void MLContext::writeTensor(ScriptState* script_state,
                             MLTensor* dst_buffer,
                             const DOMArrayBufferBase* src_data_base,
                             uint64_t src_byte_offset,
@@ -989,7 +989,7 @@
                    /*src_element_count=*/src_byte_size, exception_state);
 }
 
-ScriptPromise<DOMArrayBuffer> MLContext::readBuffer(
+ScriptPromise<DOMArrayBuffer> MLContext::readTensor(
     ScriptState* script_state,
     MLTensor* src_buffer,
     ExceptionState& exception_state) {
@@ -1011,10 +1011,10 @@
     return EmptyPromise();
   }
 
-  return src_buffer->ReadBufferImpl(script_state, exception_state);
+  return src_buffer->ReadTensorImpl(script_state, exception_state);
 }
 
-ScriptPromise<IDLUndefined> MLContext::readBuffer(
+ScriptPromise<IDLUndefined> MLContext::readTensor(
     ScriptState* script_state,
     MLTensor* src_buffer,
     DOMArrayBufferBase* dst_data,
@@ -1031,10 +1031,10 @@
     return EmptyPromise();
   }
 
-  return src_buffer->ReadBufferImpl(script_state, dst_data, exception_state);
+  return src_buffer->ReadTensorImpl(script_state, dst_data, exception_state);
 }
 
-ScriptPromise<IDLUndefined> MLContext::readBuffer(
+ScriptPromise<IDLUndefined> MLContext::readTensor(
     ScriptState* script_state,
     MLTensor* src_buffer,
     MaybeShared<DOMArrayBufferView> dst_data,
@@ -1051,7 +1051,7 @@
     return EmptyPromise();
   }
 
-  return src_buffer->ReadBufferImpl(script_state, dst_data.Get(),
+  return src_buffer->ReadTensorImpl(script_state, dst_data.Get(),
                                     exception_state);
 }
 
@@ -1136,7 +1136,7 @@
     return;
   }
 
-  dst_buffer->WriteBufferImpl(
+  dst_buffer->WriteTensorImpl(
       src_data.subspan(checked_src_byte_offset.ValueOrDie(),
                        checked_write_byte_size.ValueOrDie()),
       exception_state);
@@ -1169,7 +1169,7 @@
     ScriptPromiseResolver<blink::MLTensor>* resolver,
     webnn::OperandDescriptor validated_descriptor,
     webnn::MLTensorUsage usage,
-    webnn::mojom::blink::CreateBufferResultPtr result) {
+    webnn::mojom::blink::CreateTensorResultPtr result) {
   pending_resolvers_.erase(resolver);
 
   ScriptState* script_state = resolver->GetScriptState();
diff --git a/third_party/blink/renderer/modules/ml/ml_context.h b/third_party/blink/renderer/modules/ml/ml_context.h
index ef14214..259fac38 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.h
+++ b/third_party/blink/renderer/modules/ml/ml_context.h
@@ -79,12 +79,12 @@
                                          const MLNamedArrayBufferViews& outputs,
                                          ExceptionState& exception_state);
 
-  ScriptPromise<MLTensor> createBuffer(ScriptState* script_state,
+  ScriptPromise<MLTensor> createTensor(ScriptState* script_state,
                                        const MLTensorDescriptor* descriptor,
                                        ExceptionState& exception_state);
 
   // Writes data specified by array buffer view from offset in elements.
-  void writeBuffer(ScriptState* script_state,
+  void writeTensor(ScriptState* script_state,
                    MLTensor* dst_buffer,
                    const MaybeShared<DOMArrayBufferView>& src_data,
                    uint64_t src_element_offset,
@@ -92,7 +92,7 @@
 
   // Writes data specified by array buffer view from offset and size in
   // elements.
-  void writeBuffer(ScriptState* script_state,
+  void writeTensor(ScriptState* script_state,
                    MLTensor* dst_buffer,
                    const MaybeShared<DOMArrayBufferView>& src_data,
                    uint64_t src_element_offset,
@@ -100,30 +100,30 @@
                    ExceptionState& exception_state);
 
   // Writes array buffer data from offset in bytes.
-  void writeBuffer(ScriptState* script_state,
+  void writeTensor(ScriptState* script_state,
                    MLTensor* dst_buffer,
                    const DOMArrayBufferBase* src_data,
                    uint64_t src_byte_offset,
                    ExceptionState& exception_state);
 
   // Writes array buffer data from offset and size in bytes.
-  void writeBuffer(ScriptState* script_state,
+  void writeTensor(ScriptState* script_state,
                    MLTensor* dst_buffer,
                    const DOMArrayBufferBase* src_data,
                    uint64_t src_byte_offset,
                    uint64_t src_byte_size,
                    ExceptionState& exception_state);
 
-  ScriptPromise<DOMArrayBuffer> readBuffer(ScriptState* script_state,
+  ScriptPromise<DOMArrayBuffer> readTensor(ScriptState* script_state,
                                            MLTensor* src_buffer,
                                            ExceptionState& exception_state);
 
-  ScriptPromise<IDLUndefined> readBuffer(ScriptState* script_state,
+  ScriptPromise<IDLUndefined> readTensor(ScriptState* script_state,
                                          MLTensor* src_buffer,
                                          DOMArrayBufferBase* dst_data,
                                          ExceptionState& exception_state);
 
-  ScriptPromise<IDLUndefined> readBuffer(
+  ScriptPromise<IDLUndefined> readTensor(
       ScriptState* script_state,
       MLTensor* src_buffer,
       MaybeShared<DOMArrayBufferView> dst_data,
@@ -166,7 +166,7 @@
                             ScriptPromiseResolver<blink::MLTensor>* resolver,
                             webnn::OperandDescriptor validated_descriptor,
                             webnn::MLTensorUsage usage,
-                            webnn::mojom::blink::CreateBufferResultPtr result);
+                            webnn::mojom::blink::CreateTensorResultPtr result);
 
   V8MLDeviceType device_type_;
   V8MLPowerPreference power_preference_;
diff --git a/third_party/blink/renderer/modules/ml/ml_context.idl b/third_party/blink/renderer/modules/ml/ml_context.idl
index 1d623888..e200adb1c 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.idl
+++ b/third_party/blink/renderer/modules/ml/ml_context.idl
@@ -281,7 +281,7 @@
     RuntimeEnabled=MachineLearningNeuralNetwork,
     CallWith=ScriptState,
     RaisesException
-  ] Promise<MLTensor> createBuffer(MLTensorDescriptor descriptor);
+  ] Promise<MLTensor> createTensor(MLTensorDescriptor descriptor);
 
   // TODO(crbug.com/328105506): enable partial MLTensor reads/writes.
   // TODO(crbug.com/40278771): consider moving arguments into a dictonary 
@@ -291,8 +291,8 @@
     RuntimeEnabled=MachineLearningNeuralNetwork,
     CallWith=ScriptState,
     RaisesException
-  ] void writeBuffer(
-        MLTensor dstBuffer,
+  ] void writeTensor(
+        MLTensor dstTensor,
         [AllowShared] ArrayBufferView srcData,
         optional MLSize64 srcElementOffset = 0,
         optional MLSize64 srcElementSize);
@@ -301,8 +301,8 @@
     RuntimeEnabled=MachineLearningNeuralNetwork,
     CallWith=ScriptState,
     RaisesException
-  ] void writeBuffer(
-        MLTensor dstBuffer,
+  ] void writeTensor(
+        MLTensor dstTensor,
         ArrayBuffer srcData,
         optional MLSize64 srcByteOffset = 0,
         optional MLSize64 srcByteSize);
@@ -311,24 +311,24 @@
     RuntimeEnabled=MachineLearningNeuralNetwork,
     CallWith=ScriptState,
     RaisesException
-  ] Promise<ArrayBuffer> readBuffer(
-        MLTensor srcBuffer);
+  ] Promise<ArrayBuffer> readTensor(
+        MLTensor sourceTensor);
 
   [
     RuntimeEnabled=MachineLearningNeuralNetwork,
     CallWith=ScriptState,
     RaisesException
-  ] Promise<undefined> readBuffer(
-        MLTensor srcBuffer,
-        [AllowShared] ArrayBufferView dstData);
+  ] Promise<undefined> readTensor(
+        MLTensor sourceTensor,
+        [AllowShared] ArrayBufferView destinationData);
 
   [
     RuntimeEnabled=MachineLearningNeuralNetwork,
     CallWith=ScriptState,
     RaisesException
-  ] Promise<undefined> readBuffer(
-        MLTensor srcBuffer,
-        [AllowShared] ArrayBuffer dstData);
+  ] Promise<undefined> readTensor(
+        MLTensor sourceTensor,
+        [AllowShared] ArrayBuffer destinationData);
 
   // TODO(crbug.com/1273291): enable partial buffer dispatches.
   [
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
index 1e488e8..7f73637 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -458,12 +458,12 @@
   FakeWebNNTensor(
       WebNNContextHelper& helper,
       mojo::PendingAssociatedReceiver<blink_mojom::WebNNTensor> receiver,
-      const blink::WebNNTensorToken& buffer_handle,
-      blink_mojom::BufferInfoPtr buffer_info)
+      const blink::WebNNTensorToken& tensor_handle,
+      blink_mojom::TensorInfoPtr tensor_info)
       : helper_(helper),
         receiver_(this, std::move(receiver)),
-        handle_(buffer_handle) {
-    buffer_ = mojo_base::BigBuffer(buffer_info->descriptor.PackedByteLength());
+        handle_(tensor_handle) {
+    buffer_ = mojo_base::BigBuffer(tensor_info->descriptor.PackedByteLength());
     receiver_.set_disconnect_handler(WTF::BindOnce(
         &FakeWebNNTensor::OnConnectionError, WTF::Unretained(this)));
   }
@@ -476,14 +476,14 @@
   const blink::WebNNTensorToken& handle() const { return handle_; }
 
  private:
-  void ReadBuffer(ReadBufferCallback callback) override {
+  void ReadTensor(ReadTensorCallback callback) override {
     mojo_base::BigBuffer dst_buffer(buffer_.byte_span());
 
     std::move(callback).Run(
-        blink_mojom::ReadBufferResult::NewBuffer(std::move(dst_buffer)));
+        blink_mojom::ReadTensorResult::NewBuffer(std::move(dst_buffer)));
   }
 
-  void WriteBuffer(mojo_base::BigBuffer src_buffer) override {
+  void WriteTensor(mojo_base::BigBuffer src_buffer) override {
     ASSERT_LE(src_buffer.size(), buffer_.size());
     base::span(buffer_).copy_prefix_from(src_buffer);
   }
@@ -545,20 +545,20 @@
         std::make_unique<FakeWebNNGraphBuilder>(*helper_), std::move(receiver));
   }
 
-  void CreateBuffer(blink_mojom::BufferInfoPtr buffer_info,
-                    CreateBufferCallback callback) override {
+  void CreateTensor(blink_mojom::TensorInfoPtr tensor_info,
+                    CreateTensorCallback callback) override {
     mojo::PendingAssociatedRemote<blink_mojom::WebNNTensor> blink_remote;
     auto blink_receiver = blink_remote.InitWithNewEndpointAndPassReceiver();
-    blink::WebNNTensorToken buffer_handle;
+    blink::WebNNTensorToken tensor_handle;
     context_helper_.ConnectWebNNTensorImpl(
-        buffer_handle, std::make_unique<FakeWebNNTensor>(
+        tensor_handle, std::make_unique<FakeWebNNTensor>(
                            context_helper_, std::move(blink_receiver),
-                           buffer_handle, std::move(buffer_info)));
+                           tensor_handle, std::move(tensor_info)));
 
-    auto success = blink_mojom::CreateBufferSuccess::New(
-        std::move(blink_remote), std::move(buffer_handle));
+    auto success = blink_mojom::CreateTensorSuccess::New(
+        std::move(blink_remote), std::move(tensor_handle));
     std::move(callback).Run(
-        blink_mojom::CreateBufferResult::NewSuccess(std::move(success)));
+        blink_mojom::CreateTensorResult::NewSuccess(std::move(success)));
   }
 
   // TODO(crbug.com/354741414): Fix this dangling pointer.
@@ -789,7 +789,7 @@
   auto* script_state = scope.GetScriptState();
   ScriptPromiseTester tester(
       script_state,
-      context->readBuffer(script_state, src_buffer, scope.GetExceptionState()));
+      context->readTensor(script_state, src_buffer, scope.GetExceptionState()));
   tester.WaitUntilSettled();
   if (tester.IsRejected()) {
     return false;
@@ -811,14 +811,14 @@
 
   ScriptPromiseTester tester(
       scope.GetScriptState(),
-      ml_context->createBuffer(scope.GetScriptState(), desc,
+      ml_context->createTensor(scope.GetScriptState(), desc,
                                scope.GetExceptionState()));
   tester.WaitUntilSettled();
   CHECK(tester.IsFulfilled());
 
   MLTensor* ml_buffer = V8ToObject<MLTensor>(&scope, tester.Value());
 
-  ml_context->writeBuffer(
+  ml_context->writeTensor(
       scope.GetScriptState(), ml_buffer,
       MaybeShared<DOMArrayBufferView>(array_buffer_view.Get()),
       /*src_element_offset=*/0, scope.GetExceptionState());
@@ -830,7 +830,7 @@
                                   MLTensor* ml_buffer) {
   ScriptPromiseTester tester(
       scope.GetScriptState(),
-      ml_context->readBuffer(scope.GetScriptState(), ml_buffer,
+      ml_context->readTensor(scope.GetScriptState(), ml_buffer,
                              scope.GetExceptionState()));
   tester.WaitUntilSettled();
   if (tester.IsRejected()) {
@@ -1322,7 +1322,7 @@
 
   ScriptPromiseTester buffer_tester(
       script_state,
-      ml_context->createBuffer(script_state, desc, scope.GetExceptionState()));
+      ml_context->createTensor(script_state, desc, scope.GetExceptionState()));
   buffer_tester.WaitUntilSettled();
   EXPECT_TRUE(buffer_tester.IsFulfilled());
 
@@ -1361,7 +1361,7 @@
 
   ScriptPromiseTester buffer_tester(
       script_state,
-      ml_context->createBuffer(script_state, desc, scope.GetExceptionState()));
+      ml_context->createTensor(script_state, desc, scope.GetExceptionState()));
   buffer_tester.WaitUntilSettled();
   EXPECT_TRUE(buffer_tester.IsFulfilled());
 
@@ -1380,13 +1380,13 @@
   ASSERT_THAT(array_buffer, testing::NotNull());
 
   // Writing the full buffer.
-  ml_context->writeBuffer(
+  ml_context->writeTensor(
       script_state, ml_buffer,
       CreateArrayBufferViewFromBytes(array_buffer, input_data),
       /*src_element_offset=*/0, scope.GetExceptionState());
   EXPECT_FALSE(scope.GetExceptionState().HadException());
 
-  ml_context->writeBuffer(
+  ml_context->writeTensor(
       script_state, ml_buffer,
       MaybeShared<DOMArrayBufferView>(blink::DOMUint32Array::Create(
           array_buffer, /*byte_offset=*/0,
@@ -1398,7 +1398,7 @@
       DownloadMLTensorAndCheck(scope, ml_context, ml_buffer, input_data));
 
   // Writing to the remainder of the buffer from source offset.
-  ml_context->writeBuffer(
+  ml_context->writeTensor(
       script_state, ml_buffer,
       CreateArrayBufferViewFromBytes(
           array_buffer,
@@ -1407,7 +1407,7 @@
   EXPECT_FALSE(scope.GetExceptionState().HadException());
 
   // Writing zero bytes at the end of the buffer.
-  ml_context->writeBuffer(
+  ml_context->writeTensor(
       script_state, ml_buffer,
       MaybeShared<DOMArrayBufferView>(blink::DOMUint32Array::Create(
           array_buffer, /*byte_offset=*/0,
@@ -1420,7 +1420,7 @@
       std::array<const uint8_t, kBufferSize>{0xBB, 0xBB, 0xAA, 0xAA}));
 
   // Writing with both a source offset and size.
-  ml_context->writeBuffer(
+  ml_context->writeTensor(
       script_state, ml_buffer,
       CreateArrayBufferViewFromBytes(
           array_buffer,
@@ -1454,7 +1454,7 @@
 
   ScriptPromiseTester buffer_tester(
       script_state,
-      ml_context->createBuffer(script_state, desc, scope.GetExceptionState()));
+      ml_context->createTensor(script_state, desc, scope.GetExceptionState()));
   buffer_tester.WaitUntilSettled();
   EXPECT_TRUE(buffer_tester.IsFulfilled());
 
@@ -1469,7 +1469,7 @@
 
   ml_buffer->destroy();
 
-  ml_context->writeBuffer(
+  ml_context->writeTensor(
       script_state, ml_buffer,
       CreateDOMArrayBufferView(ml_buffer->PackedByteLength(),
                                V8MLOperandDataType::Enum::kUint8)
@@ -1497,7 +1497,7 @@
 
   ScriptPromiseTester create_buffer_tester(
       script_state,
-      ml_context->createBuffer(script_state, desc, scope.GetExceptionState()));
+      ml_context->createTensor(script_state, desc, scope.GetExceptionState()));
   create_buffer_tester.WaitUntilSettled();
   EXPECT_TRUE(create_buffer_tester.IsFulfilled());
 
@@ -1513,7 +1513,7 @@
 
   ml_buffer->destroy();
 
-  ScriptPromise<DOMArrayBuffer> read_promise = ml_context->readBuffer(
+  ScriptPromise<DOMArrayBuffer> read_promise = ml_context->readTensor(
       script_state, ml_buffer, scope.GetExceptionState());
   EXPECT_TRUE(read_promise.IsEmpty());
 }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc
index 3a43b5f6..55aa5c3 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc
@@ -22,17 +22,17 @@
     MLContext* context,
     webnn::OperandDescriptor descriptor,
     webnn::MLTensorUsage usage,
-    webnn::mojom::blink::CreateBufferSuccessPtr create_buffer_success,
+    webnn::mojom::blink::CreateTensorSuccessPtr create_tensor_success,
     base::PassKey<MLContext> /*pass_key*/)
     : ml_context_(context),
       descriptor_(std::move(descriptor)),
       usage_(usage),
-      webnn_handle_(std::move(create_buffer_success->buffer_handle)),
-      remote_buffer_(execution_context) {
-  remote_buffer_.Bind(
-      std::move(create_buffer_success->buffer_remote),
+      webnn_handle_(std::move(create_tensor_success->tensor_handle)),
+      remote_tensor_(execution_context) {
+  remote_tensor_.Bind(
+      std::move(create_tensor_success->tensor_remote),
       execution_context->GetTaskRunner(TaskType::kMachineLearning));
-  remote_buffer_.set_disconnect_handler(
+  remote_tensor_.set_disconnect_handler(
       WTF::BindOnce(&MLTensor::OnConnectionError, WrapWeakPersistent(this)));
 }
 
@@ -40,7 +40,7 @@
 
 void MLTensor::Trace(Visitor* visitor) const {
   visitor->Trace(ml_context_);
-  visitor->Trace(remote_buffer_);
+  visitor->Trace(remote_tensor_);
   visitor->Trace(pending_resolvers_);
   visitor->Trace(pending_byob_resolvers_);
   ScriptWrappable::Trace(visitor);
@@ -85,12 +85,12 @@
   return descriptor_.PackedByteLength();
 }
 
-ScriptPromise<DOMArrayBuffer> MLTensor::ReadBufferImpl(
+ScriptPromise<DOMArrayBuffer> MLTensor::ReadTensorImpl(
     ScriptState* script_state,
     ExceptionState& exception_state) {
   // Remote context gets automatically unbound when the execution context
   // destructs.
-  if (!remote_buffer_.is_bound()) {
+  if (!remote_tensor_.is_bound()) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kInvalidStateError,
         "Buffer has been destroyed or context is lost.");
@@ -101,20 +101,20 @@
       script_state, exception_state.GetContext());
   pending_resolvers_.insert(resolver);
 
-  remote_buffer_->ReadBuffer(WTF::BindOnce(&MLTensor::OnDidReadBuffer,
+  remote_tensor_->ReadTensor(WTF::BindOnce(&MLTensor::OnDidReadTensor,
                                            WrapPersistent(this),
                                            WrapPersistent(resolver)));
 
   return resolver->Promise();
 }
 
-ScriptPromise<IDLUndefined> MLTensor::ReadBufferImpl(
+ScriptPromise<IDLUndefined> MLTensor::ReadTensorImpl(
     ScriptState* script_state,
     DOMArrayBufferBase* dst_data,
     ExceptionState& exception_state) {
   // Remote context gets automatically unbound when the execution context
   // destructs.
-  if (!remote_buffer_.is_bound()) {
+  if (!remote_tensor_.is_bound()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid buffer state");
     return EmptyPromise();
@@ -129,19 +129,19 @@
       script_state, exception_state.GetContext());
   pending_byob_resolvers_.insert(resolver);
 
-  remote_buffer_->ReadBuffer(
-      WTF::BindOnce(&MLTensor::OnDidReadBufferByob, WrapPersistent(this),
+  remote_tensor_->ReadTensor(
+      WTF::BindOnce(&MLTensor::OnDidReadTensorByob, WrapPersistent(this),
                     WrapPersistent(resolver), WrapPersistent(dst_data)));
   return resolver->Promise();
 }
 
-ScriptPromise<IDLUndefined> MLTensor::ReadBufferImpl(
+ScriptPromise<IDLUndefined> MLTensor::ReadTensorImpl(
     ScriptState* script_state,
     DOMArrayBufferView* dst_data,
     ExceptionState& exception_state) {
   // Remote context gets automatically unbound when the execution context
   // destructs.
-  if (!remote_buffer_.is_bound()) {
+  if (!remote_tensor_.is_bound()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid buffer state");
     return EmptyPromise();
@@ -156,15 +156,15 @@
       script_state, exception_state.GetContext());
   pending_byob_resolvers_.insert(resolver);
 
-  remote_buffer_->ReadBuffer(
-      WTF::BindOnce(&MLTensor::OnDidReadBufferByobView, WrapPersistent(this),
+  remote_tensor_->ReadTensor(
+      WTF::BindOnce(&MLTensor::OnDidReadTensorByobView, WrapPersistent(this),
                     WrapPersistent(resolver), WrapPersistent(dst_data)));
   return resolver->Promise();
 }
 
-void MLTensor::OnDidReadBuffer(
+void MLTensor::OnDidReadTensor(
     ScriptPromiseResolver<DOMArrayBuffer>* resolver,
-    webnn::mojom::blink::ReadBufferResultPtr result) {
+    webnn::mojom::blink::ReadTensorResultPtr result) {
   pending_resolvers_.erase(resolver);
 
   if (result->is_error()) {
@@ -177,10 +177,10 @@
   resolver->Resolve(DOMArrayBuffer::Create(result->get_buffer()));
 }
 
-void MLTensor::OnDidReadBufferByob(
+void MLTensor::OnDidReadTensorByob(
     ScriptPromiseResolver<IDLUndefined>* resolver,
     DOMArrayBufferBase* dst_data,
-    webnn::mojom::blink::ReadBufferResultPtr result) {
+    webnn::mojom::blink::ReadTensorResultPtr result) {
   pending_byob_resolvers_.erase(resolver);
 
   if (result->is_error()) {
@@ -204,10 +204,10 @@
   resolver->Resolve();
 }
 
-void MLTensor::OnDidReadBufferByobView(
+void MLTensor::OnDidReadTensorByobView(
     ScriptPromiseResolver<IDLUndefined>* resolver,
     DOMArrayBufferView* dst_data,
-    webnn::mojom::blink::ReadBufferResultPtr result) {
+    webnn::mojom::blink::ReadTensorResultPtr result) {
   pending_byob_resolvers_.erase(resolver);
 
   if (result->is_error()) {
@@ -231,11 +231,11 @@
   resolver->Resolve();
 }
 
-void MLTensor::WriteBufferImpl(base::span<const uint8_t> src_data,
+void MLTensor::WriteTensorImpl(base::span<const uint8_t> src_data,
                                ExceptionState& exception_state) {
   // Remote context gets automatically unbound when the execution context
   // destructs.
-  if (!remote_buffer_.is_bound()) {
+  if (!remote_tensor_.is_bound()) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kInvalidStateError,
         "Buffer has been destroyed or context is lost.");
@@ -249,11 +249,11 @@
   }
 
   // Copy src data.
-  remote_buffer_->WriteBuffer(src_data);
+  remote_tensor_->WriteTensor(src_data);
 }
 
 void MLTensor::OnConnectionError() {
-  remote_buffer_.reset();
+  remote_tensor_.reset();
 
   for (const auto& resolver : pending_resolvers_) {
     resolver->RejectWithDOMException(
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h
index b95489a..ace65aa9 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h
@@ -32,18 +32,18 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  // Instances should only be constructed via `MLContext.createBuffer()`.
+  // Instances should only be constructed via `MLContext.createTensor()`.
   // This method is public as required by the `MakeGarbageCollected` helper.
   //
   // `descriptor` describes the buffer data type and shape.
-  // `create_buffer_success` contains the resulting handles to the created
+  // `create_tensor_success` contains the resulting handles to the created
   // buffer. which may be used to execute a context operation with respective
   // buffer.
   MLTensor(ExecutionContext* execution_context,
            MLContext* context,
            webnn::OperandDescriptor descriptor,
            webnn::MLTensorUsage usage,
-           webnn::mojom::blink::CreateBufferSuccessPtr create_buffer_success,
+           webnn::mojom::blink::CreateTensorSuccessPtr create_tensor_success,
            base::PassKey<MLContext> pass_key);
   MLTensor(const MLTensor&) = delete;
   MLTensor& operator=(const MLTensor&) = delete;
@@ -72,37 +72,37 @@
 
   const MLContext* context() const { return ml_context_.Get(); }
 
-  bool IsValid() const { return remote_buffer_.is_bound(); }
+  bool IsValid() const { return remote_tensor_.is_bound(); }
 
   // Read data from the MLTensor. The resolver should be resolved with a copy of
   // the buffer data. Otherwise, the resolver should be rejected accordingly.
-  ScriptPromise<DOMArrayBuffer> ReadBufferImpl(ScriptState* script_state,
+  ScriptPromise<DOMArrayBuffer> ReadTensorImpl(ScriptState* script_state,
                                                ExceptionState& exception_state);
 
-  ScriptPromise<IDLUndefined> ReadBufferImpl(ScriptState* script_state,
+  ScriptPromise<IDLUndefined> ReadTensorImpl(ScriptState* script_state,
                                              DOMArrayBufferBase* dst_data,
                                              ExceptionState& exception_state);
 
-  ScriptPromise<IDLUndefined> ReadBufferImpl(ScriptState* script_state,
+  ScriptPromise<IDLUndefined> ReadTensorImpl(ScriptState* script_state,
                                              DOMArrayBufferView* dst_data,
                                              ExceptionState& exception_state);
 
   // Write data to the MLTensor. If write was successful, the data will be
   // stored in the MLTensor.
-  void WriteBufferImpl(base::span<const uint8_t> src_data,
+  void WriteTensorImpl(base::span<const uint8_t> src_data,
                        ExceptionState& exception_state);
 
  private:
   // The callback of reading from `WebNNTensor` by calling hardware accelerated
   // OS machine learning APIs.
-  void OnDidReadBuffer(ScriptPromiseResolver<DOMArrayBuffer>* resolver,
-                       webnn::mojom::blink::ReadBufferResultPtr result);
-  void OnDidReadBufferByob(ScriptPromiseResolver<IDLUndefined>* resolver,
+  void OnDidReadTensor(ScriptPromiseResolver<DOMArrayBuffer>* resolver,
+                       webnn::mojom::blink::ReadTensorResultPtr result);
+  void OnDidReadTensorByob(ScriptPromiseResolver<IDLUndefined>* resolver,
                            DOMArrayBufferBase* dst_data,
-                           webnn::mojom::blink::ReadBufferResultPtr result);
-  void OnDidReadBufferByobView(ScriptPromiseResolver<IDLUndefined>* resolver,
+                           webnn::mojom::blink::ReadTensorResultPtr result);
+  void OnDidReadTensorByobView(ScriptPromiseResolver<IDLUndefined>* resolver,
                                DOMArrayBufferView* dst_data,
-                               webnn::mojom::blink::ReadBufferResultPtr result);
+                               webnn::mojom::blink::ReadTensorResultPtr result);
 
   void OnConnectionError();
 
@@ -119,7 +119,7 @@
 
   // The `WebNNTensor` is a buffer that can be used by the hardware
   // accelerated OS machine learning API.
-  HeapMojoAssociatedRemote<webnn::mojom::blink::WebNNTensor> remote_buffer_;
+  HeapMojoAssociatedRemote<webnn::mojom::blink::WebNNTensor> remote_tensor_;
 
   // Keep a set of unresolved `ScriptPromiseResolver`s which will be
   // rejected when the Mojo pipe is unexpectedly disconnected.
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index d365f126..7cd3650 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -363,6 +363,8 @@
       result->options.scalability_mode = media::SVCScalabilityMode::kL1T2;
     } else if (config->scalabilityMode() == "L1T3") {
       result->options.scalability_mode = media::SVCScalabilityMode::kL1T3;
+    } else if (config->scalabilityMode() == "manual") {
+      result->options.manual_reference_buffer_control = true;
     } else {
       result->not_supported_error_message =
           String::Format("Unsupported scalabilityMode: %s",
@@ -907,6 +909,7 @@
 
 void VideoEncoder::Trace(Visitor* visitor) const {
   visitor->Trace(background_readback_);
+  visitor->Trace(frame_reference_buffers_);
   Base::Trace(visitor);
 }
 
@@ -1051,6 +1054,29 @@
   DCHECK_EQ(request->type, Request::Type::kEncode);
   DCHECK_GT(requested_encodes_, 0u);
 
+  String js_error_message;
+  if (request->encodeOpts->hasUpdateBuffer()) {
+    auto* buffer = request->encodeOpts->updateBuffer();
+    if (buffer->owner() != this) {
+      QueueHandleError(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kNotAllowedError,
+          "updateBuffer doesn't belong to this encoder"));
+      request->EndTracing();
+      return;
+    }
+  }
+  if (request->encodeOpts->hasReferenceBuffers()) {
+    for (auto& buffer : request->encodeOpts->referenceBuffers()) {
+      if (buffer->owner() != this) {
+        QueueHandleError(MakeGarbageCollected<DOMException>(
+            DOMExceptionCode::kNotAllowedError,
+            "one of referenceBuffers doesn't belong to this encoder"));
+        request->EndTracing();
+        return;
+      }
+    }
+  }
+
   auto frame = request->input->frame();
   auto encode_options = CreateEncodeOptions(request);
   active_encodes_++;
@@ -1137,6 +1163,14 @@
     Request* request) {
   media::VideoEncoder::EncodeOptions result;
   result.key_frame = request->encodeOpts->keyFrame();
+  if (request->encodeOpts->hasUpdateBuffer()) {
+    result.update_buffer = request->encodeOpts->updateBuffer()->internal_id();
+  }
+  if (request->encodeOpts->hasReferenceBuffers()) {
+    for (auto& buffer : request->encodeOpts->referenceBuffers()) {
+      result.reference_buffers.push_back(buffer->internal_id());
+    }
+  }
   switch (active_config_->codec) {
     case media::VideoCodec::kAV1: {
       if (!active_config_->options.bitrate.has_value() ||
@@ -1247,6 +1281,18 @@
     return;
   }
 
+  // TODO(crbug.com/347676170): remove this hack when we make
+  // getAllFrameBuffers() async and can asynchronously get the number of
+  // encoder buffers.
+  if (active_config_->options.manual_reference_buffer_control &&
+      active_config_->codec == media::VideoCodec::kAV1) {
+    frame_reference_buffers_.clear();
+    for (size_t i = 0; i < 3; ++i) {
+      auto* buffer = MakeGarbageCollected<VideoEncoderBuffer>(this, i);
+      frame_reference_buffers_.push_back(buffer);
+    }
+  }
+
   if (active_config_->hw_pref == HardwarePreference::kPreferSoftware &&
       !MayHaveOSSoftwareEncoder(active_config_->profile)) {
     ContinueConfigureWithGpuFactories(request, nullptr);
@@ -1368,6 +1414,14 @@
   is_platform_encoder_ = encoder_info.is_hardware_accelerated;
   max_active_encodes_ = ComputeMaxActiveEncodes(encoder_info.frame_delay,
                                                 encoder_info.input_capacity);
+  if (active_config_->options.manual_reference_buffer_control) {
+    frame_reference_buffers_.clear();
+    for (size_t i = 0; i < encoder_info.number_of_manual_reference_buffers;
+         ++i) {
+      auto* buffer = MakeGarbageCollected<VideoEncoderBuffer>(this, i);
+      frame_reference_buffers_.push_back(buffer);
+    }
+  }
   // We may have increased our capacity for active encodes.
   ProcessRequests();
 }
@@ -1638,10 +1692,14 @@
 HeapVector<Member<VideoEncoderBuffer>> VideoEncoder::getAllFrameBuffers(
     ScriptState*,
     ExceptionState& exception_state) {
-  exception_state.ThrowDOMException(
-      DOMExceptionCode::kNotSupportedError,
-      "getAllFrameBuffers() only supported with manual scalability mode.");
-  return {};
+  if (!active_config_->options.manual_reference_buffer_control) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kNotSupportedError,
+        "getAllFrameBuffers() only supported with manual scalability mode.");
+    return {};
+  }
+
+  return frame_reference_buffers_;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.h b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
index f296dc6..c0cb81e 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
@@ -184,6 +184,9 @@
   };
   base::flat_map<base::TimeDelta, FrameMetadata> frame_metadata_;
 
+  // Buffers returned by getAllFrameBuffers()
+  HeapVector<Member<VideoEncoderBuffer>> frame_reference_buffers_;
+
   // The color space corresponding to the last emitted output. Used to update
   // emitted VideoDecoderConfig when necessary.
   gfx::ColorSpace last_output_color_space_;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.cc
index 8fed7fd6..70b9c6e2 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.cc
@@ -6,8 +6,20 @@
 
 #include <string>
 
+#include "third_party/blink/renderer/modules/webcodecs/video_encoder.h"
+
 namespace blink {
 
-VideoEncoderBuffer::VideoEncoderBuffer() {}
+VideoEncoderBuffer::VideoEncoderBuffer(VideoEncoder* owner, size_t id)
+    : id_(id), owner_(owner) {}
+
+String VideoEncoderBuffer::id() const {
+  return String::Format("%zu", id_);
+}
+
+void VideoEncoderBuffer::Trace(Visitor* visitor) const {
+  visitor->Trace(owner_);
+  ScriptWrappable::Trace(visitor);
+}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.h b/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.h
index 7a16696..2544914 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder_buffer.h
@@ -8,20 +8,31 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
+class VideoEncoder;
+
 class MODULES_EXPORT VideoEncoderBuffer final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit VideoEncoderBuffer();
+  explicit VideoEncoderBuffer(VideoEncoder* owner, size_t id);
 
   // video_encoder_buffer.idl implementation.
-  String id() const { return {}; }
+  String id() const;
+
+  // GarbageCollected override.
+  void Trace(Visitor*) const override;
+
+  size_t internal_id() const { return id_; }
+  VideoEncoder* owner() { return owner_; }
 
  private:
+  const size_t id_;
+  WeakMember<VideoEncoder> owner_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index c7a0191..c530770c 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -2623,6 +2623,18 @@
   ]
 }
 
+# This source set is used by image decoder fuzzers to initialize their decoders.
+source_set("blink_image_decoder_fuzzer_test_support") {
+  testonly = true
+  visibility = []  # Allow re-assignment of list.
+  visibility = [ "*" ]
+  sources = [
+    "image-decoders/image_decoder_fuzzer_utils.cc",
+    "image-decoders/image_decoder_fuzzer_utils.h",
+  ]
+  deps = [ ":platform" ]
+}
+
 # Fuzzer for WTF::unicode::MathVariant.
 fuzzer_test("math_transform_fuzzer") {
   sources = [ "math_transform_fuzzer.cc" ]
@@ -2772,6 +2784,7 @@
   sources = [ "image-decoders/png/png_image_decoder_fuzzer.cc" ]
   deps = [
     ":blink_fuzzer_test_support",
+    ":blink_image_decoder_fuzzer_test_support",
     ":platform",
     "//third_party/libpng",
   ]
@@ -2788,12 +2801,27 @@
   sources = [ "image-decoders/jpeg/jpeg_image_decoder_fuzzer.cc" ]
   deps = [
     ":blink_fuzzer_test_support",
+    ":blink_image_decoder_fuzzer_test_support",
     ":platform",
   ]
   seed_corpuses = [ "//third_party/blink/web_tests/images/resources/jpegfuzz" ]
   libfuzzer_options = [ "rss_limit_mb=8192" ]
 }
 
+fuzzer_test("blink_bmp_decoder_fuzzer") {
+  sources = [ "image-decoders/bmp/bmp_image_decoder_fuzzer.cc" ]
+  deps = [
+    ":blink_fuzzer_test_support",
+    ":blink_image_decoder_fuzzer_test_support",
+    ":platform",
+  ]
+  seed_corpuses = [ "//third_party/blink/web_tests/images/bmp-suite/good" ]
+
+  # TODO: crbug.com/324586211 - raise the memory limit to avoid OOMs in the
+  # fuzzer harness. This can be removed once the global memory limit is raised.
+  libfuzzer_options = [ "rss_limit_mb=4096" ]
+}
+
 # Fuzzer for blink::WEBPImageDecoder.
 fuzzer_test("blink_webp_decoder_fuzzer") {
   sources = [ "image-decoders/webp/webp_image_decoder_fuzzer.cc" ]
diff --git a/third_party/blink/renderer/platform/bindings/exception_context.h b/third_party/blink/renderer/platform/bindings/exception_context.h
index 0023da6..82d20a2 100644
--- a/third_party/blink/renderer/platform/bindings/exception_context.h
+++ b/third_party/blink/renderer/platform/bindings/exception_context.h
@@ -90,6 +90,13 @@
     return property_name_ ? String(property_name_)
                           : property_name_string_;
   }
+  std::variant<const char*, String> GetPropertyNameVariant() const {
+    DCHECK(!property_name_ || property_name_string_.IsNull());
+    if (property_name_) {
+      return property_name_;
+    }
+    return property_name_string_;
+  }
   int16_t GetArgumentIndex() const { return argument_index_; }
 
   // This is used for a performance hack to reduce the number of construction
diff --git a/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc b/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
index 81cdfc3..92194fc 100644
--- a/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
@@ -44,10 +44,8 @@
     const TransformPaintPropertyNode& root_transform,
     const TransformPaintPropertyNode& local_transform,
     float expansion_ratio) {
-  static const int pixel_distance_to_expand =
-      features::kCullRectPixelDistanceToExpand.Get();
-  static const bool small_scrollers_use_min_cull_rect =
-      features::kSmallScrollersUseMinCullRect.Get();
+  const int pixel_distance_to_expand = features::kCullRectPixelDistanceToExpand.Get();
+  const bool small_scrollers_use_min_cull_rect = features::kSmallScrollersUseMinCullRect.Get();
 
   const int min_expansion = MinimumLocalPixelDistanceToExpand(expansion_ratio);
   if (small_scrollers_use_min_cull_rect &&
diff --git a/third_party/blink/renderer/platform/image-decoders/BUILD.gn b/third_party/blink/renderer/platform/image-decoders/BUILD.gn
index 1a86364..6668b18 100644
--- a/third_party/blink/renderer/platform/image-decoders/BUILD.gn
+++ b/third_party/blink/renderer/platform/image-decoders/BUILD.gn
@@ -129,20 +129,3 @@
     ]
   }
 }
-
-fuzzer_test("blink_bmp_image_decoder_fuzzer") {
-  sources = [ "bmp/bmp_image_decoder_fuzzer.cc" ]
-  deps = [
-    ":image_decoders",
-    "//base",
-    "//third_party/blink/renderer/platform",
-    "//third_party/blink/renderer/platform:blink_fuzzer_test_support",
-    "//third_party/blink/renderer/platform:image_headers",
-    "//third_party/blink/renderer/platform/wtf",
-  ]
-  seed_corpuses = [ "//third_party/blink/web_tests/images/bmp-suite/good" ]
-
-  # TODO: crbug.com/324586211 - raise the memory limit to avoid OOMs in the
-  # fuzzer harness. This can be removed once the global memory limit is raised.
-  libfuzzer_options = [ "rss_limit_mb=4096" ]
-}
diff --git a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_fuzzer.cc b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_fuzzer.cc
index ba81c56..596bf7c 100644
--- a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_fuzzer.cc
+++ b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_fuzzer.cc
@@ -21,28 +21,24 @@
 
 #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
 
+#include <fuzzer/FuzzedDataProvider.h>
+
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/graphics/color_behavior.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h"
 #include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
 #include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
 
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  using blink::BMPImageDecoder;
-  using blink::ColorBehavior;
-  using blink::ImageDecoder;
-  using WTF::SharedBuffer;
+namespace blink {
 
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   static blink::BlinkFuzzerTestSupport test_support;
   blink::test::TaskEnvironment task_environment;
 
-  scoped_refptr<SharedBuffer> buf = SharedBuffer::Create(data, size);
-
-  BMPImageDecoder decoder{ImageDecoder::kAlphaNotPremultiplied,
-                          ColorBehavior::kTransformToSRGB,
-                          ImageDecoder::kNoDecodedImageByteLimit};
-  decoder.SetData(buf, /*all_data_received=*/true);
-  decoder.DecodeFrameBufferAtIndex(0);
+  FuzzedDataProvider fdp(data, size);
+  FuzzDecoder(DecoderType::kBmpDecoder, fdp);
   return 0;
 }
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.cc
new file mode 100644
index 0000000..b08b44c
--- /dev/null
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.cc
@@ -0,0 +1,75 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h"
+
+#include "third_party/blink/renderer/platform/graphics/color_behavior.h"
+#include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h"
+#include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"
+
+namespace blink {
+
+std::unique_ptr<ImageDecoder> CreateImageDecoder(DecoderType decoder_type,
+                                                 FuzzedDataProvider& fdp) {
+  ImageDecoder::AlphaOption option = fdp.ConsumeBool()
+                                         ? ImageDecoder::kAlphaPremultiplied
+                                         : ImageDecoder::kAlphaNotPremultiplied;
+  int which_color_behavior = fdp.ConsumeIntegralInRange(1, 3);
+  ColorBehavior behavior;
+  switch (which_color_behavior) {
+    case 1:
+      behavior = ColorBehavior::kIgnore;
+      break;
+    case 2:
+      behavior = ColorBehavior::kTag;
+      break;
+    case 3:
+      behavior = ColorBehavior::kTransformToSRGB;
+      break;
+    default:
+      behavior = ColorBehavior::kIgnore;
+      break;
+  }
+  wtf_size_t max_decoded_bytes = fdp.ConsumeIntegral<uint32_t>();
+
+  switch (decoder_type) {
+    case DecoderType::kBmpDecoder:
+      return std::make_unique<BMPImageDecoder>(option, behavior,
+                                               max_decoded_bytes);
+    case DecoderType::kJpegDecoder: {
+      cc::AuxImage aux_image_type =
+          fdp.ConsumeBool() ? cc::AuxImage::kDefault : cc::AuxImage::kGainmap;
+      wtf_size_t offset = fdp.ConsumeIntegral<uint32_t>();
+      return std::make_unique<JPEGImageDecoder>(
+          option, behavior, aux_image_type, max_decoded_bytes, offset);
+    }
+    case DecoderType::kPngDecoder: {
+      ImageDecoder::HighBitDepthDecodingOption decoding_option =
+          fdp.ConsumeBool() ? ImageDecoder::kDefaultBitDepth
+                            : ImageDecoder::kHighBitDepthToHalfFloat;
+      wtf_size_t offset = fdp.ConsumeIntegral<uint32_t>();
+      return std::make_unique<PNGImageDecoder>(
+          option, decoding_option, behavior, max_decoded_bytes, offset);
+    }
+  }
+}
+
+void FuzzDecoder(DecoderType decoder_type, FuzzedDataProvider& fdp) {
+  auto decoder = CreateImageDecoder(decoder_type, fdp);
+  auto remaining_data = fdp.ConsumeRemainingBytes<char>();
+  auto buffer =
+      SharedBuffer::Create(remaining_data.data(), remaining_data.size());
+  const bool kAllDataReceived = true;
+  decoder->SetData(buffer.get(), kAllDataReceived);
+  for (wtf_size_t frame = 0; frame < decoder->FrameCount(); ++frame) {
+    decoder->DecodeFrameBufferAtIndex(frame);
+    if (decoder->Failed()) {
+      return;
+    }
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h
new file mode 100644
index 0000000..d958541
--- /dev/null
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h
@@ -0,0 +1,26 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_IMAGE_DECODER_FUZZER_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_IMAGE_DECODER_FUZZER_UTILS_H_
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+
+namespace blink {
+
+enum class DecoderType {
+  kBmpDecoder,
+  kJpegDecoder,
+  kPngDecoder,
+};
+
+std::unique_ptr<ImageDecoder> CreateImageDecoder(DecoderType decoder_type,
+                                                 FuzzedDataProvider& fdp);
+
+void FuzzDecoder(DecoderType decoder_type, FuzzedDataProvider& fdp);
+
+}  // namespace blink
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_IMAGE_DECODER_FUZZER_UTILS_H_
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_fuzzer.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_fuzzer.cc
index 7baec4c1..e81859a 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_fuzzer.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_fuzzer.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h"
 
+#include <fuzzer/FuzzedDataProvider.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -11,6 +12,7 @@
 
 #include "third_party/blink/renderer/platform/graphics/color_behavior.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h"
 #include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
 #include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
@@ -18,27 +20,10 @@
 
 namespace blink {
 
-std::unique_ptr<ImageDecoder> CreateJPEGDecoder() {
-  // TODO(crbug.com/323934468): Initialize decoder settings dynamically using
-  // fuzzer input.
-  return std::make_unique<JPEGImageDecoder>(
-      ImageDecoder::kAlphaPremultiplied, ColorBehavior::kTransformToSRGB,
-      cc::AuxImage::kDefault, ImageDecoder::kNoDecodedImageByteLimit);
-}
-
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   static BlinkFuzzerTestSupport test_support;
-  test::TaskEnvironment task_environment;
-  auto buffer = SharedBuffer::Create(data, size);
-  auto decoder = CreateJPEGDecoder();
-  const bool kAllDataReceived = true;
-  decoder->SetData(buffer.get(), kAllDataReceived);
-  for (wtf_size_t frame = 0; frame < decoder->FrameCount(); ++frame) {
-    decoder->DecodeFrameBufferAtIndex(frame);
-    if (decoder->Failed()) {
-      return 0;
-    }
-  }
+  FuzzedDataProvider fdp(data, size);
+  FuzzDecoder(DecoderType::kJpegDecoder, fdp);
   return 0;
 }
 
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_fuzzer.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_fuzzer.cc
index f579257..0944f1b 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_fuzzer.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_fuzzer.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"
 
+#include <fuzzer/FuzzedDataProvider.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -27,6 +28,7 @@
 
 #include "third_party/blink/renderer/platform/graphics/color_behavior.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h"
 #include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
 #include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
@@ -34,27 +36,10 @@
 
 namespace blink {
 
-std::unique_ptr<ImageDecoder> CreatePNGDecoder() {
-  // TODO(crbug.com/323934468): Initialize decoder settings dynamically using
-  // fuzzer input.
-  return std::make_unique<PNGImageDecoder>(
-      ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth,
-      ColorBehavior::kTransformToSRGB, ImageDecoder::kNoDecodedImageByteLimit);
-}
-
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   static BlinkFuzzerTestSupport test_support;
-  test::TaskEnvironment task_environment;
-  auto buffer = SharedBuffer::Create(data, size);
-  auto decoder = CreatePNGDecoder();
-  static constexpr bool kAllDataReceived = true;
-  decoder->SetData(buffer.get(), kAllDataReceived);
-  for (wtf_size_t frame = 0; frame < decoder->FrameCount(); ++frame) {
-    decoder->DecodeFrameBufferAtIndex(frame);
-    if (decoder->Failed()) {
-      return 0;
-    }
-  }
+  FuzzedDataProvider fdp(data, size);
+  FuzzDecoder(DecoderType::kPngDecoder, fdp);
   return 0;
 }
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 12e2310e..fb3037d 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1156,7 +1156,7 @@
     {
       // crbug.com/325309578
       name: "CSSRelativeColorSupportsCurrentcolor",
-      status: "test",
+      status: "experimental",
     },
     {
       // Non-standard 'auto' keyword for the CSS resize property. Used for
@@ -1564,13 +1564,6 @@
       name: "DOMExceptionV8CaptureStackTraceDisableWorkaround",
       status: "experimental"
     },
-    // Controls whether DOMParser.parseFromString() attempts to use the
-    // html fast path parser. This flag is to be used as a killswitch in case
-    // of any issues.
-    {
-      name: "DOMParserUsesHTMLFastPathParser",
-      status: "stable"
-    },
     {
       name: "DOMPartsAPI",
       status: "experimental",
@@ -3745,14 +3738,6 @@
       status: "stable",
     },
     {
-      // If enabled, the type to search in a select element will ignore accents.
-      // This should land in M128, and can be cleaned up (assuming no problems)
-      // after M130.
-      // https://crbug.com/349089079
-      name: "SelectTypeToSearchIgnoreAccents",
-      status: "stable",
-    },
-    {
       name: "SendBeaconThrowForBlobWithNonSimpleType",
       public: true,
       status: "stable",
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
index 0aa060b7..6d1abb3b 100644
--- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
+++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
@@ -46,7 +46,6 @@
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/latency/latency_info.h"
 
-using perfetto::protos::pbzero::ChromeLatencyInfo;
 using perfetto::protos::pbzero::TrackEvent;
 
 using ScrollThread = cc::InputHandler::ScrollThread;
@@ -276,10 +275,12 @@
   int64_t trace_id = event->latency_info().trace_id();
   TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
               [trace_id](perfetto::EventContext ctx) {
-                ChromeLatencyInfo* info =
-                    ctx.event()->set_chrome_latency_info();
+                auto* info =
+                    ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                        ->set_chrome_latency_info();
                 info->set_trace_id(trace_id);
-                info->set_step(ChromeLatencyInfo::STEP_HANDLE_INPUT_EVENT_IMPL);
+                info->set_step(perfetto::protos::pbzero::ChromeLatencyInfo2::
+                                   Step::STEP_HANDLE_INPUT_EVENT_IMPL);
                 tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_INOUT,
                                        trace_id);
               });
@@ -570,10 +571,12 @@
   int64_t trace_id = event_with_callback->latency_info().trace_id();
   TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
               [trace_id](perfetto::EventContext ctx) {
-                ChromeLatencyInfo* info =
-                    ctx.event()->set_chrome_latency_info();
+                auto* info =
+                    ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                        ->set_chrome_latency_info();
                 info->set_trace_id(trace_id);
-                info->set_step(ChromeLatencyInfo::STEP_HANDLE_INPUT_EVENT_IMPL);
+                info->set_step(perfetto::protos::pbzero::ChromeLatencyInfo2::
+                                   Step::STEP_HANDLE_INPUT_EVENT_IMPL);
                 tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_INOUT,
                                        trace_id);
               });
diff --git a/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc b/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc
index ac4dabc..cc03b1d 100644
--- a/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc
+++ b/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc
@@ -38,7 +38,6 @@
 #include <android/keycodes.h>
 #endif
 
-using perfetto::protos::pbzero::ChromeLatencyInfo;
 using perfetto::protos::pbzero::TrackEvent;
 
 namespace blink {
@@ -310,10 +309,12 @@
   int64_t trace_id = coalesced_event.latency_info().trace_id();
   TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
               [trace_id](perfetto::EventContext ctx) {
-                ChromeLatencyInfo* info =
-                    ctx.event()->set_chrome_latency_info();
+                auto* info =
+                    ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                        ->set_chrome_latency_info();
                 info->set_trace_id(trace_id);
-                info->set_step(ChromeLatencyInfo::STEP_HANDLE_INPUT_EVENT_MAIN);
+                info->set_step(perfetto::protos::pbzero::ChromeLatencyInfo2::
+                                   Step::STEP_HANDLE_INPUT_EVENT_MAIN);
                 tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_INOUT,
                                        trace_id);
               });
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 1d2ebf5..270a6c8 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -90,6 +90,7 @@
             'base::HashingLRUCache',
             'base::HashInts',
             'base::HeapArray',
+            'base::Hertz',
             'base::HexStringToUInt64',
             'base::Hours',
             'base::i18n::TextDirection',
@@ -1010,6 +1011,12 @@
         ],
     },
     {
+        'paths': ['third_party/blink/renderer/core/css/style_color.cc'],
+        'allowed': [
+            'base::flat_map',
+        ],
+    },
+    {
         'paths': ['third_party/blink/renderer/core/editing/ime'],
         'allowed': [
             'ui::ImeTextSpan',
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 1c76006..2ab6457 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -830,15 +830,6 @@
 crbug.com/357649027 external/wpt/css/css-sizing/range-percent-intrinsic-size-2.html [ Failure ]
 crbug.com/357649027 external/wpt/css/css-sizing/range-percent-intrinsic-size-2a.html [ Failure ]
 
-# Unblock https://crrev.com/c/5836833
-crbug.com/361717594 http/tests/devtools/resource-har-conversion.js [ Pass Failure ]
-crbug.com/361717594 http/tests/devtools/resource-har-headers.js [ Pass Failure ]
-crbug.com/361717594 http/tests/devtools/resource-parameters-ipv6.js [ Crash Pass Failure ]
-crbug.com/361717594 http/tests/devtools/resource-parameters.js [ Pass Failure ]
-crbug.com/361717594 http/tests/devtools/network/har-content.js [ Pass Failure ]
-crbug.com/361717594 http/tests/devtools/network/har-post.js [ Pass Failure ]
-crbug.com/361717594 http/tests/devtools/websocket/har-websocket.js [ Pass Failure ]
-
 ##### This one passes only when it includes an iframe. Removing the iframe makes the test fail.
 crbug.com/327723279 external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-033.html [ Failure ]
 
@@ -1804,6 +1795,7 @@
 # By about a quarter or less of a pixel.
 crbug.com/997202 [ Mac ] virtual/text-antialias/international/bdo-bidi-width.html [ Failure ]
 
+crbug.com/599670 [ Win ] http/tests/devtools/resource-parameters-ipv6.js [ Crash Failure Pass ]
 crbug.com/472330 fast/borders/border-image-outset-split-inline-vertical-lr.html [ Failure ]
 crbug.com/472330 fast/writing-mode/box-shadow-vertical-lr.html [ Failure ]
 crbug.com/472330 fast/writing-mode/box-shadow-vertical-rl.html [ Failure ]
@@ -2634,7 +2626,6 @@
 crbug.com/364677549 external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html [ Crash Pass Timeout ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/364970783 external/wpt/css/css-tables/table-intrinsic-size-003.html [ Failure ]
 crbug.com/364935894 [ Mac14 ] external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html [ Timeout ]
 crbug.com/364935894 [ Mac12 ] external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html [ Timeout ]
 [ Linux ] wpt_internal/html/semantics/forms/the-select-element/stylable-select/select-only-picker-opt-in.tentative.html [ Failure ]
@@ -2753,7 +2744,6 @@
 crbug.com/356955226 external/wpt/fedcm/lfedcm-identity.create-store-collect.tentative.sub.https.html [ Timeout ]
 crbug.com/356955226 external/wpt/fedcm/lfedcm-identity.discovery.tentative.sub.https.html [ Timeout ]
 crbug.com/356428750 external/wpt/css/css-backgrounds/background-clip/clip-text-animated-text.html [ Failure ]
-crbug.com/356441927 [ Mac11 ] external/wpt/css/css-masking/animations/mask-border-outset-interpolation.html [ Failure Timeout ]
 crbug.com/356428750 virtual/threaded/external/wpt/css/css-backgrounds/background-clip/clip-text-animated-text.html [ Failure ]
 crbug.com/356436572 external/wpt/css/css-box/margin-trim/block-container-block-end-collapsed-margins.html [ Failure ]
 crbug.com/356436572 external/wpt/css/css-box/margin-trim/block-container-block-end-self-collapsing-item-has-larger-block-end.html [ Failure ]
@@ -3152,7 +3142,6 @@
 crbug.com/626703 [ Mac13 ] virtual/third-party-storage-partitioning/external/wpt/IndexedDB/reading-autoincrement-indexes-cursors.any.serviceworker.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/third-party-storage-partitioning/external/wpt/IndexedDB/reading-autoincrement-indexes.any.sharedworker.html [ Timeout ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/web-locks/bfcache/sharedworker-multiple.tentative.https.html [ Skip Timeout ]
-crbug.com/626703 virtual/composite-clip-path-animation/external/wpt/css/css-masking/clip-path/animations/clip-path-rect-interpolation-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-color/border-color-currentcolor.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-rtl-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-rtl-002.html [ Failure ]
@@ -3174,10 +3163,8 @@
 crbug.com/626703 external/wpt/editing/crashtests/insertparagraph-in-listitem-in-svg-followed-by-collapsible-spaces.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/fetch/api/cors/cors-keepalive.any.html [ Skip Timeout ]
 crbug.com/626703 [ Mac12 ] external/wpt/fetch/api/cors/cors-keepalive.any.html [ Skip Timeout ]
-crbug.com/626703 [ Mac13 Release ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/animation-timeline-view-functional-notation.tentative.html [ Skip Timeout ]
 crbug.com/626703 external/wpt/css/css-backgrounds/box-shadow-border-radius-001.html [ Failure ]
 crbug.com/626703 virtual/threaded/external/wpt/css/css-backgrounds/box-shadow-border-radius-001.html [ Failure ]
-crbug.com/626703 [ Mac12 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/animation-timeline-view-functional-notation.tentative.html [ Skip Timeout ]
 crbug.com/626703 [ Mac13 Release ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
 crbug.com/626703 [ Mac13-arm64 Release ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/svg/pservers/reftests/pattern-opacity-01.svg [ Failure ]
@@ -6690,9 +6677,6 @@
 # Gardnener 2023-07-07
 crbug.com/1462462 http/tests/history/replacestate-post-to-get-2.html [ Failure Pass Timeout ]
 
-# Gardener 2023-07-10
-crbug.com/1463743 external/wpt/scroll-animations/css/pseudo-on-scroller.html [ Failure Pass ]
-
 # WPT for the Initiator attribute in RT API which is currently under development
 external/wpt/resource-timing/tentative/document-initiated.html [ Failure Timeout ]
 external/wpt/resource-timing/tentative/script-initiated.html [ Failure Timeout ]
@@ -7740,6 +7724,7 @@
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-a98rgb-01.html [ Crash Failure Timeout ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-displayp3-01.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-hsl-01.html [ Crash Failure Timeout ]
+crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-hsl-02.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-hwb-01.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-lab-01.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-lch-01.html [ Crash Failure ]
@@ -7749,11 +7734,9 @@
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rec2020-01.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rec2020-02.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rgb-01.html [ Crash Failure ]
+crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rgb-02.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-xyzd50-01.html [ Crash Failure ]
 crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-xyzd65-01.html [ Crash Failure ]
-# Failures with or without CSSRelativeColorSupportsCurrentcolor enabled
-crbug.com/325309578 external/wpt/css/css-color/relative-currentcolor-hsl-02.html [ Crash Failure ]
-crbug.com/325309578 external/wpt/css/css-color/relative-currentcolor-rgb-02.html [ Crash Failure ]
 
 # Branch Gardener 2024-04-10
 crbug.com/333639341 [ Fuchsia ] fast/writing-mode/english-lr-text.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-relative-color.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-relative-color.html
index 4997d65..83806e2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-relative-color.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-relative-color.html
@@ -219,6 +219,7 @@
 
   // Testing with 'currentColor'
   fuzzy_test_computed_color_using_currentcolor(`hsl(from currentColor h s l)`, `color(srgb 0.4 0.2 0.6)`);
+  fuzzy_test_computed_color_using_currentcolor(`hsl(from currentColor calc((h / 360) * 360deg) s l)`, `color(srgb 0.2 0.2 0.6)`);
 
   // color-mix
   fuzzy_test_computed_color(`hsl(from color-mix(in srgb, red, red) h s l / alpha)`, `color(srgb 1 0 0)`);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-filtering.sub.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-filtering.sub.any.js
index a26eacc..5f94924 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-filtering.sub.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-filtering.sub.any.js
@@ -12,7 +12,6 @@
       } else {
         assert_false(resp.headers.has(headerName), "UA should exclude " + headerName + " header from response");
       }
-      test.done();
     });
   }, "CORS filter on " + headerName + " header");
 }
@@ -36,7 +35,6 @@
       } else {
         assert_false(resp.headers.has(headerName), "UA should exclude " + headerName + " header from response");
       }
-      test.done();
     });
   }, title);
 }
@@ -54,16 +52,14 @@
 corsFilter(url, "Age", "27", true);
 corsFilter(url, "Server", "wptServe" , true);
 corsFilter(url, "Warning", "Mind the gap" , true);
-corsFilter(url, "Set-Cookie", "name=value" , true);
-corsFilter(url, "Set-Cookie2", "name=value" , true);
+corsFilter(url, "Set-Cookie", "name=value; max-age=0", true);
+corsFilter(url, "Set-Cookie2", "name=value; max-age=0", true);
 
 corsExposeFilter(url, "Age", "27", false);
 corsExposeFilter(url, "Server", "wptServe" , false);
 corsExposeFilter(url, "Warning", "Mind the gap" , false);
 
-corsExposeFilter(url, "Set-Cookie", "name=value" , true);
-corsExposeFilter(url, "Set-Cookie2", "name=value" , true);
-corsExposeFilter(url, "Set-Cookie", "name=value" , true, true);
-corsExposeFilter(url, "Set-Cookie2", "name=value" , true, true);
-
-done();
+corsExposeFilter(url, "Set-Cookie", "name=value; max-age=0" , true);
+corsExposeFilter(url, "Set-Cookie2", "name=value; max-age=0" , true);
+corsExposeFilter(url, "Set-Cookie", "name=value; max-age=0" , true, true);
+corsExposeFilter(url, "Set-Cookie2", "name=value; max-age=0" , true, true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/buffer.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/buffer.https.any.js
index 279a821..9a91f0b 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/buffer.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/buffer.https.any.js
@@ -57,7 +57,7 @@
 
     try {
       const mlBuffer =
-          await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 3]});
+          await mlContext.createTensor({dataType: 'int32', dimensions: [2, 3]});
     } catch (e) {
       throw new AssertionError(
           `Unable to create buffer for ${variant} variant. ${e}`);
@@ -65,7 +65,7 @@
   });
   promise_test(async () => {
     let mlBuffer =
-        await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 3]});
+        await mlContext.createTensor({dataType: 'int32', dimensions: [2, 3]});
     mlBuffer.destroy();
     mlBuffer.destroy();
   }, `${testName}`);
@@ -91,11 +91,11 @@
     if (!mlContext.opSupportLimits().input.dataTypes.includes(
             bufferDescriptor.dataType)) {
       await promise_rejects_js(
-          t, TypeError, mlContext.createBuffer(bufferDescriptor));
+          t, TypeError, mlContext.createTensor(bufferDescriptor));
       return;
     }
 
-    const mlBuffer = await mlContext.createBuffer(bufferDescriptor);
+    const mlBuffer = await mlContext.createTensor(bufferDescriptor);
     assert_equals(
         mlBuffer.dataType, bufferDescriptor.dataType,
         'buffer data types do not match');
@@ -123,7 +123,7 @@
   });
   promise_test(async t => {
     await promise_rejects_js(
-        t, TypeError, mlContext.createBuffer(bufferDescriptor));
+        t, TypeError, mlContext.createTensor(bufferDescriptor));
   }, `${testName} / ${bufferDescriptor.dataType}`);
 };
 
@@ -134,7 +134,7 @@
  * @param {Array} expected - Array of the expected data in the buffer.
  */
 const assert_buffer_data_equals = async (mlContext, mlBuffer, expected) => {
-  const actual = await mlContext.readBuffer(mlBuffer);
+  const actual = await mlContext.readTensor(mlBuffer);
   assert_array_equals(
       new expected.constructor(actual), expected,
       'Read buffer data equals expected data.');
@@ -156,7 +156,7 @@
 
     try {
       const mlBuffer =
-          await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 3]});
+          await mlContext.createTensor({dataType: 'int32', dimensions: [2, 3]});
     } catch (e) {
       throw new AssertionError(
           `Unable to create buffer for ${variant} variant. ${e}`);
@@ -169,7 +169,7 @@
       dimensions: [1],
       usage: MLTensorUsage.WRITE_TO,
     };
-    let mlBuffer = await mlContext.createBuffer(bufferDescriptor);
+    let mlBuffer = await mlContext.createTensor(bufferDescriptor);
 
     const bufferByteLength = sizeOfDescriptor(bufferDescriptor);
     let arrayBuffer = new ArrayBuffer(bufferByteLength);
@@ -177,38 +177,38 @@
     // Writing with a size that goes past that source buffer length.
     assert_throws_js(
         TypeError,
-        () => mlContext.writeBuffer(
+        () => mlContext.writeTensor(
             mlBuffer, new Uint8Array(arrayBuffer), /*srcOffset=*/ 0,
             /*srcSize=*/ bufferByteLength + 1));
     assert_throws_js(
         TypeError,
-        () => mlContext.writeBuffer(
+        () => mlContext.writeTensor(
             mlBuffer, new Uint8Array(arrayBuffer), /*srcOffset=*/ 3,
             /*srcSize=*/ bufferByteLength));
 
     // Writing with a source offset that is out of range of the source size.
     assert_throws_js(
         TypeError,
-        () => mlContext.writeBuffer(
+        () => mlContext.writeTensor(
             mlBuffer, new Uint8Array(arrayBuffer),
             /*srcOffset=*/ bufferByteLength + 1));
 
     // Writing with a source offset that is out of range of implicit copy size.
     assert_throws_js(
         TypeError,
-        () => mlContext.writeBuffer(
+        () => mlContext.writeTensor(
             mlBuffer, new Uint8Array(arrayBuffer),
             /*srcOffset=*/ bufferByteLength + 1, /*srcSize=*/ undefined));
 
     assert_throws_js(
         TypeError,
-        () => mlContext.writeBuffer(
+        () => mlContext.writeTensor(
             mlBuffer, new Uint8Array(arrayBuffer), /*srcOffset=*/ undefined,
             /*srcSize=*/ bufferByteLength + 1));
 
     assert_throws_js(
         TypeError,
-        () => mlContext.writeBuffer(
+        () => mlContext.writeTensor(
             mlBuffer, Uint8Array.from([0xEE, 0xEE, 0xEE, 0xEE, 0xEE])));
   }, `${testName} / error`);
 
@@ -218,14 +218,14 @@
       dimensions: [2, 2],
       usage: MLTensorUsage.WRITE_TO,
     };
-    let mlBuffer = await mlContext.createBuffer(bufferDescriptor);
+    let mlBuffer = await mlContext.createTensor(bufferDescriptor);
 
     // Writing data to a destroyed MLTensor should throw.
     mlBuffer.destroy();
 
     assert_throws_dom(
         'InvalidStateError',
-        () => mlContext.writeBuffer(
+        () => mlContext.writeTensor(
             mlBuffer, new Uint8Array(sizeOfDescriptor(bufferDescriptor))));
   }, `${testName} / destroy`);
 
@@ -235,21 +235,21 @@
       dimensions: [2, 3],
       usage: MLTensorUsage.WRITE_TO,
     };
-    let mlBuffer = await mlContext.createBuffer(bufferDescriptor);
+    let mlBuffer = await mlContext.createTensor(bufferDescriptor);
 
     let anotherMLContext = await navigator.ml.createContext(contextOptions);
-    let anotherMLTensor = await anotherMLContext.createBuffer(bufferDescriptor);
+    let anotherMLTensor = await anotherMLContext.createTensor(bufferDescriptor);
 
     let inputData =
         new Uint8Array(sizeOfDescriptor(bufferDescriptor)).fill(0xAA);
     assert_throws_js(
-        TypeError, () => mlContext.writeBuffer(anotherMLTensor, inputData));
+        TypeError, () => mlContext.writeTensor(anotherMLTensor, inputData));
     assert_throws_js(
-        TypeError, () => anotherMLContext.writeBuffer(mlBuffer, inputData));
+        TypeError, () => anotherMLContext.writeTensor(mlBuffer, inputData));
   }, `${testName} / context_mismatch`);
 
   promise_test(async () => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [1],
       usage: MLTensorUsage.WRITE_TO | MLTensorUsage.READ_FROM,
@@ -257,15 +257,15 @@
 
     // Initialize the buffer.
     const inputData = Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]);
-    mlContext.writeBuffer(mlBuffer, inputData);
+    mlContext.writeTensor(mlBuffer, inputData);
 
     // Writing zero bytes from a zero write size.
-    mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xBB]), 0, 0);
+    mlContext.writeTensor(mlBuffer, Uint8Array.from([0xBB]), 0, 0);
 
     await assert_buffer_data_equals(mlContext, mlBuffer, inputData);
 
     // Writing zero bytes at the end of the buffer.
-    mlContext.writeBuffer(
+    mlContext.writeTensor(
         mlBuffer, Uint32Array.from([0xBBBBBBBB]), /*srcOffset=*/ 1);
 
     await assert_buffer_data_equals(mlContext, mlBuffer, inputData);
@@ -277,7 +277,7 @@
       dimensions: [2, 2],
       usage: MLTensorUsage.WRITE_TO | MLTensorUsage.READ_FROM,
     };
-    let mlBuffer = await mlContext.createBuffer(bufferDescriptor);
+    let mlBuffer = await mlContext.createTensor(bufferDescriptor);
 
     const bufferByteLength = sizeOfDescriptor(bufferDescriptor);
     let inputBuffer = new ArrayBuffer(bufferByteLength);
@@ -286,13 +286,13 @@
     const int32View = new Int32Array(inputBuffer);
     int32View.fill(0xBBBBBBBB);
 
-    mlContext.writeBuffer(mlBuffer, int32View);
+    mlContext.writeTensor(mlBuffer, int32View);
 
     // Writing to a detached buffer should be ignored.
     const detachedBuffer = inputBuffer.transfer();
     assert_true(inputBuffer.detached, 'array buffer should be detached.');
 
-    mlContext.writeBuffer(mlBuffer, inputBuffer);
+    mlContext.writeTensor(mlBuffer, inputBuffer);
 
     await assert_buffer_data_equals(
         mlContext, mlBuffer, new Int32Array(detachedBuffer));
@@ -315,7 +315,7 @@
 
     try {
       const mlBuffer =
-          await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 3]});
+          await mlContext.createTensor({dataType: 'int32', dimensions: [2, 3]});
     } catch (e) {
       throw new AssertionError(
           `Unable to create buffer for ${variant} variant. ${e}`);
@@ -323,7 +323,7 @@
   });
 
   promise_test(async t => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [2, 2],
       usage: MLTensorUsage.READ_FROM,
@@ -333,18 +333,18 @@
     mlBuffer.destroy();
 
     await promise_rejects_dom(
-        t, 'InvalidStateError', mlContext.readBuffer(mlBuffer));
+        t, 'InvalidStateError', mlContext.readTensor(mlBuffer));
   }, `${testName} / read_after_destroy`);
 
   promise_test(async t => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [2, 3],
       usage: MLTensorUsage.READ_FROM,
     });
 
-    let promise = mlContext.readBuffer(mlBuffer);
-    let anotherPromise = mlContext.readBuffer(mlBuffer);
+    let promise = mlContext.readTensor(mlBuffer);
+    let anotherPromise = mlContext.readTensor(mlBuffer);
 
     mlBuffer.destroy();
 
@@ -353,7 +353,7 @@
   }, `${testName} / read_before_destroy`);
 
   promise_test(async () => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [1024],
       usage: MLTensorUsage.READ_FROM,
@@ -364,33 +364,33 @@
   }, `${testName} / uninitialized`);
 
   promise_test(async () => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [1],
       usage: MLTensorUsage.READ_FROM | MLTensorUsage.WRITE_TO,
     });
 
     // Initialize the buffer.
-    mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
+    mlContext.writeTensor(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
 
-    mlContext.writeBuffer(mlBuffer, Uint32Array.from([0xBBBBBBBB]));
+    mlContext.writeTensor(mlBuffer, Uint32Array.from([0xBBBBBBBB]));
     await assert_buffer_data_equals(
         mlContext, mlBuffer, Uint32Array.from([0xBBBBBBBB]));
     ;
   }, `${testName} / full_size`);
 
   promise_test(async () => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [1],
       usage: MLTensorUsage.WRITE_TO | MLTensorUsage.READ_FROM,
     });
 
     // Initialize the buffer.
-    mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
+    mlContext.writeTensor(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
 
     // Writing to the remainder of the buffer from source offset.
-    mlContext.writeBuffer(
+    mlContext.writeTensor(
         mlBuffer, Uint8Array.from([0xCC, 0xCC, 0xBB, 0xBB]),
         /*srcOffset=*/ 2);
     await assert_buffer_data_equals(
@@ -398,17 +398,17 @@
   }, `${testName} / src_offset_only`);
 
   promise_test(async () => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [1],
       usage: MLTensorUsage.WRITE_TO | MLTensorUsage.READ_FROM,
     });
 
     // Initialize the buffer.
-    mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
+    mlContext.writeTensor(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
 
     // Writing with both a source offset and size.
-    mlContext.writeBuffer(
+    mlContext.writeTensor(
         mlBuffer, Uint8Array.from([0xDD, 0xDD, 0xCC, 0xDD]),
         /*srcOffset=*/ 2, /*srcSize=*/ 1);
     await assert_buffer_data_equals(
@@ -416,17 +416,17 @@
   }, `${testName} / src_offset_and_size`);
 
   promise_test(async () => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [1],
       usage: MLTensorUsage.WRITE_TO | MLTensorUsage.READ_FROM,
     });
 
     // Initialize the buffer.
-    mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
+    mlContext.writeTensor(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
 
     // Using an offset allows a larger source buffer to fit.
-    mlContext.writeBuffer(
+    mlContext.writeTensor(
         mlBuffer, Uint8Array.from([0xEE, 0xEE, 0xEE, 0xEE, 0xEE]),
         /*srcOffset=*/ 1);
     await assert_buffer_data_equals(
@@ -434,7 +434,7 @@
   }, `${testName} / larger_src_data`);
 
   promise_test(async () => {
-    let mlBuffer = await mlContext.createBuffer({
+    let mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [1],
       usage: MLTensorUsage.WRITE_TO | MLTensorUsage.READ_FROM,
@@ -443,7 +443,7 @@
     const inputData = [0xAA, 0xAA, 0xAA, 0xAA];
 
     // Writing with a source offset of undefined should be treated as 0.
-    mlContext.writeBuffer(
+    mlContext.writeTensor(
         mlBuffer, Uint8Array.from(inputData), /*srcOffset=*/ undefined,
         /*srcSize=*/ inputData.length);
     await assert_buffer_data_equals(
@@ -456,15 +456,15 @@
       dimensions: [2, 3],
       usage: MLTensorUsage.READ_FROM,
     };
-    let mlBuffer = await mlContext.createBuffer(bufferDescriptor);
+    let mlBuffer = await mlContext.createTensor(bufferDescriptor);
 
     let anotherMLContext = await navigator.ml.createContext(contextOptions);
-    let anotherMLTensor = await anotherMLContext.createBuffer(bufferDescriptor);
+    let anotherMLTensor = await anotherMLContext.createTensor(bufferDescriptor);
 
     await promise_rejects_js(
-        t, TypeError, mlContext.readBuffer(anotherMLTensor));
+        t, TypeError, mlContext.readTensor(anotherMLTensor));
     await promise_rejects_js(
-        t, TypeError, anotherMLContext.readBuffer(mlBuffer));
+        t, TypeError, anotherMLContext.readTensor(mlBuffer));
   }, `${testName} / context_mismatch`);
 };
 
@@ -501,19 +501,19 @@
 
     try {
       const mlBuffer =
-          await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 3]});
+          await mlContext.createTensor({dataType: 'int32', dimensions: [2, 3]});
     } catch (e) {
       throw new AssertionError(
           `Unable to create buffer for ${variant} variant. ${e}`);
     }
 
     inputs = {
-      'lhs': await mlContext.createBuffer(bufferDescriptor),
-      'rhs': await mlContext.createBuffer(bufferDescriptor),
+      'lhs': await mlContext.createTensor(bufferDescriptor),
+      'rhs': await mlContext.createTensor(bufferDescriptor),
     };
     outputs = {
-      'output1': await mlContext.createBuffer(bufferDescriptor),
-      'output2': await mlContext.createBuffer(bufferDescriptor),
+      'output1': await mlContext.createTensor(bufferDescriptor),
+      'output2': await mlContext.createTensor(bufferDescriptor),
     };
   });
 
@@ -524,7 +524,7 @@
     mlContext.dispatch(mlGraph, inputs, outputs);
 
     // Test the wrong context being used for inputs.
-    const lhsBuffer = await anotherMLContext.createBuffer(
+    const lhsBuffer = await anotherMLContext.createTensor(
         getDescriptorFromBuffer(inputs['lhs']));
     assert_throws_js(
         TypeError,
@@ -536,7 +536,7 @@
             outputs));
 
     // Test the wrong context being used for outputs.
-    const outputBuffer1 = await anotherMLContext.createBuffer(
+    const outputBuffer1 = await anotherMLContext.createTensor(
         getDescriptorFromBuffer(outputs['output1']));
     assert_throws_js(TypeError, () => mlContext.dispatch(mlGraph, inputs, {
       'output1': outputBuffer1,
@@ -549,7 +549,7 @@
     mlContext.dispatch(mlGraph, inputs, outputs);
 
     // Input is a different shape.
-    const lhsBuffer = await mlContext.createBuffer({
+    const lhsBuffer = await mlContext.createTensor({
       dataType: inputs['lhs'].dataType,
       // Input rank is too high.
       dimensions: inputs['lhs'].shape.concat([2])
@@ -564,7 +564,7 @@
             },
             outputs));
 
-    const rhsBuffer = await mlContext.createBuffer({
+    const rhsBuffer = await mlContext.createTensor({
       dataType: inputs['rhs'].dataType,
       // Input rank is too low.
       dimensions: inputs['rhs'].shape.slice(1)
@@ -582,7 +582,7 @@
     // Output is a different shape. Dimension value is too large.
     let output1WrongShape = [...outputs['output1'].shape];
     output1WrongShape[0] += 2;
-    const outputBuffer1 = await mlContext.createBuffer(
+    const outputBuffer1 = await mlContext.createTensor(
         {dataType: outputs['output1'].dataType, dimensions: output1WrongShape});
 
     assert_throws_js(TypeError, () => mlContext.dispatch(mlGraph, inputs, {
@@ -593,7 +593,7 @@
     // Output is a different shape. Dimension value is too small.
     let output2WrongShape = [...outputs['output2'].shape];
     output2WrongShape[1] -= 1;
-    const outputBuffer2 = await mlContext.createBuffer(
+    const outputBuffer2 = await mlContext.createTensor(
         {dataType: outputs['output2'].dataType, dimensions: output2WrongShape});
 
     assert_throws_js(TypeError, () => mlContext.dispatch(mlGraph, inputs, {
@@ -614,7 +614,7 @@
         TypeError,
         () => mlContext.dispatch(
             mlGraph, {
-              'lhs': mlContext.createBuffer({
+              'lhs': mlContext.createTensor({
                 dataType: inputWrongDataType,
                 dimensions: inputs['lhs'].shape
               }),
@@ -627,7 +627,7 @@
         () => mlContext.dispatch(
             mlGraph, {
               'lhs': inputs['lhs'],
-              'rhs': mlContext.createBuffer({
+              'rhs': mlContext.createTensor({
                 dataType: inputWrongDataType,
                 dimensions: inputs['rhs'].shape
               }),
@@ -638,7 +638,7 @@
     const outputWrongDataType = 'int32';
     assert_not_equals(outputs['output1'].dataType, outputWrongDataType);
     assert_not_equals(outputs['output2'].dataType, outputWrongDataType);
-    const outputBuffer1 = await mlContext.createBuffer(
+    const outputBuffer1 = await mlContext.createTensor(
         {dataType: outputWrongDataType, dimensions: outputs['output1'].shape});
 
     assert_throws_js(TypeError, () => mlContext.dispatch(mlGraph, inputs, {
@@ -646,7 +646,7 @@
       'output2': outputs['output2'],
     }));
 
-    const outputBuffer2 = await mlContext.createBuffer(
+    const outputBuffer2 = await mlContext.createTensor(
         {dataType: outputWrongDataType, dimensions: outputs['output2'].shape});
 
     assert_throws_js(TypeError, () => mlContext.dispatch(mlGraph, inputs, {
@@ -703,7 +703,7 @@
 
     // Too many named inputs is invalid.
     const anotherRhsBuffer =
-        await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs']));
+        await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs']));
     assert_throws_js(
         TypeError,
         () => mlContext.dispatch(
@@ -720,7 +720,7 @@
     }));
 
     // Too many named outputs is invalid.
-    const anotherOutputBuffer2 = await mlContext.createBuffer(
+    const anotherOutputBuffer2 = await mlContext.createTensor(
         getDescriptorFromBuffer(outputs['output2']));
     assert_throws_js(TypeError, () => mlContext.dispatch(mlGraph, inputs, {
       'output1': outputs['output1'],
@@ -773,30 +773,30 @@
   promise_test(async () => {
     const dispatchInputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
     const dispatch1Outputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     const dispatch2Outputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     // Initialize inputs
     const inputData =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(1.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], inputData);
-    mlContext.writeBuffer(dispatchInputs['rhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['lhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['rhs'], inputData);
 
     // Output_1 = LHS + RHS = 1 + 1 = 2
     mlContext.dispatch(mlGraph, dispatchInputs, dispatch1Outputs);
@@ -824,35 +824,35 @@
   promise_test(async () => {
     const dispatch1Inputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
     const dispatch2Inputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
     const dispatchOutputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     // Initialize inputs
     const input1Data =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(1.0);
-    mlContext.writeBuffer(dispatch1Inputs['lhs'], input1Data);
-    mlContext.writeBuffer(dispatch1Inputs['rhs'], input1Data);
+    mlContext.writeTensor(dispatch1Inputs['lhs'], input1Data);
+    mlContext.writeTensor(dispatch1Inputs['rhs'], input1Data);
 
     const input2Data =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(2.0);
-    mlContext.writeBuffer(dispatch2Inputs['lhs'], input2Data);
-    mlContext.writeBuffer(dispatch2Inputs['rhs'], input2Data);
+    mlContext.writeTensor(dispatch2Inputs['lhs'], input2Data);
+    mlContext.writeTensor(dispatch2Inputs['rhs'], input2Data);
 
     // Output = LHS_1 + RHS_1 = 1 + 1 = 2
     mlContext.dispatch(mlGraph, dispatch1Inputs, dispatchOutputs);
@@ -872,23 +872,23 @@
   promise_test(async () => {
     const dispatchInputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
     const dispatchOutputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     // Initialize inputs
     const inputData =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(1.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], inputData);
-    mlContext.writeBuffer(dispatchInputs['rhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['lhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['rhs'], inputData);
 
     // Output = LHS + RHS = 1 + 1 = 2
     mlContext.dispatch(mlGraph, dispatchInputs, dispatchOutputs);
@@ -906,30 +906,30 @@
   promise_test(async () => {
     const dispatchInputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
     const dispatch1Outputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     const dispatch2Outputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     // Initialize inputs
     const inputData =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(1.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], inputData);
-    mlContext.writeBuffer(dispatchInputs['rhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['lhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['rhs'], inputData);
 
     // Output_1 = LHS + RHS = 1 + 1 = 2
     mlContext.dispatch(mlGraph, dispatchInputs, dispatch1Outputs);
@@ -969,19 +969,19 @@
         await builder.build({'output': builder.sub(lhsOperand, rhsOperand)});
 
     const lhsBuffer =
-        await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs']));
+        await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs']));
     const rhsBuffer =
-        await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs']));
+        await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs']));
 
     const dispatchOutputs = {
-      'output': await mlContext.createBuffer(
+      'output': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1']))
     };
 
     // Initialize inputs
-    mlContext.writeBuffer(
+    mlContext.writeTensor(
         lhsBuffer, new TypedArrayDict['float32'](sizeOfShape(shape)).fill(5.0));
-    mlContext.writeBuffer(
+    mlContext.writeTensor(
         rhsBuffer, new TypedArrayDict['float32'](sizeOfShape(shape)).fill(3.0));
 
     // Output = LHS - RHS = 5 - 3 = 2
@@ -1012,21 +1012,21 @@
   promise_test(async () => {
     const dispatchInputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
-    const outputBuffer1 = await mlContext.createBuffer(
+    const outputBuffer1 = await mlContext.createTensor(
         getDescriptorFromBuffer(outputs['output1']));
-    const outputBuffer2 = await mlContext.createBuffer(
+    const outputBuffer2 = await mlContext.createTensor(
         getDescriptorFromBuffer(outputs['output2']));
 
     // Initialize inputs
     const inputData1 =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(1.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], inputData1);
-    mlContext.writeBuffer(dispatchInputs['rhs'], inputData1);
+    mlContext.writeTensor(dispatchInputs['lhs'], inputData1);
+    mlContext.writeTensor(dispatchInputs['rhs'], inputData1);
 
     // Output = LHS + RHS = 1 + 1 = 2
     mlContext.dispatch(mlGraph, dispatchInputs, {
@@ -1037,12 +1037,12 @@
     // Output = LHS + RHS = 2 + 2 = 4
     const inputData2 =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(2.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], inputData2);
-    mlContext.writeBuffer(dispatchInputs['rhs'], inputData2);
+    mlContext.writeTensor(dispatchInputs['lhs'], inputData2);
+    mlContext.writeTensor(dispatchInputs['rhs'], inputData2);
 
     mlContext.dispatch(mlGraph, dispatchInputs, {
       'output1': outputBuffer1,
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     });
 
@@ -1055,23 +1055,23 @@
   promise_test(async () => {
     const dispatchInputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
     const dispatchOutputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     // Initialize inputs
     const inputData =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(1.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], inputData);
-    mlContext.writeBuffer(dispatchInputs['rhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['lhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['rhs'], inputData);
 
     // Output = LHS + RHS = 1 + 1 = 2
     mlContext.dispatch(mlGraph, dispatchInputs, dispatchOutputs);
@@ -1079,11 +1079,11 @@
     // Check destroyed input buffers cannot be re-used in subsequent dispatches.
     dispatchInputs['lhs'].destroy();
     dispatchInputs['lhs'] =
-        await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs']));
+        await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs']));
 
     const newInputData =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(2.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], newInputData);
+    mlContext.writeTensor(dispatchInputs['lhs'], newInputData);
 
     // Output = LHS + RHS = 2 + 1 = 3
     mlContext.dispatch(mlGraph, dispatchInputs, dispatchOutputs);
@@ -1094,8 +1094,8 @@
 
     dispatchInputs['rhs'].destroy();
     dispatchInputs['rhs'] =
-        await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs']));
-    mlContext.writeBuffer(dispatchInputs['rhs'], newInputData);
+        await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs']));
+    mlContext.writeTensor(dispatchInputs['rhs'], newInputData);
 
     // Output = LHS + RHS = 2 + 2 = 4
     mlContext.dispatch(mlGraph, dispatchInputs, dispatchOutputs);
@@ -1108,23 +1108,23 @@
   promise_test(async () => {
     const dispatchInputs = {
       'lhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['lhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['lhs'])),
       'rhs':
-          await mlContext.createBuffer(getDescriptorFromBuffer(inputs['rhs'])),
+          await mlContext.createTensor(getDescriptorFromBuffer(inputs['rhs'])),
     };
 
     const dispatchOutputs = {
-      'output1': await mlContext.createBuffer(
+      'output1': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output1'])),
-      'output2': await mlContext.createBuffer(
+      'output2': await mlContext.createTensor(
           getDescriptorFromBuffer(outputs['output2'])),
     };
 
     // Initialize inputs
     const inputData =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(1.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], inputData);
-    mlContext.writeBuffer(dispatchInputs['rhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['lhs'], inputData);
+    mlContext.writeTensor(dispatchInputs['rhs'], inputData);
 
     // Output = LHS + RHS = 1 + 1 = 2
     mlContext.dispatch(mlGraph, dispatchInputs, dispatchOutputs);
@@ -1132,12 +1132,12 @@
     // Check destroyed output buffers cannot be re-used in subsequent
     // dispatches.
     dispatchOutputs['output1'].destroy();
-    dispatchOutputs['output1'] = await mlContext.createBuffer(
+    dispatchOutputs['output1'] = await mlContext.createTensor(
         getDescriptorFromBuffer(outputs['output1']));
 
     const newInputData =
         new TypedArrayDict['float32'](sizeOfShape(shape)).fill(2.0);
-    mlContext.writeBuffer(dispatchInputs['lhs'], newInputData);
+    mlContext.writeTensor(dispatchInputs['lhs'], newInputData);
 
     // Output = LHS + RHS = 2 + 1 = 3
     mlContext.dispatch(mlGraph, dispatchInputs, dispatchOutputs);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/byob_readbuffer.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/byob_readbuffer.https.any.js
index d0d721a8..e939f02 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/byob_readbuffer.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/byob_readbuffer.https.any.js
@@ -29,7 +29,7 @@
   }
 
   try {
-    mlBuffer = await mlContext.createBuffer({
+    mlBuffer = await mlContext.createTensor({
       dataType: 'int32',
       dimensions: [2, 4],
       usage: MLTensorUsage.WRITE_TO | MLTensorUsage.READ_FROM,
@@ -39,22 +39,22 @@
         `Unable to create buffer for ${variant} variant. ${e}`);
   }
 
-  mlContext.writeBuffer(mlBuffer, testContents);
+  mlContext.writeTensor(mlBuffer, testContents);
 });
 
 promise_test(async (t) => {
   const arrayBuffer = new ArrayBuffer(testContents.byteLength - 4);
 
   await promise_rejects_js(
-      t, TypeError, mlContext.readBuffer(mlBuffer, arrayBuffer));
-}, `readBuffer() with an ArrayBuffer that is too small should reject`);
+      t, TypeError, mlContext.readTensor(mlBuffer, arrayBuffer));
+}, `readTensor() with an ArrayBuffer that is too small should reject`);
 
 promise_test(async (t) => {
   const typedArray = new Uint32Array(testContents.length - 1);
 
   await promise_rejects_js(
-      t, TypeError, mlContext.readBuffer(mlBuffer, typedArray));
-}, `readBuffer() with a TypedArray that is too small should reject`);
+      t, TypeError, mlContext.readTensor(mlBuffer, typedArray));
+}, `readTensor() with a TypedArray that is too small should reject`);
 
 promise_test(async (t) => {
   const arrayBuffer = new ArrayBuffer(testContents.byteLength);
@@ -63,11 +63,11 @@
   arrayBuffer.transfer();
 
   await promise_rejects_js(
-      t, TypeError, mlContext.readBuffer(mlBuffer, arrayBuffer));
+      t, TypeError, mlContext.readTensor(mlBuffer, arrayBuffer));
 
   await promise_rejects_js(
-      t, TypeError, mlContext.readBuffer(mlBuffer, typedArray));
-}, `readBuffer() with a detached ArrayBuffer should reject`);
+      t, TypeError, mlContext.readTensor(mlBuffer, typedArray));
+}, `readTensor() with a detached ArrayBuffer should reject`);
 
 promise_test(async (t) => {
   const arrayBuffer = new ArrayBuffer(testContents.byteLength);
@@ -75,23 +75,23 @@
 
   const checks = Promise.all([
     promise_rejects_js(
-        t, TypeError, mlContext.readBuffer(mlBuffer, arrayBuffer)),
+        t, TypeError, mlContext.readTensor(mlBuffer, arrayBuffer)),
     promise_rejects_js(
-        t, TypeError, mlContext.readBuffer(mlBuffer, typedArray)),
+        t, TypeError, mlContext.readTensor(mlBuffer, typedArray)),
   ]);
 
   arrayBuffer.transfer();
 
   await checks;
-}, `Detaching an ArrayBuffer while readBuffer() is in progress should reject`);
+}, `Detaching an ArrayBuffer while readTensor() is in progress should reject`);
 
 promise_test(async () => {
   const arrayBuffer = new ArrayBuffer(testContents.byteLength);
 
-  await mlContext.readBuffer(mlBuffer, arrayBuffer);
+  await mlContext.readTensor(mlBuffer, arrayBuffer);
 
   assert_array_equals(new Uint32Array(arrayBuffer), testContents);
-}, `readBuffer() with an ArrayBuffer`);
+}, `readTensor() with an ArrayBuffer`);
 
 promise_test(async () => {
   // Create a slightly larger ArrayBuffer and set up the TypedArray at an
@@ -100,15 +100,15 @@
   const arrayBuffer = new ArrayBuffer(testContents.byteLength + 4);
   const typedArray = new Uint32Array(arrayBuffer, 4);
 
-  await mlContext.readBuffer(mlBuffer, typedArray);
+  await mlContext.readTensor(mlBuffer, typedArray);
 
   assert_array_equals(typedArray, testContents);
-}, `readBuffer() with a TypedArray`);
+}, `readTensor() with a TypedArray`);
 
 promise_test(async () => {
   const arrayBuffer = new ArrayBuffer(testContents.byteLength * 2);
 
-  await mlContext.readBuffer(mlBuffer, arrayBuffer);
+  await mlContext.readTensor(mlBuffer, arrayBuffer);
 
   assert_array_equals(
       new Uint32Array(arrayBuffer).subarray(0, testContents.length),
@@ -118,7 +118,7 @@
       new Uint32Array(arrayBuffer)
           .subarray(testContents.length, testContents.length * 2),
       new Uint32Array(testContents.length));
-}, `readBuffer() with a larger ArrayBuffer`);
+}, `readTensor() with a larger ArrayBuffer`);
 
 promise_test(async () => {
   // Create a slightly larger ArrayBuffer and set up the TypedArray at an
@@ -127,7 +127,7 @@
   const arrayBuffer = new ArrayBuffer(testContents.byteLength * 2 + 4);
   const typedArray = new Uint32Array(arrayBuffer, 4);
 
-  await mlContext.readBuffer(mlBuffer, typedArray);
+  await mlContext.readTensor(mlBuffer, typedArray);
 
   assert_array_equals(
       typedArray.subarray(0, testContents.length), testContents);
@@ -135,10 +135,10 @@
   assert_array_equals(
       typedArray.subarray(testContents.length, testContents.length * 2),
       new Uint32Array(testContents.length));
-}, `readBuffer() with a larger TypedArray`);
+}, `readTensor() with a larger TypedArray`);
 
 promise_test(async (t) => {
-  const buffer = await mlContext.createBuffer({
+  const buffer = await mlContext.createTensor({
     dataType: 'int32',
     dimensions: [2, 2],
     usage: MLTensorUsage.READ_FROM,
@@ -150,13 +150,13 @@
   buffer.destroy();
 
   await promise_rejects_dom(
-      t, 'InvalidStateError', mlContext.readBuffer(buffer, arrayBuffer));
+      t, 'InvalidStateError', mlContext.readTensor(buffer, arrayBuffer));
   await promise_rejects_dom(
-      t, 'InvalidStateError', mlContext.readBuffer(buffer, arrayBufferView));
-}, `readBuffer() rejects on a destroyed MLTensor`);
+      t, 'InvalidStateError', mlContext.readTensor(buffer, arrayBufferView));
+}, `readTensor() rejects on a destroyed MLTensor`);
 
 promise_test(async (t) => {
-  const buffer = await mlContext.createBuffer({
+  const buffer = await mlContext.createTensor({
     dataType: 'int32',
     dimensions: [2, 2],
     usage: MLTensorUsage.READ_FROM,
@@ -166,12 +166,12 @@
 
   const checks = Promise.all([
     promise_rejects_dom(
-        t, 'InvalidStateError', mlContext.readBuffer(buffer, arrayBuffer)),
+        t, 'InvalidStateError', mlContext.readTensor(buffer, arrayBuffer)),
     promise_rejects_dom(
-        t, 'InvalidStateError', mlContext.readBuffer(buffer, arrayBufferView)),
+        t, 'InvalidStateError', mlContext.readTensor(buffer, arrayBufferView)),
   ]);
 
   buffer.destroy();
 
   await checks;
-}, `readBuffer() rejects when the MLTensor is destroyed`);
+}, `readTensor() rejects when the MLTensor is destroyed`);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/parallel-dispatch.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/parallel-dispatch.https.any.js
index 11ff41a..32189f9 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/parallel-dispatch.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/parallel-dispatch.https.any.js
@@ -39,35 +39,35 @@
   const [mlGraph, inputBuffer1, inputBuffer2, outputBuffer] =
       await Promise.all([
         buildMulGraph(mlContext, operandDescriptor, 2),
-        mlContext.createBuffer(operandDescriptor),
-        mlContext.createBuffer(operandDescriptor),
-        mlContext.createBuffer(operandDescriptor)
+        mlContext.createTensor(operandDescriptor),
+        mlContext.createTensor(operandDescriptor),
+        mlContext.createTensor(operandDescriptor)
       ]);
 
-  mlContext.writeBuffer(inputBuffer1, Float32Array.from([1]));
-  mlContext.writeBuffer(inputBuffer2, Float32Array.from([10]));
+  mlContext.writeTensor(inputBuffer1, Float32Array.from([1]));
+  mlContext.writeTensor(inputBuffer2, Float32Array.from([10]));
 
-  let readBufferPromises = [];
+  let readTensorPromises = [];
 
   mlContext.dispatch(
       mlGraph, {'input': inputBuffer1}, {'output': outputBuffer});
 
   // Don't await buffer readback before dispatching again.
-  readBufferPromises.push(mlContext.readBuffer(outputBuffer));
+  readTensorPromises.push(mlContext.readTensor(outputBuffer));
 
   mlContext.dispatch(
       mlGraph, {'input': inputBuffer2}, {'output': outputBuffer});
 
-  readBufferPromises.push(mlContext.readBuffer(outputBuffer));
+  readTensorPromises.push(mlContext.readTensor(outputBuffer));
 
   const actualOutputs =
-      await Promise.all(readBufferPromises.map(async (promise) => {
+      await Promise.all(readTensorPromises.map(async (promise) => {
         const output = await promise;
         return new Float32Array(output)[0];
       }));
 
   assert_array_equals(actualOutputs, [2, 20]);
-}, 'dispatch queues behind readBuffer');
+}, 'dispatch queues behind readTensor');
 
 promise_test(async () => {
   const operandDescriptor = {
@@ -81,16 +81,16 @@
   const testInputs = [1, 2, 3, 4];
   const actualOutputs = await Promise.all(testInputs.map(async (input) => {
     const [inputBuffer, outputBuffer] = await Promise.all([
-      mlContext.createBuffer(operandDescriptor),
-      mlContext.createBuffer(operandDescriptor)
+      mlContext.createTensor(operandDescriptor),
+      mlContext.createTensor(operandDescriptor)
     ]);
 
-    mlContext.writeBuffer(inputBuffer, Float32Array.from([input]));
+    mlContext.writeTensor(inputBuffer, Float32Array.from([input]));
 
     mlContext.dispatch(
         mlGraph, {'input': inputBuffer}, {'output': outputBuffer});
 
-    const output = await mlContext.readBuffer(outputBuffer);
+    const output = await mlContext.readTensor(outputBuffer);
     return new Float32Array(output)[0];
   }));
 
@@ -110,25 +110,25 @@
   const inputAndOutputBuffers =
       await Promise.all(testInputs.map(async (testInput) => {
         const [inputBuffer, outputBuffer] = await Promise.all([
-          mlContext.createBuffer(operandDescriptor),
-          mlContext.createBuffer(operandDescriptor)
+          mlContext.createTensor(operandDescriptor),
+          mlContext.createTensor(operandDescriptor)
         ]);
 
-        mlContext.writeBuffer(inputBuffer, Float32Array.from([testInput]));
+        mlContext.writeTensor(inputBuffer, Float32Array.from([testInput]));
         return [inputBuffer, outputBuffer];
       }));
 
   // dispatch/read, dispatch/read, ...
-  let readBufferPromises = [];
+  let readTensorPromises = [];
   for (let i = 0; i < testInputs.length; i++) {
     mlContext.dispatch(
         mlGraph, {'input': inputAndOutputBuffers[i][0]},
         {'output': inputAndOutputBuffers[i][1]});
-    readBufferPromises.push(mlContext.readBuffer(inputAndOutputBuffers[i][1]));
+    readTensorPromises.push(mlContext.readTensor(inputAndOutputBuffers[i][1]));
   };
 
   const actualOutputs =
-      await Promise.all(readBufferPromises.map(async (promise) => {
+      await Promise.all(readTensorPromises.map(async (promise) => {
         const output = await promise;
         return new Float32Array(output)[0];
       }));
@@ -149,11 +149,11 @@
   const inputAndOutputBuffers =
       await Promise.all(testInputs.map(async (testInput) => {
         const [inputBuffer, outputBuffer] = await Promise.all([
-          mlContext.createBuffer(operandDescriptor),
-          mlContext.createBuffer(operandDescriptor)
+          mlContext.createTensor(operandDescriptor),
+          mlContext.createTensor(operandDescriptor)
         ]);
 
-        mlContext.writeBuffer(inputBuffer, Float32Array.from([testInput]));
+        mlContext.writeTensor(inputBuffer, Float32Array.from([testInput]));
         return [inputBuffer, outputBuffer];
       }));
 
@@ -167,7 +167,7 @@
   // read/read...
   const actualOutputs = await Promise.all(
       inputAndOutputBuffers.map(async (inputAndOutputBuffer) => {
-        const output = await mlContext.readBuffer(inputAndOutputBuffer[1]);
+        const output = await mlContext.readTensor(inputAndOutputBuffer[1]);
         return new Float32Array(output)[0];
       }));
 
@@ -183,14 +183,14 @@
   const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 2);
 
   const buffers = await Promise.all([
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor)
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor)
   ]);
 
-  mlContext.writeBuffer(buffers[0], Float32Array.from([1]));
+  mlContext.writeTensor(buffers[0], Float32Array.from([1]));
 
   // dispatch/dispatch...
   for (let i = 0; i < buffers.length - 1; i++) {
@@ -200,7 +200,7 @@
 
   // read/read...
   const actualOutputs = await Promise.all(buffers.map(async (buffer) => {
-    const output = await mlContext.readBuffer(buffer);
+    const output = await mlContext.readTensor(buffer);
     return new Float32Array(output)[0];
   }));
 
@@ -220,25 +220,25 @@
       await Promise.all(testInputs.map(async (testInput) => {
         const [graph, inputBuffer, outputBuffer] = await Promise.all([
           buildMulGraph(mlContext, operandDescriptor, testInput),
-          mlContext.createBuffer(operandDescriptor),
-          mlContext.createBuffer(operandDescriptor)
+          mlContext.createTensor(operandDescriptor),
+          mlContext.createTensor(operandDescriptor)
         ]);
 
-        mlContext.writeBuffer(inputBuffer, Float32Array.from([testInput]));
+        mlContext.writeTensor(inputBuffer, Float32Array.from([testInput]));
         return [graph, inputBuffer, outputBuffer];
       }));
 
   // dispatch/read, dispatch/read, ...
-  let readBufferPromises = [];
+  let readTensorPromises = [];
   for (let i = 0; i < graphsAndBuffers.length; i++) {
     mlContext.dispatch(
         graphsAndBuffers[i][0], {'input': graphsAndBuffers[i][1]},
         {'output': graphsAndBuffers[i][2]});
-    readBufferPromises.push(mlContext.readBuffer(graphsAndBuffers[i][2]));
+    readTensorPromises.push(mlContext.readTensor(graphsAndBuffers[i][2]));
   };
 
   const actualOutputs =
-      await Promise.all(readBufferPromises.map(async (promise) => {
+      await Promise.all(readTensorPromises.map(async (promise) => {
         const output = await promise;
         return new Float32Array(output)[0];
       }));
@@ -259,11 +259,11 @@
       await Promise.all(testInputs.map(async (testInput) => {
         const [graph, inputBuffer, outputBuffer] = await Promise.all([
           buildMulGraph(mlContext, operandDescriptor, testInput * 2),
-          mlContext.createBuffer(operandDescriptor),
-          mlContext.createBuffer(operandDescriptor)
+          mlContext.createTensor(operandDescriptor),
+          mlContext.createTensor(operandDescriptor)
         ]);
 
-        mlContext.writeBuffer(inputBuffer, Float32Array.from([testInput]));
+        mlContext.writeTensor(inputBuffer, Float32Array.from([testInput]));
         return [graph, inputBuffer, outputBuffer];
       }));
 
@@ -277,7 +277,7 @@
   // read/read...
   const actualOutputs =
       await Promise.all(graphsAndBuffers.map(async (graphAndBuffers) => {
-        const output = await mlContext.readBuffer(graphAndBuffers[2]);
+        const output = await mlContext.readTensor(graphAndBuffers[2]);
         return new Float32Array(output)[0];
       }));
 
@@ -296,14 +296,14 @@
   }));
 
   const buffers = await Promise.all([
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor)
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor)
   ]);
 
-  mlContext.writeBuffer(buffers[0], Float32Array.from([1]));
+  mlContext.writeTensor(buffers[0], Float32Array.from([1]));
 
   // dispatch/dispatch...
   for (let i = 0; i < buffers.length - 1; i++) {
@@ -313,7 +313,7 @@
 
   // read/read...
   const actualOutputs = await Promise.all(buffers.map(async (buffer) => {
-    const output = await mlContext.readBuffer(buffer);
+    const output = await mlContext.readTensor(buffer);
     return new Float32Array(output)[0];
   }));
 
@@ -332,12 +332,12 @@
   }));
 
   const buffers = await Promise.all([
-    mlContext.createBuffer(operandDescriptor),
-    mlContext.createBuffer(operandDescriptor)
+    mlContext.createTensor(operandDescriptor),
+    mlContext.createTensor(operandDescriptor)
   ]);
 
   // Write to the buffer which will be initially used as an input.
-  mlContext.writeBuffer(buffers[0], Float32Array.from([1]));
+  mlContext.writeTensor(buffers[0], Float32Array.from([1]));
 
   // Double the value in one buffer, sticking the result in the other buffer.
   //
@@ -359,7 +359,7 @@
 
   // read/read...
   const actualOutputs = await Promise.all(buffers.map(async (buffer) => {
-    const output = await mlContext.readBuffer(buffer);
+    const output = await mlContext.readTensor(buffer);
     return new Float32Array(output)[0];
   }));
 
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyContext.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyContext.https.any.js
index d50725a..c4ba478 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyContext.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyContext.https.any.js
@@ -85,10 +85,10 @@
   const graph =
       await builder.build({'output': builder.sub(lhsOperand, rhsOperand)});
 
-  const lhsBuffer = await context.createBuffer(operandType);
-  const rhsBuffer = await context.createBuffer(operandType);
+  const lhsBuffer = await context.createTensor(operandType);
+  const rhsBuffer = await context.createTensor(operandType);
 
-  const dispatchOutputs = {'output': await context.createBuffer(operandType)};
+  const dispatchOutputs = {'output': await context.createTensor(operandType)};
   context.destroy();
   assert_throws_dom('InvalidStateError', () => {
     context.dispatch(
@@ -109,10 +109,10 @@
   const graph =
       await builder.build({'output': builder.sub(lhsOperand, rhsOperand)});
 
-  const lhsBuffer = await context.createBuffer(operandType);
-  const rhsBuffer = await context.createBuffer(operandType);
+  const lhsBuffer = await context.createTensor(operandType);
+  const rhsBuffer = await context.createTensor(operandType);
 
-  const dispatchOutputs = {'output': await context.createBuffer(operandType)};
+  const dispatchOutputs = {'output': await context.createTensor(operandType)};
   context.dispatch(
       graph, {
         'lhs': lhsBuffer,
@@ -127,38 +127,38 @@
   context.destroy();
   promise_rejects_dom(
       t, 'InvalidStateError',
-      context.createBuffer({dataType: 'float32', dimensions: [1]}));
+      context.createTensor({dataType: 'float32', dimensions: [1]}));
 }, 'Destroyed context can not create buffer.');
 
 promise_test(async t => {
   const context = await navigator.ml.createContext(contextOptions);
-  const buffer = await context.createBuffer({
+  const buffer = await context.createTensor({
     dataType: 'float32',
     dimensions: [1],
     usage: MLTensorUsage.READ_FROM,
   });
   context.destroy();
-  promise_rejects_dom(t, 'InvalidStateError', context.readBuffer(buffer));
+  promise_rejects_dom(t, 'InvalidStateError', context.readTensor(buffer));
 }, 'Destroyed context can not read buffer.');
 
 promise_test(async t => {
   const context = await navigator.ml.createContext(contextOptions);
-  const buffer = await context.createBuffer({
+  const buffer = await context.createTensor({
     dataType: 'float32',
     dimensions: [1],
     usage: MLTensorUsage.READ_FROM,
   });
-  let promise = context.readBuffer(buffer);
+  let promise = context.readTensor(buffer);
   context.destroy();
   promise_rejects_dom(t, 'InvalidStateError', promise);
-}, 'Pending promise of readbuffer() will be rejected immediately when context is destroyed.');
+}, 'Pending promise of readtensor() will be rejected immediately when context is destroyed.');
 
 promise_test(async t => {
   const context = await navigator.ml.createContext(contextOptions);
   // Destroying another context doesn't impact the first context.
   const another_context = await navigator.ml.createContext(contextOptions);
   another_context.destroy();
-  const buffer = await context.createBuffer({
+  const buffer = await context.createTensor({
     dataType: 'float32',
     dimensions: [1],
     usage: MLTensorUsage.WRITE_TO,
@@ -166,6 +166,6 @@
   let arrayBuffer = new ArrayBuffer(4);
   context.destroy();
   assert_throws_dom('InvalidStateError', () => {
-    context.writeBuffer(buffer, new Uint8Array(arrayBuffer));
+    context.writeTensor(buffer, new Uint8Array(arrayBuffer));
   });
 }, 'Destroyed context can not write buffer.');
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyGraph.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyGraph.https.any.js
index 7dfadfe..c954c720 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyGraph.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/destroyGraph.https.any.js
@@ -84,9 +84,9 @@
   const graph =
       await builder.build({'output': builder.mul(lhsOperand, rhsOperand)});
 
-  const lhsBuffer = await context.createBuffer(operandType);
-  const rhsBuffer = await context.createBuffer(operandType);
-  const dispatchOutputs = {'output': await context.createBuffer(operandType)};
+  const lhsBuffer = await context.createTensor(operandType);
+  const rhsBuffer = await context.createTensor(operandType);
+  const dispatchOutputs = {'output': await context.createTensor(operandType)};
 
   graph.destroy();
   assert_throws_dom('InvalidStateError', () => {
@@ -107,25 +107,25 @@
   const graph =
       await builder.build({'output': builder.mul(lhsOperand, rhsOperand)});
 
-  const lhsBuffer = await context.createBuffer({
+  const lhsBuffer = await context.createTensor({
     dataType: 'float32',
     dimensions: [1],
     usage: MLTensorUsage.WRITE_TO,
   });
-  const rhsBuffer = await context.createBuffer({
+  const rhsBuffer = await context.createTensor({
     dataType: 'float32',
     dimensions: [1],
     usage: MLTensorUsage.WRITE_TO,
   });
-  const outputBuffer = await context.createBuffer({
+  const outputBuffer = await context.createTensor({
     dataType: 'float32',
     dimensions: [1],
     usage: MLTensorUsage.READ_FROM,
   });
   // Initialize inputs
   const inputData = new Float32Array(1).fill(2.0);
-  context.writeBuffer(lhsBuffer, inputData);
-  context.writeBuffer(rhsBuffer, inputData);
+  context.writeTensor(lhsBuffer, inputData);
+  context.writeTensor(rhsBuffer, inputData);
   context.dispatch(
       graph, {
         'lhs': lhsBuffer,
@@ -134,8 +134,8 @@
       {'output': outputBuffer});
 
   graph.destroy();
-  const outputData = await context.readBuffer(outputBuffer);
+  const outputData = await context.readTensor(outputBuffer);
   assert_array_equals(
       new Float32Array(outputData), [4],
       'Read buffer data equals expected data.');
-}, 'Destroying graph after dispatch() and before readBuffer() is OK.');
+}, 'Destroying graph after dispatch() and before readTensor() is OK.');
diff --git a/third_party/blink/web_tests/fast/forms/select/stylable-select/nested-select-console-message-expected.txt b/third_party/blink/web_tests/fast/forms/select/stylable-select/nested-select-console-message-expected.txt
new file mode 100644
index 0000000..543dc29e
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/select/stylable-select/nested-select-console-message-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+option
diff --git a/third_party/blink/web_tests/fast/forms/select/stylable-select/nested-select-console-message.html b/third_party/blink/web_tests/fast/forms/select/stylable-select/nested-select-console-message.html
new file mode 100644
index 0000000..ae76aa8
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/select/stylable-select/nested-select-console-message.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://issues.chromium.org/issues/363243411">
+
+<select>
+  <option>option</option>
+<select>
+
+<script>
+testRunner.dumpAsText();
+</script>
diff --git a/third_party/blink/web_tests/fast/parser/input-textarea-inside-select-element-expected.txt b/third_party/blink/web_tests/fast/parser/input-textarea-inside-select-element-expected.txt
index 496a613..d6e879e 100644
--- a/third_party/blink/web_tests/fast/parser/input-textarea-inside-select-element-expected.txt
+++ b/third_party/blink/web_tests/fast/parser/input-textarea-inside-select-element-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 Test for bug 17421: Lack of end tag of SELECT element causes inaccessible (blank) a rest of a page rendered.
 
 There should be two green bars below.
diff --git a/third_party/blink/web_tests/fast/scroll-snap/snap-scrolls-visual-viewport.html b/third_party/blink/web_tests/fast/scroll-snap/snap-scrolls-visual-viewport.html
index 26433623..1c4da525 100644
--- a/third_party/blink/web_tests/fast/scroll-snap/snap-scrolls-visual-viewport.html
+++ b/third_party/blink/web_tests/fast/scroll-snap/snap-scrolls-visual-viewport.html
@@ -47,25 +47,23 @@
     visual_viewport_y) {
   const scale_factor = 2;
   internals.setPageScaleFactor(scale_factor);
-  window.scrollTo(0, initial_position);
+  await waitForWindowScrollTo({top: initial_position, left: 0});
   internals.setVisualViewportOffset(0, 0);
+  await waitForCompositorCommit();
   assert_equals(window.visualViewport.scale, 2);
   assert_equals(window.scrollY, initial_position);
   assert_equals(window.visualViewport.offsetTop, 0);
 
   const x = 200;
   const y = 200;
-  const scrollPromise = waitForScrollEvent(document);
+  const scrollEndPromise = waitForScrollendEvent(document);
   await smoothScroll(scale_factor * scroll_delta,
                      x,
                      y,
                      SOURCE_TYPE,
                      scroll_direction,
                      SPEED_INSTANT);
-  await scrollPromise;
-  await waitForAnimationEndTimeBased(() => {
-    return window.scrollY + window.visualViewport.offsetTop;
-  });
+  await scrollEndPromise;
 
   assert_approx_equals(window.scrollY, layout_viewport_y, 1);
   assert_approx_equals(window.visualViewport.offsetTop, visual_viewport_y, 1);
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt
index c6362f9..ae7e64f 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt
@@ -1,4 +1,6 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/tests1.dat:
 30
 102
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt
index c6362f9..ae7e64f 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt
@@ -1,4 +1,6 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/tests1.dat:
 30
 102
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests2-data-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests2-data-expected.txt
index 0fcb5950..7e1900f 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-tests2-data-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-tests2-data-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/tests2.dat:
 36
 37
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests2-write-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests2-write-expected.txt
index 0fcb5950..7e1900f 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-tests2-write-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-tests2-write-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/tests2.dat:
 36
 37
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt
index 72e630c6..15e65e9 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt
@@ -1,4 +1,5 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/tests7.dat:
 13
 14
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt
index 72e630c6..15e65e9 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt
@@ -1,4 +1,5 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/tests7.dat:
 13
 14
diff --git a/third_party/blink/web_tests/html5lib/generated/run-webkit01-data-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-webkit01-data-expected.txt
index f2ca392..5d2247ae 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-webkit01-data-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-webkit01-data-expected.txt
@@ -1,5 +1,12 @@
 CONSOLE MESSAGE: PASS
 CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/webkit01.dat:
 31
 
diff --git a/third_party/blink/web_tests/html5lib/generated/run-webkit01-write-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-webkit01-write-expected.txt
index f2ca392..5d2247ae 100644
--- a/third_party/blink/web_tests/html5lib/generated/run-webkit01-write-expected.txt
+++ b/third_party/blink/web_tests/html5lib/generated/run-webkit01-write-expected.txt
@@ -1,5 +1,12 @@
 CONSOLE MESSAGE: PASS
 CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 ../resources/webkit01.dat:
 31
 
diff --git a/third_party/blink/web_tests/html5lib/webkit-resumer-expected.txt b/third_party/blink/web_tests/html5lib/webkit-resumer-expected.txt
index 4330a2b0..9bb6aa9 100644
--- a/third_party/blink/web_tests/html5lib/webkit-resumer-expected.txt
+++ b/third_party/blink/web_tests/html5lib/webkit-resumer-expected.txt
@@ -156,6 +156,888 @@
 CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
 CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
 CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
 resources/webkit01.dat:
 1177.1
 1178.2
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/har-content.js b/third_party/blink/web_tests/http/tests/devtools/network/har-content.js
index 45e75fd..6b53c6b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/network/har-content.js
+++ b/third_party/blink/web_tests/http/tests/devtools/network/har-content.js
@@ -23,7 +23,10 @@
     var stream = new TestRunner.StringOutputStream(onSaved);
     var progress = new Common.Progress.Progress();
     await NetworkTestRunner.writeHARLog(
-        stream, NetworkTestRunner.networkRequests(), progress);
+        stream,
+        NetworkTestRunner.networkRequests(),
+        {sanitize: false},
+        progress);
     progress.done();
     stream.close();
   }
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/har-post.js b/third_party/blink/web_tests/http/tests/devtools/network/har-post.js
index d3879b3..d184d09 100644
--- a/third_party/blink/web_tests/http/tests/devtools/network/har-post.js
+++ b/third_party/blink/web_tests/http/tests/devtools/network/har-post.js
@@ -37,7 +37,7 @@
     const stream = new TestRunner.StringOutputStream(resolve);
     const progress = new Common.Progress.Progress();
     const networkRequests = NetworkTestRunner.networkRequests();
-    await NetworkTestRunner.writeHARLog(stream, networkRequests, progress);
+    await NetworkTestRunner.writeHARLog(stream, networkRequests, {sanitize: false}, progress);
     progress.done();
     stream.close();
   });
diff --git a/third_party/blink/web_tests/http/tests/devtools/resource-har-conversion.js b/third_party/blink/web_tests/http/tests/devtools/resource-har-conversion.js
index 596731b..27d6665 100644
--- a/third_party/blink/web_tests/http/tests/devtools/resource-har-conversion.js
+++ b/third_party/blink/web_tests/http/tests/devtools/resource-har-conversion.js
@@ -56,7 +56,7 @@
   addCookieHeadersToRequest(test_url);
   addServiceWorkerInfoToRequest(test_url);
   const requests = NetworkTestRunner.networkRequests();
-  var log = await NetworkTestRunner.buildHARLog(requests);
+  var log = await NetworkTestRunner.buildHARLog(requests, {sanitize: false});
   // Filter out favicon.ico requests that only appear on certain platforms.
   log.entries = log.entries.filter(function(entry) {
     return !/favicon\.ico$/.test(entry.request.url);
diff --git a/third_party/blink/web_tests/http/tests/devtools/resource-har-headers.js b/third_party/blink/web_tests/http/tests/devtools/resource-har-headers.js
index b1b2437..84ecfcd 100644
--- a/third_party/blink/web_tests/http/tests/devtools/resource-har-headers.js
+++ b/third_party/blink/web_tests/http/tests/devtools/resource-har-headers.js
@@ -94,7 +94,7 @@
     '_transferSize': 'formatAsTypeName',
     '_error': 'skip'
   };
-  var har = await NetworkTestRunner.buildHARLogEntry(testRequest);
+  var har = await NetworkTestRunner.buildHARLogEntry(testRequest, {sanitize: false});
   TestRunner.addObject(har, stillNondeterministic, '', 'HAR:');
   TestRunner.completeTest();
 })();
diff --git a/third_party/blink/web_tests/http/tests/devtools/resource-parameters-ipv6.js b/third_party/blink/web_tests/http/tests/devtools/resource-parameters-ipv6.js
index 1fae708..af29cb6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/resource-parameters-ipv6.js
+++ b/third_party/blink/web_tests/http/tests/devtools/resource-parameters-ipv6.js
@@ -34,7 +34,7 @@
       return;
     TestRunner.addResult(request.url());
     TestRunner.addObject(
-        await NetworkTestRunner.buildHARLogEntry(request),
+        await NetworkTestRunner.buildHARLogEntry(request, {sanitize: false}),
         NetworkTestRunner.HARPropertyFormattersWithSize);
     TestRunner.completeTest();
   }
diff --git a/third_party/blink/web_tests/http/tests/devtools/resource-parameters.js b/third_party/blink/web_tests/http/tests/devtools/resource-parameters.js
index 3061f8e..e74b49eb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/resource-parameters.js
+++ b/third_party/blink/web_tests/http/tests/devtools/resource-parameters.js
@@ -31,7 +31,7 @@
     var request = event.data;
     TestRunner.addResult(request.url());
     TestRunner.addObject(
-        await NetworkTestRunner.buildHARLogEntry(request),
+        await NetworkTestRunner.buildHARLogEntry(request, {sanitize: false}),
         NetworkTestRunner.HARPropertyFormattersWithSize);
     TestRunner.completeTest();
   }
diff --git a/third_party/blink/web_tests/http/tests/devtools/websocket/har-websocket.js b/third_party/blink/web_tests/http/tests/devtools/websocket/har-websocket.js
index aac4580..83ac531 100644
--- a/third_party/blink/web_tests/http/tests/devtools/websocket/har-websocket.js
+++ b/third_party/blink/web_tests/http/tests/devtools/websocket/har-websocket.js
@@ -41,7 +41,10 @@
     const stream = new TestRunner.StringOutputStream(resolve);
     const progress = new Common.Progress.Progress();
     await NetworkTestRunner.writeHARLog(
-        stream, NetworkTestRunner.networkRequests(), progress);
+        stream,
+        NetworkTestRunner.networkRequests(),
+        {sanitize: false},
+        progress);
     progress.done();
     stream.close();
   });
diff --git a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt b/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt
index ad05bd1..5ede774 100644
--- a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt
+++ b/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 34 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 35 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] Property color value 'color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple)'
   Colors do not match.\nActual:   color(srgb 0.2 0.2 0.6)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.4 +/- 0.01, expected 0.4 but got 0.2
 [FAIL] Property background-color value 'rgb(from currentColor r g b)'
@@ -8,6 +8,8 @@
   Colors do not match.\nActual:   color(srgb 0.6 0.2 0.5)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.4 +/- 0.01, expected 0.4 but got 0.6
 [FAIL] Property background-color value 'hsl(from currentColor h s l)'
   assert_true: 'hsl(from currentColor h s l)' is a supported value for background-color. expected true got false
+[FAIL] Property background-color value 'hsl(from currentColor calc((h / 360) * 360deg) s l)'
+  assert_true: 'hsl(from currentColor calc((h / 360) * 360deg) s l)' is a supported value for background-color. expected true got false
 [FAIL] Property color value 'color-mix(in hwb, hwb(from rebeccapurple none w b), rebeccapurple)'
   Colors do not match.\nActual:   color(srgb 0.6 0.2 0.5)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.4 +/- 0.01, expected 0.4 but got 0.6
 [FAIL] Property background-color value 'hwb(from currentColor h w b)'
diff --git a/third_party/blink/web_tests/virtual/dom-parts-disabled/fast/parser/input-textarea-inside-select-element-expected.txt b/third_party/blink/web_tests/virtual/dom-parts-disabled/fast/parser/input-textarea-inside-select-element-expected.txt
new file mode 100644
index 0000000..d6e879e
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/dom-parts-disabled/fast/parser/input-textarea-inside-select-element-expected.txt
@@ -0,0 +1,4 @@
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+Test for bug 17421: Lack of end tag of SELECT element causes inaccessible (blank) a rest of a page rendered.
+
+There should be two green bars below.
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/parser/input-textarea-inside-select-element-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/parser/input-textarea-inside-select-element-expected.txt
new file mode 100644
index 0000000..d6e879e
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/parser/input-textarea-inside-select-element-expected.txt
@@ -0,0 +1,4 @@
+CONSOLE WARNING: A <select> tag was parsed within another <select> tag and was converted into </select><select>. Please add the missing </select> end tag.
+Test for bug 17421: Lack of end tag of SELECT element causes inaccessible (blank) a rest of a page rendered.
+
+There should be two green bars below.
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests1-write-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests1-write-expected.txt
deleted file mode 100644
index c6362f9..0000000
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests1-write-expected.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
-../resources/tests1.dat:
-30
-102
-
-Test 30 of 114 in ../resources/tests1.dat failed. Input:
-<select><b><option><select><option></b></select>X
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <b>
-|         <option>
-|     <b>
-|     <select>
-|       <b>
-|         <option>
-|     "X"
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <option>
-|     <option>
-|       "X"
-
-Test 102 of 114 in ../resources/tests1.dat failed. Input:
-<select><b><option><select><option></b></select>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <b>
-|         <option>
-|     <b>
-|     <select>
-|       <b>
-|         <option>
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <option>
-|     <option>
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests2-data-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests2-data-expected.txt
deleted file mode 100644
index 0fcb5950..0000000
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests2-data-expected.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-../resources/tests2.dat:
-36
-37
-43
-
-Test 36 of 61 in ../resources/tests2.dat failed. Input:
-<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|       <option>
-|     <select>
-|       <option>
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|       <option>
-|     <option>
-
-Test 37 of 61 in ../resources/tests2.dat failed. Input:
-<!DOCTYPE html><select><optgroup><option><optgroup>
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|         <optgroup>
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|       <optgroup>
-
-Test 43 of 61 in ../resources/tests2.dat failed. Input:
-<isindex test=x name=x>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <isindex>
-|       name="x"
-|       test="x"
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <form>
-|       <hr>
-|       <label>
-|         "This is a searchable index. Enter search keywords: "
-|         <input>
-|           name="isindex"
-|           test="x"
-|       <hr>
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests2-write-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests2-write-expected.txt
deleted file mode 100644
index 0fcb5950..0000000
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests2-write-expected.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-../resources/tests2.dat:
-36
-37
-43
-
-Test 36 of 61 in ../resources/tests2.dat failed. Input:
-<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|       <option>
-|     <select>
-|       <option>
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|       <option>
-|     <option>
-
-Test 37 of 61 in ../resources/tests2.dat failed. Input:
-<!DOCTYPE html><select><optgroup><option><optgroup>
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|         <optgroup>
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <optgroup>
-|         <option>
-|       <optgroup>
-
-Test 43 of 61 in ../resources/tests2.dat failed. Input:
-<isindex test=x name=x>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <isindex>
-|       name="x"
-|       test="x"
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <form>
-|       <hr>
-|       <label>
-|         "This is a searchable index. Enter search keywords: "
-|         <input>
-|           name="isindex"
-|           test="x"
-|       <hr>
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests7-data-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests7-data-expected.txt
deleted file mode 100644
index 72e630c6..0000000
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests7-data-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
-../resources/tests7.dat:
-13
-14
-30
-
-Test 13 of 30 in ../resources/tests7.dat failed. Input:
-<!doctype html><select><input>X
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <input>
-|       "X"
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     <input>
-|     "X"
-
-Test 14 of 30 in ../resources/tests7.dat failed. Input:
-<!doctype html><select><select>X
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     <select>
-|       "X"
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     "X"
-
-Test 30 of 30 in ../resources/tests7.dat failed. Input:
-<select><keygen>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <keygen>
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     <keygen>
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests7-write-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests7-write-expected.txt
deleted file mode 100644
index 72e630c6..0000000
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-tests7-write-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
-../resources/tests7.dat:
-13
-14
-30
-
-Test 13 of 30 in ../resources/tests7.dat failed. Input:
-<!doctype html><select><input>X
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <input>
-|       "X"
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     <input>
-|     "X"
-
-Test 14 of 30 in ../resources/tests7.dat failed. Input:
-<!doctype html><select><select>X
-Got:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     <select>
-|       "X"
-Expected:
-| <!DOCTYPE html>
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     "X"
-
-Test 30 of 30 in ../resources/tests7.dat failed. Input:
-<select><keygen>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <keygen>
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|     <keygen>
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-webkit01-data-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-webkit01-data-expected.txt
deleted file mode 100644
index f2ca392..0000000
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-webkit01-data-expected.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-CONSOLE MESSAGE: PASS
-CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
-../resources/webkit01.dat:
-31
-
-Test 31 of 51 in ../resources/webkit01.dat failed. Input:
-<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <option>
-|         "A"
-|     <select>
-|       <option>
-|         "B"
-|     <select>
-|       <option>
-|         "C"
-|     <select>
-|       <option>
-|         "D"
-|     <select>
-|       <option>
-|         "E"
-|     <select>
-|       <option>
-|         "F"
-|     <select>
-|       <option>
-|         "G"
-|     <select>
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <option>
-|         "A"
-|     <option>
-|       "B"
-|       <select>
-|         <option>
-|           "C"
-|     <option>
-|       "D"
-|       <select>
-|         <option>
-|           "E"
-|     <option>
-|       "F"
-|       <select>
-|         <option>
-|           "G"
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-webkit01-write-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-webkit01-write-expected.txt
deleted file mode 100644
index f2ca392..0000000
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/html5lib/generated/run-webkit01-write-expected.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-CONSOLE MESSAGE: PASS
-CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
-../resources/webkit01.dat:
-31
-
-Test 31 of 51 in ../resources/webkit01.dat failed. Input:
-<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <option>
-|         "A"
-|     <select>
-|       <option>
-|         "B"
-|     <select>
-|       <option>
-|         "C"
-|     <select>
-|       <option>
-|         "D"
-|     <select>
-|       <option>
-|         "E"
-|     <select>
-|       <option>
-|         "F"
-|     <select>
-|       <option>
-|         "G"
-|     <select>
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <select>
-|       <option>
-|         "A"
-|     <option>
-|       "B"
-|       <select>
-|         <option>
-|           "C"
-|     <option>
-|       "D"
-|       <select>
-|         <option>
-|           "E"
-|     <option>
-|       "F"
-|       <select>
-|         <option>
-|           "G"
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/fast/forms/select/stylable-select/nested-select-console-message-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/fast/forms/select/stylable-select/nested-select-console-message-expected.txt
new file mode 100644
index 0000000..5b51814
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/fast/forms/select/stylable-select/nested-select-console-message-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
+option
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-data-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-data-expected.txt
index bd911704..6d136ea 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-data-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-data-expected.txt
@@ -1,4 +1,6 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
 CONSOLE WARNING: A b tag was parsed inside of a <select> which was not inserted into the document. This is not valid HTML and the behavior may be changed in future versions of chrome.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 CONSOLE WARNING: A b tag was parsed inside of a <select> which was not inserted into the document. This is not valid HTML and the behavior may be changed in future versions of chrome.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 ../resources/tests1.dat: PASS
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-write-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-write-expected.txt
index bd911704..6d136ea 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-write-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests1-write-expected.txt
@@ -1,4 +1,6 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
 CONSOLE WARNING: A b tag was parsed inside of a <select> which was not inserted into the document. This is not valid HTML and the behavior may be changed in future versions of chrome.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 CONSOLE WARNING: A b tag was parsed inside of a <select> which was not inserted into the document. This is not valid HTML and the behavior may be changed in future versions of chrome.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 ../resources/tests1.dat: PASS
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-data-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-data-expected.txt
index 200bf48..2f19c1b 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-data-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-data-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 ../resources/tests2.dat:
 43
 
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-write-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-write-expected.txt
index 200bf48..2f19c1b 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-write-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests2-write-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 ../resources/tests2.dat:
 43
 
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-data-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-data-expected.txt
index bbaeb9d..63be75e 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-data-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-data-expected.txt
@@ -1,4 +1,5 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
 CONSOLE WARNING: A input tag was parsed inside of a <select> which caused a </select> to be inserted before this tag. This is not valid HTML and the behavior may be changed in future versions of chrome.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 CONSOLE WARNING: A keygen tag was parsed inside of a <select> which caused a </select> to be inserted before this tag. This is not valid HTML and the behavior may be changed in future versions of chrome.
 ../resources/tests7.dat: PASS
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-write-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-write-expected.txt
index bbaeb9d..63be75e 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-write-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-tests7-write-expected.txt
@@ -1,4 +1,5 @@
 CONSOLE ERROR: Uncaught SyntaxError: Unexpected token '<'
 CONSOLE WARNING: A input tag was parsed inside of a <select> which caused a </select> to be inserted before this tag. This is not valid HTML and the behavior may be changed in future versions of chrome.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 CONSOLE WARNING: A keygen tag was parsed inside of a <select> which caused a </select> to be inserted before this tag. This is not valid HTML and the behavior may be changed in future versions of chrome.
 ../resources/tests7.dat: PASS
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-data-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-data-expected.txt
index 1995fce9..d362e100 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-data-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-data-expected.txt
@@ -1,3 +1,7 @@
 CONSOLE MESSAGE: PASS
 CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 ../resources/webkit01.dat: PASS
diff --git a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-write-expected.txt b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-write-expected.txt
index 1995fce9..d362e100 100644
--- a/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-write-expected.txt
+++ b/third_party/blink/web_tests/virtual/stylable-select-disabled/html5lib/generated/run-webkit01-write-expected.txt
@@ -1,3 +1,7 @@
 CONSOLE MESSAGE: PASS
 CONSOLE MESSAGE: FOO<span>BAR</span>BAZ
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
+CONSOLE ERROR: A <select> tag was parsed within another <select> tag and was converted into </select>. This behavior will change in a future browser version. Please add the missing </select> end tag.
 ../resources/webkit01.dat: PASS
diff --git a/third_party/blink/web_tests/wpt_internal/third-party-script-detection/resources/third-party-script-test-utils.js b/third_party/blink/web_tests/wpt_internal/third-party-script-detection/resources/third-party-script-test-utils.js
index 0085c1d..ee4a3eb 100644
--- a/third_party/blink/web_tests/wpt_internal/third-party-script-detection/resources/third-party-script-test-utils.js
+++ b/third_party/blink/web_tests/wpt_internal/third-party-script-detection/resources/third-party-script-test-utils.js
@@ -14,7 +14,9 @@
   // Hotjar
   'https://static.hotjar.com/c/hotjar-1903348.js',
   // Elementor
-  'https://elementor.com/wp-content/plugins/elementor/assets/lib/swiper/v8/swiper.min.js'
+  'https://elementor.com/wp-content/plugins/elementor/assets/lib/swiper/v8/swiper.min.js',
+  // Slider Revolution
+  'https://artfulagenda.com/wp-content/plugins/revslider/public/assets/js/jquery.themepunch.tools.min.js'
 ];
 
 function third_party_script_test(test_type, url, expected_metric_value) {
diff --git a/third_party/blink/web_tests/wpt_internal/third-party-script-detection/third-party-script-callback-contributors-ukm-sliderrevolution.https.html b/third_party/blink/web_tests/wpt_internal/third-party-script-detection/third-party-script-callback-contributors-ukm-sliderrevolution.https.html
new file mode 100644
index 0000000..9c43785
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/third-party-script-detection/third-party-script-callback-contributors-ukm-sliderrevolution.https.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=resources/third-party-script-test-utils.js></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<script>
+  third_party_script_test(
+    'script-callback',
+    'https://artfulagenda.com/wp-content/plugins/revslider/public/assets/js/jquery.themepunch.tools.min.js', 1 << 15 /*Technology::kSliderRevolution*/);
+</script>
\ No newline at end of file
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index 01e1ae3..f10c1dc 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit 01e1ae3687e391a076fe470471f096db1f6d6bb4
+Subproject commit f10c1dc37174843c504a80e94c252e35b7b1eb61
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index 7fd4b86..5117dda 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit 7fd4b8625471752cff2ed65f7676900a15a3a2fe
+Subproject commit 5117ddadfa9e6ef29d5eb03ab93e90fd506c0828
diff --git a/third_party/cloud_authenticator/README.chromium b/third_party/cloud_authenticator/README.chromium
index 333b91a..431a85ae 100644
--- a/third_party/cloud_authenticator/README.chromium
+++ b/third_party/cloud_authenticator/README.chromium
@@ -6,6 +6,7 @@
 License Android Compatible: yes
 Security Critical: no
 Shipped: no
+Revision: 2a2ec65789f63c135a68a7990b6426922c785825
 
 Description:
 This directory contains the partial source code for the passkeys enclave. The
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 4deaf64..0f4c020 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: N/A
-Revision: 915913bd5a721b26fa5ee6321ab9b26777ae9202
+Revision: 35e06fe736ff20b59b37c238b0322f04b49aff28
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/third_party/xnu/README.crashpad b/third_party/crashpad/crashpad/third_party/xnu/README.crashpad
index dbcf740..58591950 100644
--- a/third_party/crashpad/crashpad/third_party/xnu/README.crashpad
+++ b/third_party/crashpad/crashpad/third_party/xnu/README.crashpad
@@ -1,8 +1,8 @@
 Name: XNU
 Short Name: xnu
-URL: https://opensource.apple.com/source/xnu/
-URL: https://opensource.apple.com/tarballs/xnu/
+URL: https://github.com/apple-oss-distributions/xnu/
 Version: 6153.11.26 (from macOS 10.15.0)
+Revision: a5e7219620fa69943647714baaf632196f37249e
 License: APSL 2.0
 License File: APPLE_LICENSE
 Security Critical: no
diff --git a/third_party/crc32c/src b/third_party/crc32c/src
index fa5ade4..d3d60ac 160000
--- a/third_party/crc32c/src
+++ b/third_party/crc32c/src
@@ -1 +1 @@
-Subproject commit fa5ade41ee480003d9c5af6f43567ba22e4e17e6
+Subproject commit d3d60ac6e0f16780bcfcc825385e1d338801a558
diff --git a/third_party/dawn b/third_party/dawn
index 7d3a30e..73d7f7e 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 7d3a30e786c1c9bd61d24b21d7fdec5218ab280c
+Subproject commit 73d7f7ee1b320591b78dfbc35ceec83e6baea621
diff --git a/third_party/depot_tools b/third_party/depot_tools
index ae37456..653e86a 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit ae3745656b1111c995e41ec70eaa4397eaea7951
+Subproject commit 653e86a6f020e89e7f9249d40a22b25a8d6ba02a
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index b6c4c78..7ae8cb3 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit b6c4c78e370aab6bd45dd39584cb49962687e8ac
+Subproject commit 7ae8cb30b21435841a28f345b03624cc31029418
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 7e0f06a..a058cb5 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 7e0f06a7936e95c3410f27cfaccbd94c7b5ff26c
+Subproject commit a058cb54ecbbb8630ccc3b959b209b20d7ad2fa8
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 6184e4f..eb0d5d9b 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-13-3-8-g300803206
-Revision: 3008032062e2ce8549c26b42ae55c6e02439f27c
+Version: VER-2-13-3-9-g83af801b5
+Revision: 83af801b552111e37d9466a887e1783a0fb5f196
 CPEPrefix: cpe:/a:freetype:freetype:2.13.3
 License: FTL
 License File: src/docs/FTL.TXT
diff --git a/third_party/freetype/src b/third_party/freetype/src
index 3008032..83af801 160000
--- a/third_party/freetype/src
+++ b/third_party/freetype/src
@@ -1 +1 @@
-Subproject commit 3008032062e2ce8549c26b42ae55c6e02439f27c
+Subproject commit 83af801b552111e37d9466a887e1783a0fb5f196
diff --git a/third_party/jni_zero/jni_registration_generator.py b/third_party/jni_zero/jni_registration_generator.py
index 6d3b5e6..3b1e74b1 100644
--- a/third_party/jni_zero/jni_registration_generator.py
+++ b/third_party/jni_zero/jni_registration_generator.py
@@ -295,8 +295,8 @@
 
 def _InsertMultiplexingSwitchCases(signature_to_cpp_calls,
                                    java_functions_string, short_gen_jni_class):
-  switch_case_method_name_re = re.compile('return (\w+)\(')
-  java_function_call_re = re.compile('public static \S+ (\w+)\(')
+  switch_case_method_name_re = re.compile(r'return (\w+)\(')
+  java_function_call_re = re.compile(r'public static \S+ (\w+)\(')
   method_to_switch_num = {}
   for signature, cases in sorted(signature_to_cpp_calls.items()):
     for i, case in enumerate(cases):
diff --git a/third_party/jni_zero/parse.py b/third_party/jni_zero/parse.py
index d3435b97..2a80231e 100644
--- a/third_party/jni_zero/parse.py
+++ b/third_party/jni_zero/parse.py
@@ -112,7 +112,7 @@
     value = ret
 
 
-_PACKAGE_REGEX = re.compile('^package\s+(\S+?);', flags=re.MULTILINE)
+_PACKAGE_REGEX = re.compile(r'^package\s+(\S+?);', flags=re.MULTILINE)
 
 
 def _parse_package(contents):
@@ -383,7 +383,7 @@
           package.replace('.', '/') + '/' + class_name.replace('.', '$'))
 
 
-_JNI_NAMESPACE_REGEX = re.compile('@JNINamespace\("(.*?)"\)')
+_JNI_NAMESPACE_REGEX = re.compile(r'@JNINamespace\("(.*?)"\)')
 
 
 def _parse_jni_namespace(contents):
diff --git a/third_party/libc++/src b/third_party/libc++/src
index 7ef1f0a..9be1056 160000
--- a/third_party/libc++/src
+++ b/third_party/libc++/src
@@ -1 +1 @@
-Subproject commit 7ef1f0a187aa3320426084c19e42833568f779a9
+Subproject commit 9be1056e883d3fe5cd6666ac69702a6c5e9a39df
diff --git a/third_party/perfetto b/third_party/perfetto
index 6a4a99c..bea7f2f 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 6a4a99c3a7a42d98ea93990af32e4a69cfb39552
+Subproject commit bea7f2f92cb9ecf6923ecea52120c312840494a0
diff --git a/third_party/rust/anyhow/v1/BUILD.gn b/third_party/rust/anyhow/v1/BUILD.gn
index c2827c1..db07bb9 100644
--- a/third_party/rust/anyhow/v1/BUILD.gn
+++ b/third_party/rust/anyhow/v1/BUILD.gn
@@ -13,25 +13,25 @@
   epoch = "1"
   crate_type = "rlib"
   crate_root =
-      "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/lib.rs"
+      "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/lib.rs"
   sources = [
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/backtrace.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/chain.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/context.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/ensure.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/error.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/fmt.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/kind.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/lib.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/macros.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/ptr.rs",
-    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/wrapper.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/backtrace.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/chain.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/context.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/ensure.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/error.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/fmt.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/kind.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/macros.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/ptr.rs",
+    "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/wrapper.rs",
   ]
   inputs = []
 
   build_native_rust_unit_tests = false
   edition = "2018"
-  cargo_pkg_version = "1.0.86"
+  cargo_pkg_version = "1.0.87"
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "anyhow"
   cargo_pkg_description =
@@ -44,9 +44,9 @@
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
   features = [ "std" ]
   build_root =
-      "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build.rs"
+      "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build.rs"
   build_sources =
-      [ "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build.rs" ]
+      [ "//third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build.rs" ]
 
   testonly = true
 }
diff --git a/third_party/rust/anyhow/v1/README.chromium b/third_party/rust/anyhow/v1/README.chromium
index 8d5a302..7ad401ac 100644
--- a/third_party/rust/anyhow/v1/README.chromium
+++ b/third_party/rust/anyhow/v1/README.chromium
@@ -1,9 +1,9 @@
 Name: anyhow
 URL: https://crates.io/crates/anyhow
 Description: Flexible concrete Error type built on std::error::Error
-Version: 1.0.86
+Version: 1.0.87
 Security Critical: no
 Shipped: no
 License: Apache 2.0
-License File: //third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/LICENSE-APACHE
-Revision: 8ea1819c4c7829d0eb09e54a52806f382b8d445b
+License File: //third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/LICENSE-APACHE
+Revision: afe93e7b167d069ac79f2c7f363b919d3793e6ce
diff --git a/third_party/rust/bytemuck/v1/BUILD.gn b/third_party/rust/bytemuck/v1/BUILD.gn
index 1c863250..cb79842 100644
--- a/third_party/rust/bytemuck/v1/BUILD.gn
+++ b/third_party/rust/bytemuck/v1/BUILD.gn
@@ -13,28 +13,28 @@
   epoch = "1"
   crate_type = "rlib"
   crate_root =
-      "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/lib.rs"
+      "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/lib.rs"
   sources = [
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/allocation.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/anybitpattern.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/checked.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/contiguous.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/internal.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/lib.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/must.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/no_uninit.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/offset_of.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/pod.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/pod_in_option.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/transparent.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/zeroable.rs",
-    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/zeroable_in_option.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/allocation.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/anybitpattern.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/checked.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/contiguous.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/internal.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/must.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/no_uninit.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/offset_of.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/pod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/pod_in_option.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/transparent.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/zeroable.rs",
+    "//third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/zeroable_in_option.rs",
   ]
   inputs = []
 
   build_native_rust_unit_tests = false
   edition = "2018"
-  cargo_pkg_version = "1.17.1"
+  cargo_pkg_version = "1.18.0"
   cargo_pkg_authors = "Lokathor <zefria@gmail.com>"
   cargo_pkg_name = "bytemuck"
   cargo_pkg_description = "A crate for mucking around with piles of bytes."
diff --git a/third_party/rust/bytemuck/v1/README.chromium b/third_party/rust/bytemuck/v1/README.chromium
index 5911a78..5b3e259 100644
--- a/third_party/rust/bytemuck/v1/README.chromium
+++ b/third_party/rust/bytemuck/v1/README.chromium
@@ -1,9 +1,9 @@
 Name: bytemuck
 URL: https://crates.io/crates/bytemuck
 Description: A crate for mucking around with piles of bytes.
-Version: 1.17.1
+Version: 1.18.0
 Security Critical: yes
 Shipped: yes
 License: Apache 2.0
-License File: //third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-APACHE
-Revision: dc059fd187c45cd9739aeedabd5e75e527058f90
+License File: //third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-APACHE
+Revision: 860c391345a2ec61fecf3cd46bcdde1add01caf9
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock
index d052228..6d3b2a00 100644
--- a/third_party/rust/chromium_crates_io/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -27,7 +27,7 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -47,7 +47,7 @@
 
 [[package]]
 name = "bytemuck"
-version = "1.17.1"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bytemuck_derive",
@@ -70,7 +70,7 @@
 
 [[package]]
 name = "cc"
-version = "1.1.16"
+version = "1.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "shlex",
@@ -539,7 +539,7 @@
 
 [[package]]
 name = "serde"
-version = "1.0.209"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "serde_derive",
@@ -547,7 +547,7 @@
 
 [[package]]
 name = "serde_derive"
-version = "1.0.209"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro2",
diff --git a/third_party/rust/chromium_crates_io/patches/png/0101-Introduce-a-separate-struct-Adam7Info.patch b/third_party/rust/chromium_crates_io/patches/png/0101-Introduce-a-separate-struct-Adam7Info.patch
new file mode 100644
index 0000000..9651b86
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/patches/png/0101-Introduce-a-separate-struct-Adam7Info.patch
@@ -0,0 +1,199 @@
+From a8606523dc284a0432c9b1737066b189ca3ea660 Mon Sep 17 00:00:00 2001
+From: Lukasz Anforowicz <lukasza@chromium.org>
+Date: Fri, 30 Aug 2024 19:19:17 +0000
+Subject: [PATCH 101/107] Introduce a separate `struct Adam7Info`.
+
+This helps with the following things:
+
+* It means that after making `InterlaceInfo` public in a follow-up
+  commit, `pass`, `line`, and `width` fields can remain private.
+* It means that a follow-up commit that refactors `adam7::expand_pass`
+  to take a single `info` parameter doesn't allow passing an
+  invalid `InterlaceInfo::Null` value.
+* It gives `Adam7Iterator` a nicer, named `Iterator::Item`.
+---
+ src/adam7.rs       | 67 ++++++++++++++++++++++++++++++++++++++--------
+ src/decoder/mod.rs | 32 +++++++++++++---------
+ 2 files changed, 76 insertions(+), 23 deletions(-)
+
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+index 5bf7bb3..550e215 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+@@ -1,7 +1,20 @@
+-//! Utility functions
++//! Utility functions related to handling of
++//! [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm).
+ use std::iter::StepBy;
+ use std::ops::Range;
+ 
++/// Describes which stage of
++/// [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm)
++/// applies to a decoded row.
++///
++/// See also [Reader::next_interlaced_row].
++#[derive(Clone, Copy, Debug, PartialEq, Eq)]
++pub struct Adam7Info {
++    pub(crate) pass: u8,
++    pub(crate) line: u32,
++    pub(crate) width: u32,
++}
++
+ /// This iterator iterates over the different passes of an image Adam7 encoded
+ /// PNG image
+ /// The pattern is:
+@@ -63,14 +76,18 @@ impl Adam7Iterator {
+     }
+ }
+ 
+-/// Iterates over the (passes, lines, widths)
++/// Iterates over `Adam7Info`s.
+ impl Iterator for Adam7Iterator {
+-    type Item = (u8, u32, u32);
++    type Item = Adam7Info;
+     fn next(&mut self) -> Option<Self::Item> {
+         if self.line < self.lines && self.line_width > 0 {
+             let this_line = self.line;
+             self.line += 1;
+-            Some((self.current_pass, this_line, self.line_width))
++            Some(Adam7Info {
++                pass: self.current_pass,
++                line: this_line,
++                width: self.line_width,
++            })
+         } else if self.current_pass < 7 {
+             self.current_pass += 1;
+             self.init_pass();
+@@ -179,13 +196,41 @@ fn test_adam7() {
+     assert_eq!(
+         &*passes,
+         &[
+-            (1, 0, 1),
+-            (4, 0, 1),
+-            (5, 0, 2),
+-            (6, 0, 2),
+-            (6, 1, 2),
+-            (7, 0, 4),
+-            (7, 1, 4)
++            Adam7Info {
++                pass: 1,
++                line: 0,
++                width: 1
++            },
++            Adam7Info {
++                pass: 4,
++                line: 0,
++                width: 1
++            },
++            Adam7Info {
++                pass: 5,
++                line: 0,
++                width: 2
++            },
++            Adam7Info {
++                pass: 6,
++                line: 0,
++                width: 2
++            },
++            Adam7Info {
++                pass: 6,
++                line: 1,
++                width: 2
++            },
++            Adam7Info {
++                pass: 7,
++                line: 0,
++                width: 4
++            },
++            Adam7Info {
++                pass: 7,
++                line: 1,
++                width: 4
++            }
+         ]
+     );
+ }
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
+index 2a18964..a5f2e70 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
+@@ -99,19 +99,26 @@ impl<'data> InterlacedRow<'data> {
+         self.data
+     }
+ 
+-    pub fn interlace(&self) -> InterlaceInfo {
+-        self.interlace
++    pub fn interlace(&self) -> &InterlaceInfo {
++        &self.interlace
+     }
+ }
+ 
++/// Describes which interlacing algorithm applies to a decoded row.
++///
+ /// PNG (2003) specifies two interlace modes, but reserves future extensions.
++///
++/// See also [Reader::next_interlaced_row].
+ #[derive(Clone, Copy, Debug)]
+ pub enum InterlaceInfo {
+-    /// the null method means no interlacing
++    /// The `null` method means no interlacing.
+     Null,
+-    /// Adam7 derives its name from doing 7 passes over the image, only decoding a subset of all pixels in each pass.
+-    /// The following table shows pictorially what parts of each 8x8 area of the image is found in each pass:
++    /// [The `Adam7` algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm) derives its name
++    /// from doing 7 passes over the image, only decoding a subset of all pixels in each pass.
++    /// The following table shows pictorially what parts of each 8x8 area of the image is found in
++    /// each pass:
+     ///
++    /// ```txt
+     /// 1 6 4 6 2 6 4 6
+     /// 7 7 7 7 7 7 7 7
+     /// 5 6 5 6 5 6 5 6
+@@ -120,7 +127,8 @@ pub enum InterlaceInfo {
+     /// 7 7 7 7 7 7 7 7
+     /// 5 6 5 6 5 6 5 6
+     /// 7 7 7 7 7 7 7 7
+-    Adam7 { pass: u8, line: u32, width: u32 },
++    /// ```
++    Adam7(adam7::Adam7Info),
+ }
+ 
+ /// A row of data without interlace information.
+@@ -545,7 +553,7 @@ impl<R: Read> Reader<R> {
+             }) = self.next_interlaced_row()?
+             {
+                 let (line, pass) = match interlace {
+-                    InterlaceInfo::Adam7 { line, pass, .. } => (line, pass),
++                    InterlaceInfo::Adam7(adam7::Adam7Info { line, pass, .. }) => (line, pass),
+                     InterlaceInfo::Null => unreachable!("expected interlace information"),
+                 };
+                 let samples = color_type.samples() as u8;
+@@ -599,7 +607,7 @@ impl<R: Read> Reader<R> {
+             None => return Ok(None),
+         };
+ 
+-        let width = if let InterlaceInfo::Adam7 { width, .. } = interlace {
++        let width = if let InterlaceInfo::Adam7(adam7::Adam7Info { width, .. }) = interlace {
+             width
+         } else {
+             self.subframe.width
+@@ -715,12 +723,12 @@ impl<R: Read> Reader<R> {
+         match self.subframe.interlace {
+             InterlaceIter::Adam7(ref mut adam7) => {
+                 let last_pass = adam7.current_pass();
+-                let (pass, line, width) = adam7.next()?;
+-                let rowlen = self.info().raw_row_length_from_width(width);
+-                if last_pass != pass {
++                let adam7info = adam7.next()?;
++                let rowlen = self.info().raw_row_length_from_width(adam7info.width);
++                if last_pass != adam7info.pass {
+                     self.prev_start = self.current_start;
+                 }
+-                Some((rowlen, InterlaceInfo::Adam7 { pass, line, width }))
++                Some((rowlen, InterlaceInfo::Adam7(adam7info)))
+             }
+             InterlaceIter::None(ref mut height) => {
+                 let _ = height.next()?;
+-- 
+2.46.0.598.g6f2099f65c-goog
+
diff --git a/third_party/rust/chromium_crates_io/patches/png/0102-Passing-Adam7Info-to-fn-expand_pass.patch b/third_party/rust/chromium_crates_io/patches/png/0102-Passing-Adam7Info-to-fn-expand_pass.patch
new file mode 100644
index 0000000..da83300
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/patches/png/0102-Passing-Adam7Info-to-fn-expand_pass.patch
@@ -0,0 +1,205 @@
+From 82547fcd38519ea1104e99ff58d0863fb304551f Mon Sep 17 00:00:00 2001
+From: Lukasz Anforowicz <lukasza@chromium.org>
+Date: Thu, 29 Aug 2024 17:05:30 +0000
+Subject: [PATCH 102/107] Passing `&Adam7Info` to `fn expand_pass`.
+
+Instead of passing `line_no` and `pass` as separate parameters, we
+can pass a single `&Adam7Info` parameter.  This minor refactoring
+helps with:
+
+* Exposing a nice public API in a follow-up commit
+* Depending on `Adam7Info.width` in a follow-up commit
+---
+ src/adam7.rs       | 57 +++++++++++++++++++++++++++-------------------
+ src/decoder/mod.rs | 22 ++++++++++++------
+ 2 files changed, 48 insertions(+), 31 deletions(-)
+
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+index 550e215..213bb6d 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+@@ -148,16 +148,10 @@ fn expand_adam7_bits(
+ }
+ 
+ /// Expands an Adam 7 pass
+-pub fn expand_pass(
+-    img: &mut [u8],
+-    width: u32,
+-    scanline: &[u8],
+-    pass: u8,
+-    line_no: u32,
+-    bits_pp: u8,
+-) {
++pub fn expand_pass(img: &mut [u8], width: u32, scanline: &[u8], info: &Adam7Info, bits_pp: u8) {
+     let width = width as usize;
+-    let line_no = line_no as usize;
++    let line_no = info.line as usize;
++    let pass = info.pass;
+     let bits_pp = bits_pp as usize;
+ 
+     // pass is out of range but don't blow up
+@@ -318,56 +312,57 @@ fn test_expand_pass_subbyte() {
+     let mut img = [0u8; 8];
+     let width = 8;
+     let bits_pp = 1;
++    let info = create_adam7_info_for_tests;
+ 
+-    expand_pass(&mut img, width, &[0b10000000], 1, 0, bits_pp);
++    expand_pass(&mut img, width, &[0b10000000], &info(1, 0, width), bits_pp);
+     assert_eq!(img, [0b10000000u8, 0, 0, 0, 0, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b10000000], 2, 0, bits_pp);
++    expand_pass(&mut img, width, &[0b10000000], &info(2, 0, width), bits_pp);
+     assert_eq!(img, [0b10001000u8, 0, 0, 0, 0, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11000000], 3, 0, bits_pp);
++    expand_pass(&mut img, width, &[0b11000000], &info(3, 0, width), bits_pp);
+     assert_eq!(img, [0b10001000u8, 0, 0, 0, 0b10001000, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11000000], 4, 0, bits_pp);
++    expand_pass(&mut img, width, &[0b11000000], &info(4, 0, width), bits_pp);
+     assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10001000, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11000000], 4, 1, bits_pp);
++    expand_pass(&mut img, width, &[0b11000000], &info(4, 1, width), bits_pp);
+     assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10101010, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11110000], 5, 0, bits_pp);
++    expand_pass(&mut img, width, &[0b11110000], &info(5, 0, width), bits_pp);
+     assert_eq!(img, [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11110000], 5, 1, bits_pp);
++    expand_pass(&mut img, width, &[0b11110000], &info(5, 1, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], 6, 0, bits_pp);
++    expand_pass(&mut img, width, &[0b11110000], &info(6, 0, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b11111111u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], 6, 1, bits_pp);
++    expand_pass(&mut img, width, &[0b11110000], &info(6, 1, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b11111111u8, 0, 0b11111111, 0, 0b10101010, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], 6, 2, bits_pp);
++    expand_pass(&mut img, width, &[0b11110000], &info(6, 2, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], 6, 3, bits_pp);
++    expand_pass(&mut img, width, &[0b11110000], &info(6, 3, width), bits_pp);
+     assert_eq!(
+         [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b11111111, 0],
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], 7, 0, bits_pp);
++    expand_pass(&mut img, width, &[0b11111111], &info(7, 0, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -382,7 +377,7 @@ fn test_expand_pass_subbyte() {
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], 7, 1, bits_pp);
++    expand_pass(&mut img, width, &[0b11111111], &info(7, 1, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -397,7 +392,7 @@ fn test_expand_pass_subbyte() {
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], 7, 2, bits_pp);
++    expand_pass(&mut img, width, &[0b11111111], &info(7, 2, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -412,7 +407,7 @@ fn test_expand_pass_subbyte() {
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], 7, 3, bits_pp);
++    expand_pass(&mut img, width, &[0b11111111], &info(7, 3, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -427,3 +422,17 @@ fn test_expand_pass_subbyte() {
+         img
+     );
+ }
++
++#[cfg(test)]
++fn create_adam7_info_for_tests(pass: u8, line: u32, img_width: u32) -> Adam7Info {
++    let width = {
++        let img_height = 8;
++        Adam7Iterator::new(img_width, img_height)
++            .filter(|info| info.pass == pass)
++            .map(|info| info.width)
++            .next()
++            .unwrap()
++    };
++
++    Adam7Info { pass, line, width }
++}
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
+index a5f2e70..bbd5953 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
+@@ -131,6 +131,15 @@ pub enum InterlaceInfo {
+     Adam7(adam7::Adam7Info),
+ }
+ 
++impl InterlaceInfo {
++    fn get_adam7_info(&self) -> Option<&adam7::Adam7Info> {
++        match self {
++            InterlaceInfo::Null => None,
++            InterlaceInfo::Adam7(adam7info) => Some(adam7info),
++        }
++    }
++}
++
+ /// A row of data without interlace information.
+ #[derive(Clone, Copy, Debug)]
+ pub struct Row<'data> {
+@@ -544,20 +553,19 @@ impl<R: Read> Reader<R> {
+         self.data_stream.clear();
+         self.current_start = 0;
+         self.prev_start = 0;
+-        let width = self.info().width;
+         if self.info().interlaced {
++            let width = self.info().width;
++            let samples = color_type.samples() as u8;
++            let bits_pp = samples * (bit_depth as u8);
+             while let Some(InterlacedRow {
+                 data: row,
+                 interlace,
+                 ..
+             }) = self.next_interlaced_row()?
+             {
+-                let (line, pass) = match interlace {
+-                    InterlaceInfo::Adam7(adam7::Adam7Info { line, pass, .. }) => (line, pass),
+-                    InterlaceInfo::Null => unreachable!("expected interlace information"),
+-                };
+-                let samples = color_type.samples() as u8;
+-                adam7::expand_pass(buf, width, row, pass, line, samples * (bit_depth as u8));
++                // `unwrap` won't panic, because we checked `self.info().interlaced` above.
++                let adam7info = interlace.get_adam7_info().unwrap();
++                adam7::expand_pass(buf, width, row, &adam7info, bits_pp);
+             }
+         } else {
+             for row in buf
+-- 
+2.46.0.598.g6f2099f65c-goog
+
diff --git a/third_party/rust/chromium_crates_io/patches/png/0103-Passing-Adam7Info-to-fn-expand_adam7_bits.patch b/third_party/rust/chromium_crates_io/patches/png/0103-Passing-Adam7Info-to-fn-expand_adam7_bits.patch
new file mode 100644
index 0000000..dba1eba
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/patches/png/0103-Passing-Adam7Info-to-fn-expand_adam7_bits.patch
@@ -0,0 +1,149 @@
+From fa12d377c046bbb1e20805552cf4866977ba3c77 Mon Sep 17 00:00:00 2001
+From: Lukasz Anforowicz <lukasza@chromium.org>
+Date: Thu, 29 Aug 2024 19:02:27 +0000
+Subject: [PATCH 103/107] Passing `&Adam7Info` to `fn expand_adam7_bits`.
+
+Instead of passing `line_no` and `pass` as separate parameters, we
+can pass a single `&Adam7Info` parameter.  This minor refactoring
+helps with:
+
+* Cleaning up `fn expand_pass` by moving some of its complexity closer
+  to where its needed (within `fn expand_adam7_bits`)
+* Preparing for changing the semantics of the `width` parameter of
+  `fn expand_adam7_bits` in a follow-up commit, where we will stop
+  depending on `width` for calculating the length of the returned
+  iterator (depending on `Adam7Info.width` instead).  See the follow-up
+  commit for more details.
+---
+ src/adam7.rs | 46 ++++++++++++++++++++++------------------------
+ 1 file changed, 22 insertions(+), 24 deletions(-)
+
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+index 213bb6d..51667f7 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+@@ -117,14 +117,13 @@ fn subbyte_pixels(scanline: &[u8], bits_pp: usize) -> impl Iterator<Item = u8> +
+         })
+ }
+ 
+-/// Given pass, image width, and line number, produce an iterator of bit positions of pixels to copy
+-/// from the input scanline to the image buffer.
+-fn expand_adam7_bits(
+-    pass: u8,
+-    width: usize,
+-    line_no: usize,
+-    bits_pp: usize,
+-) -> StepBy<Range<usize>> {
++/// Given image `width`, interlace `info`, and bits-per-pixel, produce an iterator of bit positions
++/// of pixels to copy from the input scanline to the image buffer.  The positions are expressed as
++/// bit offsets from position (0,0) in the frame that is currently being decoded.
++fn expand_adam7_bits(width: usize, info: &Adam7Info, bits_pp: usize) -> StepBy<Range<usize>> {
++    let line_no = info.line as usize;
++    let pass = info.pass;
++
+     let (line_mul, line_off, samp_mul, samp_off) = match pass {
+         1 => (8, 0, 8, 0),
+         2 => (8, 0, 8, 4),
+@@ -133,7 +132,11 @@ fn expand_adam7_bits(
+         5 => (4, 2, 2, 0),
+         6 => (2, 0, 2, 1),
+         7 => (2, 1, 1, 0),
+-        _ => panic!("Adam7 pass out of range: {}", pass),
++        _ => {
++            // `Adam7Info.pass` is a non-`pub`lic field.  `InterlaceInfo` is expected
++            // to maintain an invariant that `pass` is valid.
++            panic!("Invalid `Adam7Info.pass`");
++        }
+     };
+ 
+     // the equivalent line number in progressive scan
+@@ -150,16 +153,9 @@ fn expand_adam7_bits(
+ /// Expands an Adam 7 pass
+ pub fn expand_pass(img: &mut [u8], width: u32, scanline: &[u8], info: &Adam7Info, bits_pp: u8) {
+     let width = width as usize;
+-    let line_no = info.line as usize;
+-    let pass = info.pass;
+     let bits_pp = bits_pp as usize;
+ 
+-    // pass is out of range but don't blow up
+-    if pass == 0 || pass > 7 {
+-        return;
+-    }
+-
+-    let bit_indices = expand_adam7_bits(pass, width, line_no, bits_pp);
++    let bit_indices = expand_adam7_bits(width, info, bits_pp);
+ 
+     if bits_pp < 8 {
+         for (pos, px) in bit_indices.zip(subbyte_pixels(scanline, bits_pp)) {
+@@ -242,6 +238,8 @@ fn test_subbyte_pixels() {
+ fn test_expand_adam7_bits() {
+     let width = 32;
+     let bits_pp = 1;
++    let info =
++        |pass, line, img_width| create_adam7_info_for_tests(pass, line as u32, img_width as u32);
+ 
+     let expected = |offset: usize, step: usize, count: usize| {
+         (0..count)
+@@ -253,21 +251,21 @@ fn test_expand_adam7_bits() {
+         let start = 8 * line_no * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(1, width, line_no, bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(width, &info(1, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 8, 4)
+         );
+ 
+         let start = start + 4;
+ 
+         assert_eq!(
+-            expand_adam7_bits(2, width, line_no, bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(width, &info(2, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 8, 4)
+         );
+ 
+         let start = (8 * line_no + 4) * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(3, width, line_no, bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(width, &info(3, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 4, 8)
+         );
+     }
+@@ -276,14 +274,14 @@ fn test_expand_adam7_bits() {
+         let start = 4 * line_no * width + 2;
+ 
+         assert_eq!(
+-            expand_adam7_bits(4, width, line_no, bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(width, &info(4, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 4, 8)
+         );
+ 
+         let start = (4 * line_no + 2) * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(5, width, line_no, bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(width, &info(5, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 2, 16)
+         )
+     }
+@@ -292,7 +290,7 @@ fn test_expand_adam7_bits() {
+         let start = 2 * line_no * width + 1;
+ 
+         assert_eq!(
+-            expand_adam7_bits(6, width, line_no, bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(width, &info(6, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 2, 16),
+             "line_no: {}",
+             line_no
+@@ -301,7 +299,7 @@ fn test_expand_adam7_bits() {
+         let start = (2 * line_no + 1) * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(7, width, line_no, bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(width, &info(7, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 1, 32)
+         );
+     }
+-- 
+2.46.0.598.g6f2099f65c-goog
+
diff --git a/third_party/rust/chromium_crates_io/patches/png/0104-Independent-row_stride_in_bytes-in-expand_adam7_bits.patch b/third_party/rust/chromium_crates_io/patches/png/0104-Independent-row_stride_in_bytes-in-expand_adam7_bits.patch
new file mode 100644
index 0000000..66c481e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/patches/png/0104-Independent-row_stride_in_bytes-in-expand_adam7_bits.patch
@@ -0,0 +1,319 @@
+From d19fa0957bc4910fc8235ff53b6f0b2578f73c62 Mon Sep 17 00:00:00 2001
+From: Lukasz Anforowicz <lukasza@chromium.org>
+Date: Thu, 29 Aug 2024 20:09:49 +0000
+Subject: [PATCH 104/107] Independent `row_stride_in_bytes` in
+ `expand_adam7_bits`.
+
+This commit refactors implementation of `expand_adam7_bits` so that it
+can accept `row_stride_in_bytes` that is different from the expanded
+width of the frame or image.
+
+This is helpful for making `expand_pass` work in scenarios where
+interlaced row needs to expanded into a bigger image (e.g. if the
+currently decoded frame is an animation frame that only takes a
+subregion of the whole image - in this case the stride between expanded
+rows is bigger than the size of expanded rows).
+
+And the above is helpful for exposing `expand_pass` through a public API
+that will hopefully pass the test of time...
+---
+ src/adam7.rs       | 105 ++++++++++++++++++++++++++++-----------------
+ src/decoder/mod.rs |   4 +-
+ 2 files changed, 68 insertions(+), 41 deletions(-)
+
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+index 51667f7..2863f2a 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+@@ -1,7 +1,5 @@
+ //! Utility functions related to handling of
+ //! [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm).
+-use std::iter::StepBy;
+-use std::ops::Range;
+ 
+ /// Describes which stage of
+ /// [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm)
+@@ -117,12 +115,17 @@ fn subbyte_pixels(scanline: &[u8], bits_pp: usize) -> impl Iterator<Item = u8> +
+         })
+ }
+ 
+-/// Given image `width`, interlace `info`, and bits-per-pixel, produce an iterator of bit positions
++/// Given `row_stride`, interlace `info`, and bits-per-pixel, produce an iterator of bit positions
+ /// of pixels to copy from the input scanline to the image buffer.  The positions are expressed as
+ /// bit offsets from position (0,0) in the frame that is currently being decoded.
+-fn expand_adam7_bits(width: usize, info: &Adam7Info, bits_pp: usize) -> StepBy<Range<usize>> {
++fn expand_adam7_bits(
++    row_stride_in_bytes: usize,
++    info: &Adam7Info,
++    bits_pp: usize,
++) -> impl Iterator<Item = usize> {
+     let line_no = info.line as usize;
+     let pass = info.pass;
++    let interlaced_width = info.width as usize;
+ 
+     let (line_mul, line_off, samp_mul, samp_off) = match pass {
+         1 => (8, 0, 8, 0),
+@@ -141,21 +144,19 @@ fn expand_adam7_bits(width: usize, info: &Adam7Info, bits_pp: usize) -> StepBy<R
+ 
+     // the equivalent line number in progressive scan
+     let prog_line = line_mul * line_no + line_off;
+-    // line width is rounded up to the next byte
+-    let line_width = (width * bits_pp + 7) & !7;
+-    let line_start = prog_line * line_width;
+-    let start = line_start + (samp_off * bits_pp);
+-    let stop = line_start + (width * bits_pp);
++    let line_start = prog_line * row_stride_in_bytes * 8;
+ 
+-    (start..stop).step_by(bits_pp * samp_mul)
++    (0..interlaced_width)
++        .map(move |i| i * samp_mul + samp_off)
++        .map(move |i| i * bits_pp)
++        .map(move |bits_offset| bits_offset + line_start)
+ }
+ 
+ /// Expands an Adam 7 pass
+-pub fn expand_pass(img: &mut [u8], width: u32, scanline: &[u8], info: &Adam7Info, bits_pp: u8) {
+-    let width = width as usize;
++pub fn expand_pass(img: &mut [u8], stride: usize, scanline: &[u8], info: &Adam7Info, bits_pp: u8) {
+     let bits_pp = bits_pp as usize;
+ 
+-    let bit_indices = expand_adam7_bits(width, info, bits_pp);
++    let bit_indices = expand_adam7_bits(stride, info, bits_pp);
+ 
+     if bits_pp < 8 {
+         for (pos, px) in bit_indices.zip(subbyte_pixels(scanline, bits_pp)) {
+@@ -238,8 +239,8 @@ fn test_subbyte_pixels() {
+ fn test_expand_adam7_bits() {
+     let width = 32;
+     let bits_pp = 1;
+-    let info =
+-        |pass, line, img_width| create_adam7_info_for_tests(pass, line as u32, img_width as u32);
++    let stride = width / 8;
++    let info = |pass, line, img_width| create_adam7_info_for_tests(pass, line as u32, img_width);
+ 
+     let expected = |offset: usize, step: usize, count: usize| {
+         (0..count)
+@@ -251,21 +252,21 @@ fn test_expand_adam7_bits() {
+         let start = 8 * line_no * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(width, &info(1, line_no, width), bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(stride, &info(1, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 8, 4)
+         );
+ 
+         let start = start + 4;
+ 
+         assert_eq!(
+-            expand_adam7_bits(width, &info(2, line_no, width), bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(stride, &info(2, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 8, 4)
+         );
+ 
+         let start = (8 * line_no + 4) * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(width, &info(3, line_no, width), bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(stride, &info(3, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 4, 8)
+         );
+     }
+@@ -274,14 +275,14 @@ fn test_expand_adam7_bits() {
+         let start = 4 * line_no * width + 2;
+ 
+         assert_eq!(
+-            expand_adam7_bits(width, &info(4, line_no, width), bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(stride, &info(4, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 4, 8)
+         );
+ 
+         let start = (4 * line_no + 2) * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(width, &info(5, line_no, width), bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(stride, &info(5, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 2, 16)
+         )
+     }
+@@ -290,7 +291,7 @@ fn test_expand_adam7_bits() {
+         let start = 2 * line_no * width + 1;
+ 
+         assert_eq!(
+-            expand_adam7_bits(width, &info(6, line_no, width), bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(stride, &info(6, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 2, 16),
+             "line_no: {}",
+             line_no
+@@ -299,68 +300,94 @@ fn test_expand_adam7_bits() {
+         let start = (2 * line_no + 1) * width;
+ 
+         assert_eq!(
+-            expand_adam7_bits(width, &info(7, line_no, width), bits_pp).collect::<Vec<_>>(),
++            expand_adam7_bits(stride, &info(7, line_no, width), bits_pp).collect::<Vec<_>>(),
+             expected(start, 1, 32)
+         );
+     }
+ }
+ 
++#[test]
++fn test_expand_adam7_bits_independent_row_stride() {
++    let pass = 1;
++    let line_no = 1;
++    let width = 32;
++    let bits_pp = 8;
++    let info = create_adam7_info_for_tests;
++
++    {
++        let stride = width;
++        assert_eq!(
++            expand_adam7_bits(stride, &info(pass, line_no, width), bits_pp).collect::<Vec<_>>(),
++            vec![2048, 2112, 2176, 2240],
++        );
++    }
++
++    {
++        let stride = 10000;
++        assert_eq!(
++            expand_adam7_bits(stride, &info(pass, line_no, width), bits_pp).collect::<Vec<_>>(),
++            vec![640000, 640064, 640128, 640192],
++        );
++    }
++}
++
+ #[test]
+ fn test_expand_pass_subbyte() {
+     let mut img = [0u8; 8];
+     let width = 8;
++    let stride = width / 8;
+     let bits_pp = 1;
+     let info = create_adam7_info_for_tests;
+ 
+-    expand_pass(&mut img, width, &[0b10000000], &info(1, 0, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b10000000], &info(1, 0, width), bits_pp);
+     assert_eq!(img, [0b10000000u8, 0, 0, 0, 0, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b10000000], &info(2, 0, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b10000000], &info(2, 0, width), bits_pp);
+     assert_eq!(img, [0b10001000u8, 0, 0, 0, 0, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11000000], &info(3, 0, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11000000], &info(3, 0, width), bits_pp);
+     assert_eq!(img, [0b10001000u8, 0, 0, 0, 0b10001000, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11000000], &info(4, 0, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11000000], &info(4, 0, width), bits_pp);
+     assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10001000, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11000000], &info(4, 1, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11000000], &info(4, 1, width), bits_pp);
+     assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10101010, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11110000], &info(5, 0, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11110000], &info(5, 0, width), bits_pp);
+     assert_eq!(img, [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0, 0]);
+ 
+-    expand_pass(&mut img, width, &[0b11110000], &info(5, 1, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11110000], &info(5, 1, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], &info(6, 0, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11110000], &info(6, 0, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b11111111u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], &info(6, 1, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11110000], &info(6, 1, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b11111111u8, 0, 0b11111111, 0, 0b10101010, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], &info(6, 2, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11110000], &info(6, 2, width), bits_pp);
+     assert_eq!(
+         img,
+         [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b10101010, 0]
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11110000], &info(6, 3, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11110000], &info(6, 3, width), bits_pp);
+     assert_eq!(
+         [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b11111111, 0],
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], &info(7, 0, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11111111], &info(7, 0, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -375,7 +402,7 @@ fn test_expand_pass_subbyte() {
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], &info(7, 1, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11111111], &info(7, 1, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -390,7 +417,7 @@ fn test_expand_pass_subbyte() {
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], &info(7, 2, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11111111], &info(7, 2, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -405,7 +432,7 @@ fn test_expand_pass_subbyte() {
+         img
+     );
+ 
+-    expand_pass(&mut img, width, &[0b11111111], &info(7, 3, width), bits_pp);
++    expand_pass(&mut img, stride, &[0b11111111], &info(7, 3, width), bits_pp);
+     assert_eq!(
+         [
+             0b11111111u8,
+@@ -422,10 +449,10 @@ fn test_expand_pass_subbyte() {
+ }
+ 
+ #[cfg(test)]
+-fn create_adam7_info_for_tests(pass: u8, line: u32, img_width: u32) -> Adam7Info {
++fn create_adam7_info_for_tests(pass: u8, line: u32, img_width: usize) -> Adam7Info {
+     let width = {
+         let img_height = 8;
+-        Adam7Iterator::new(img_width, img_height)
++        Adam7Iterator::new(img_width as u32, img_height)
+             .filter(|info| info.pass == pass)
+             .map(|info| info.width)
+             .next()
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
+index bbd5953..8f50e9b 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
+@@ -554,7 +554,7 @@ impl<R: Read> Reader<R> {
+         self.current_start = 0;
+         self.prev_start = 0;
+         if self.info().interlaced {
+-            let width = self.info().width;
++            let stride = self.output_line_size(self.info().width);
+             let samples = color_type.samples() as u8;
+             let bits_pp = samples * (bit_depth as u8);
+             while let Some(InterlacedRow {
+@@ -565,7 +565,7 @@ impl<R: Read> Reader<R> {
+             {
+                 // `unwrap` won't panic, because we checked `self.info().interlaced` above.
+                 let adam7info = interlace.get_adam7_info().unwrap();
+-                adam7::expand_pass(buf, width, row, &adam7info, bits_pp);
++                adam7::expand_pass(buf, stride, row, &adam7info, bits_pp);
+             }
+         } else {
+             for row in buf
+-- 
+2.46.0.598.g6f2099f65c-goog
+
diff --git a/third_party/rust/chromium_crates_io/patches/png/0105-New-public-API-pub-fn-expand_interlaced_row.patch b/third_party/rust/chromium_crates_io/patches/png/0105-New-public-API-pub-fn-expand_interlaced_row.patch
new file mode 100644
index 0000000..8601f12
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/patches/png/0105-New-public-API-pub-fn-expand_interlaced_row.patch
@@ -0,0 +1,94 @@
+From 83c89cd36644e73648ea100128370cbcab6a3834 Mon Sep 17 00:00:00 2001
+From: Lukasz Anforowicz <lukasza@chromium.org>
+Date: Wed, 28 Aug 2024 23:22:26 +0000
+Subject: [PATCH 105/107] New public API: `pub fn expand_interlaced_row`.
+
+This also exposes supporting items through the public API: `Adam7Info`,
+`InterlaceInfo`, `InterlacedRow`.
+---
+ src/adam7.rs | 35 +++++++++++++++++++++++++++--------
+ src/lib.rs   |  5 ++++-
+ 2 files changed, 31 insertions(+), 9 deletions(-)
+
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+index 2863f2a..4d65be8 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+@@ -5,7 +5,7 @@
+ /// [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm)
+ /// applies to a decoded row.
+ ///
+-/// See also [Reader::next_interlaced_row].
++/// See also [crate::decoder::Reader::next_interlaced_row].
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+ pub struct Adam7Info {
+     pub(crate) pass: u8,
+@@ -152,21 +152,40 @@ fn expand_adam7_bits(
+         .map(move |bits_offset| bits_offset + line_start)
+ }
+ 
+-/// Expands an Adam 7 pass
+-pub fn expand_pass(img: &mut [u8], stride: usize, scanline: &[u8], info: &Adam7Info, bits_pp: u8) {
+-    let bits_pp = bits_pp as usize;
+-
+-    let bit_indices = expand_adam7_bits(stride, info, bits_pp);
++/// Copies pixels from `interlaced_row` into the right location in `img`.
++///
++/// First bytes of `img` should belong to the top-left corner of the currently decoded frame.
++///
++/// `img_row_stride` specifies an offset in bytes between subsequent rows of `img`.
++/// This can be the width of the current frame being decoded, but this is not required - a bigger
++/// stride may be useful if the frame being decoded is a sub-region of `img`.
++///
++/// `interlaced_row` and `interlace_info` typically come from
++/// [crate::decoder::Reader::next_interlaced_row], but this is not required.  In particular, before
++/// calling `expand_interlaced_row` one may need to expand the decoded row, so that its format and
++/// `bits_per_pixel` matches that of `img`.  Note that in initial Adam7 passes the `interlaced_row`
++/// may contain less pixels that the width of the frame being decoded (e.g. it contains only 1/8th
++/// of pixels in the initial pass).
++pub fn expand_pass(
++    img: &mut [u8],
++    img_row_stride: usize,
++    interlaced_row: &[u8],
++    interlace_info: &Adam7Info,
++    bits_per_pixel: u8,
++) {
++    let bits_pp = bits_per_pixel as usize;
++
++    let bit_indices = expand_adam7_bits(img_row_stride, interlace_info, bits_pp);
+ 
+     if bits_pp < 8 {
+-        for (pos, px) in bit_indices.zip(subbyte_pixels(scanline, bits_pp)) {
++        for (pos, px) in bit_indices.zip(subbyte_pixels(interlaced_row, bits_pp)) {
+             let rem = 8 - pos % 8 - bits_pp;
+             img[pos / 8] |= px << rem as u8;
+         }
+     } else {
+         let bytes_pp = bits_pp / 8;
+ 
+-        for (bitpos, px) in bit_indices.zip(scanline.chunks(bytes_pp)) {
++        for (bitpos, px) in bit_indices.zip(interlaced_row.chunks(bytes_pp)) {
+             for (offset, val) in px.iter().enumerate() {
+                 img[bitpos / 8 + offset] = *val;
+             }
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs
+index e514aa5..23c7b78 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs
+@@ -71,9 +71,12 @@ mod srgb;
+ pub mod text_metadata;
+ mod traits;
+ 
++pub use crate::adam7::expand_pass as expand_interlaced_row;
++pub use crate::adam7::Adam7Info;
+ pub use crate::common::*;
+ pub use crate::decoder::{
+-    DecodeOptions, Decoded, Decoder, DecodingError, Limits, OutputInfo, Reader, StreamingDecoder,
++    DecodeOptions, Decoded, Decoder, DecodingError, InterlaceInfo, InterlacedRow, Limits,
++    OutputInfo, Reader, StreamingDecoder,
+ };
+ pub use crate::encoder::{Encoder, EncodingError, StreamWriter, Writer};
+ pub use crate::filter::{AdaptiveFilterType, FilterType};
+-- 
+2.46.0.598.g6f2099f65c-goog
+
diff --git a/third_party/rust/chromium_crates_io/patches/png/0106-Fix-cargo-doc-warnings.patch b/third_party/rust/chromium_crates_io/patches/png/0106-Fix-cargo-doc-warnings.patch
new file mode 100644
index 0000000..638931b2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/patches/png/0106-Fix-cargo-doc-warnings.patch
@@ -0,0 +1,39 @@
+From ac04cd314dfa2259f8b2426c63a4b42c69fef0f8 Mon Sep 17 00:00:00 2001
+From: Lukasz Anforowicz <lukasza@chromium.org>
+Date: Fri, 30 Aug 2024 20:01:06 +0000
+Subject: [PATCH 106/107] Fix `cargo doc` warnings
+
+---
+ src/decoder/transform/palette.rs | 2 +-
+ src/text_metadata.rs             | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs
+index 0bf49f2..329c7bd 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs
+@@ -5,7 +5,7 @@
+ //!
+ //! To achieve higher throughput, `create_rgba_palette` combines entries from
+ //! `PLTE` and `trNS` chunks into a single lookup table.  This is based on the
+-//! ideas explored in https://crbug.com/706134.
++//! ideas explored in <https://crbug.com/706134>.
+ //!
+ //! Memoization is a trade-off:
+ //! * On one hand, memoization requires spending X ns before starting to call
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs
+index 18a2abe..7fc730f 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs
+@@ -145,7 +145,7 @@ pub(crate) enum TextDecodingError {
+ 
+ /// A generalized text chunk trait
+ pub trait EncodableTextChunk {
+-    /// Encode text chunk as Vec<u8> to a `Write`
++    /// Encode text chunk as `Vec<u8>` to a `Write`
+     fn encode<W: Write>(&self, w: &mut W) -> Result<(), EncodingError>;
+ }
+ 
+-- 
+2.46.0.598.g6f2099f65c-goog
+
diff --git a/third_party/rust/chromium_crates_io/patches/png/0107-Add-usage-example-to-the-doc-comment-of-fn-expand_in.patch b/third_party/rust/chromium_crates_io/patches/png/0107-Add-usage-example-to-the-doc-comment-of-fn-expand_in.patch
new file mode 100644
index 0000000..f4955b9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/patches/png/0107-Add-usage-example-to-the-doc-comment-of-fn-expand_in.patch
@@ -0,0 +1,76 @@
+From ddb54b298bc87079c2216d3bdc16749477d73cc1 Mon Sep 17 00:00:00 2001
+From: Lukasz Anforowicz <lukasza@chromium.org>
+Date: Fri, 30 Aug 2024 20:49:06 +0000
+Subject: [PATCH 107/107] Add usage example to the doc comment of `fn
+ expand_interlaced_row`.
+
+---
+ src/adam7.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+index 4d65be8..8016b8b 100644
+--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
++++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+@@ -13,6 +13,31 @@ pub struct Adam7Info {
+     pub(crate) width: u32,
+ }
+ 
++impl Adam7Info {
++    /// Creates a new `Adam7Info`.  May panic if the arguments are out of range (e.g. if `pass` is
++    /// 0 or greater than 8).
++    ///
++    /// * `pass` corresponds to a pass of the
++    ///   [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm)
++    /// * `line` is the number of a line within a pass (starting with 0).  For example,
++    ///   in an image of height 8, `line` can be beteween `0..4` in the 7th `pass`
++    ///   (those 4 interlaced rows correspond to 2nd, 4th, 6th, and 8th row of the full image).
++    /// * `width` describes how many pixels are in an interlaced row.  For example,
++    ///   in the 7th `pass`, the `width` is be the same as full image width, but in
++    ///   in the 1st `pass`, the `width` is be 1/8th of the image width (rounded up as
++    ///   necessary).
++    ///
++    /// Note that in typical usage, `Adam7Info`s are returned by [Reader::next_interlaced_row]
++    /// and there is no need to create them by calling `Adam7Info::new`.  `Adam7Info::new` is
++    /// nevertheless exposed as a public API, because it helps to provide self-contained example
++    /// usage of [expand_interlaced_row].
++    pub fn new(pass: u8, line: u32, width: u32) -> Self {
++        assert!(1 <= pass && pass <= 7);
++        assert!(width > 0);
++        Self { pass, line, width }
++    }
++}
++
+ /// This iterator iterates over the different passes of an image Adam7 encoded
+ /// PNG image
+ /// The pattern is:
+@@ -166,6 +191,26 @@ fn expand_adam7_bits(
+ /// `bits_per_pixel` matches that of `img`.  Note that in initial Adam7 passes the `interlaced_row`
+ /// may contain less pixels that the width of the frame being decoded (e.g. it contains only 1/8th
+ /// of pixels in the initial pass).
++///
++/// Example:
++///
++/// ```
++/// use png::{expand_interlaced_row, Adam7Info};
++/// let info = Adam7Info::new(5, 0, 4);  // 1st line of 5th pass has 4 pixels.
++/// let mut img = vec![0; 8 * 8];
++/// let row = vec![1, 2, 3, 4];
++/// expand_interlaced_row(&mut img, 8, &row, &info, 8);
++/// assert_eq!(&img, &[
++///     0, 0, 0, 0, 0, 0, 0, 0,
++///     0, 0, 0, 0, 0, 0, 0, 0,
++///     1, 0, 2, 0, 3, 0, 4, 0,  // <= this is where the 1st line of 5s appears
++///     0, 0, 0, 0, 0, 0, 0, 0,  //    in the schematic drawing of the passes at
++///     0, 0, 0, 0, 0, 0, 0, 0,  //    https://en.wikipedia.org/wiki/Adam7_algorithm
++///     0, 0, 0, 0, 0, 0, 0, 0,
++///     0, 0, 0, 0, 0, 0, 0, 0,
++///     0, 0, 0, 0, 0, 0, 0, 0,
++/// ]);
++/// ```
+ pub fn expand_pass(
+     img: &mut [u8],
+     img_row_stride: usize,
+-- 
+2.46.0.598.g6f2099f65c-goog
+
diff --git a/third_party/rust/chromium_crates_io/supply-chain/audits.toml b/third_party/rust/chromium_crates_io/supply-chain/audits.toml
index 047fd17..62fa4b2 100644
--- a/third_party/rust/chromium_crates_io/supply-chain/audits.toml
+++ b/third_party/rust/chromium_crates_io/supply-chain/audits.toml
@@ -178,6 +178,12 @@
 delta = "1.0.83 -> 1.0.86"
 notes = "Delta only updates the ensure macro implementation, still safe to run, no crypto"
 
+[[audits.anyhow]]
+who = "Adrian Taylor <adetaylor@chromium.org>"
+criteria = ["safe-to-run", "does-not-implement-crypto"]
+delta = "1.0.86 -> 1.0.87"
+notes = "Minimal changes, mostly renaming std to core for a type"
+
 [[audits.autocfg]]
 who = "Lukasz Anforowicz <lukasza@chromium.org>"
 criteria = ["ub-risk-0", "safe-to-deploy", "does-not-implement-crypto"]
@@ -330,6 +336,12 @@
 delta = "1.16.3 -> 1.17.1"
 notes = "Unsafe review comments can be found in https://crrev.com/c/5813463"
 
+[[audits.bytemuck]]
+who = "Adrian Taylor <adetaylor@chromium.org>"
+criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-2"]
+delta = "1.17.1 -> 1.18.0"
+notes = "No code changes - just altering feature flag arrangements"
+
 [[audits.bytemuck_derive]]
 who = "Lukasz Anforowicz <lukasza@chromium.org>"
 criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-2"]
@@ -1710,6 +1722,12 @@
 of the crate (in `src/de/format.rs` and `src/ser/impls.rs`).
 """
 
+[[audits.serde]]
+who = "Adrian Taylor <adetaylor@chromium.org>"
+criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-2"]
+delta = "1.0.209 -> 1.0.210"
+notes = "Almost no new code - just feature rearrangement"
+
 [[audits.serde_derive]]
 who = "Lukasz Anforowicz <lukasza@chromium.org>"
 criteria = "ub-risk-0"
@@ -1772,6 +1790,12 @@
 `\bnet\b`, and `\bunsafe\b`.  There were no hits.
 '''
 
+[[audits.serde_derive]]
+who = "Adrian Taylor <adetaylor@chromium.org>"
+criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-0"]
+delta = "1.0.209 -> 1.0.210"
+notes = "Almost no new code - just feature rearrangement"
+
 [[audits.serde_json]]
 who = "danakj@chromium.org"
 criteria = ["safe-to-run", "does-not-implement-crypto"]
diff --git a/third_party/rust/chromium_crates_io/supply-chain/config.toml b/third_party/rust/chromium_crates_io/supply-chain/config.toml
index 8f326d8..9c49f5d0 100644
--- a/third_party/rust/chromium_crates_io/supply-chain/config.toml
+++ b/third_party/rust/chromium_crates_io/supply-chain/config.toml
@@ -53,7 +53,7 @@
 [policy."anstyle:1.0.8"]
 criteria = ["crypto-safe", "safe-to-run"]
 
-[policy."anyhow:1.0.86"]
+[policy."anyhow:1.0.87"]
 criteria = ["crypto-safe", "safe-to-run"]
 
 [policy."base64:0.13.1"]
@@ -65,7 +65,7 @@
 [policy."bitflags:2.6.0"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."bytemuck:1.17.1"]
+[policy."bytemuck:1.18.0"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
 [policy."bytemuck_derive:1.7.1"]
@@ -74,7 +74,7 @@
 [policy."bytes:1.7.1"]
 criteria = ["crypto-safe", "safe-to-run"]
 
-[policy."cc:1.1.16"]
+[policy."cc:1.1.18"]
 criteria = []
 
 [policy."cfg-if:1.0.0"]
@@ -239,10 +239,10 @@
 [policy."semver:1.0.23"]
 criteria = ["crypto-safe", "safe-to-run"]
 
-[policy."serde:1.0.209"]
+[policy."serde:1.0.210"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."serde_derive:1.0.209"]
+[policy."serde_derive:1.0.210"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
 [policy."serde_json:1.0.128"]
@@ -337,7 +337,7 @@
 
 [[exemptions.cxx]]
 version = "1.0.128"
-criteria = ["safe-to-deploy", "ub-risk-2", "crypto-safe"]
+criteria = ["safe-to-deploy", "crypto-safe", "ub-risk-2"]
 notes = """
 Grandparented-in when setting up `cargo vet` in Jan 2024
 
@@ -355,7 +355,7 @@
 
 [[exemptions.cxxbridge-macro]]
 version = "1.0.128"
-criteria = ["safe-to-deploy", "ub-risk-2", "crypto-safe"]
+criteria = ["safe-to-deploy", "crypto-safe", "ub-risk-2"]
 notes = """
 Grandparented-in when setting up `cargo vet` in Jan 2024
 
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.cargo_vcs_info.json
deleted file mode 100644
index 2e2fc9b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "git": {
-    "sha1": "8ea1819c4c7829d0eb09e54a52806f382b8d445b"
-  },
-  "path_in_vcs": ""
-}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/compiletest.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/compiletest.rs
deleted file mode 100644
index 7974a62..0000000
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/compiletest.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#[rustversion::attr(not(nightly), ignore)]
-#[cfg_attr(miri, ignore)]
-#[test]
-fn ui() {
-    let t = trybuild::TestCases::new();
-    t.compile_fail("tests/ui/*.rs");
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.cargo-checksum.json
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.cargo-checksum.json
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.cargo-checksum.json
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.cargo_vcs_info.json
new file mode 100644
index 0000000..67960a39
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "afe93e7b167d069ac79f2c7f363b919d3793e6ce"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.github/FUNDING.yml b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.github/FUNDING.yml
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.github/FUNDING.yml
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.github/FUNDING.yml
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.github/workflows/ci.yml b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.github/workflows/ci.yml
similarity index 89%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.github/workflows/ci.yml
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.github/workflows/ci.yml
index 5f539d6..9e8a9ca 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.github/workflows/ci.yml
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.github/workflows/ci.yml
@@ -24,7 +24,7 @@
     strategy:
       fail-fast: false
       matrix:
-        rust: [nightly, beta, stable, 1.70.0]
+        rust: [nightly, beta, stable, 1.80.0, 1.70.0]
     timeout-minutes: 45
     steps:
       - uses: actions/checkout@v4
@@ -41,6 +41,11 @@
       - run: cargo test
       - run: cargo check --no-default-features
       - run: cargo check --features backtrace
+      - uses: actions/upload-artifact@v4
+        if: matrix.rust == 'nightly' && always()
+        with:
+          name: Cargo.lock
+          path: Cargo.lock
 
   build:
     name: Rust ${{matrix.rust}}
@@ -50,7 +55,7 @@
     strategy:
       fail-fast: false
       matrix:
-        rust: [1.65.0, 1.52.0, 1.51.0, 1.50.0, 1.39.0]
+        rust: [1.67.0, 1.65.0, 1.52.0, 1.51.0, 1.50.0, 1.39.0]
     timeout-minutes: 45
     steps:
       - uses: actions/checkout@v4
@@ -61,7 +66,7 @@
       - run: cargo check
       - run: cargo check --no-default-features
       - run: cargo check --features backtrace
-        if: matrix.rust != '1.52.0' && matrix.rust != '1.51.0' && matrix.rust != '1.50.0' && matrix.rust != '1.39.0'
+        if: matrix.rust != '1.65.0' && matrix.rust != '1.52.0' && matrix.rust != '1.51.0' && matrix.rust != '1.50.0' && matrix.rust != '1.39.0'
 
   minimal:
     name: Minimal versions
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.gitignore b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.gitignore
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/.gitignore
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/.gitignore
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/Cargo.toml
similarity index 95%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/Cargo.toml
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/Cargo.toml
index c06b4c7..d1f3e3e 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2018"
 rust-version = "1.39"
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.87"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 build = "build.rs"
 autobins = false
@@ -35,11 +35,7 @@
 repository = "https://github.com/dtolnay/anyhow"
 
 [package.metadata.docs.rs]
-rustdoc-args = [
-    "--cfg",
-    "doc_cfg",
-    "--generate-link-to-definition",
-]
+rustdoc-args = ["--generate-link-to-definition"]
 targets = ["x86_64-unknown-linux-gnu"]
 
 [lib]
@@ -48,61 +44,61 @@
 doc-scrape-examples = false
 
 [[test]]
-name = "test_ensure"
-path = "tests/test_ensure.rs"
-
-[[test]]
-name = "test_chain"
-path = "tests/test_chain.rs"
-
-[[test]]
-name = "test_fmt"
-path = "tests/test_fmt.rs"
-
-[[test]]
-name = "test_source"
-path = "tests/test_source.rs"
-
-[[test]]
-name = "test_repr"
-path = "tests/test_repr.rs"
+name = "compiletest"
+path = "tests/compiletest.rs"
 
 [[test]]
 name = "test_autotrait"
 path = "tests/test_autotrait.rs"
 
 [[test]]
-name = "test_boxed"
-path = "tests/test_boxed.rs"
-
-[[test]]
 name = "test_backtrace"
 path = "tests/test_backtrace.rs"
 
 [[test]]
-name = "test_convert"
-path = "tests/test_convert.rs"
+name = "test_boxed"
+path = "tests/test_boxed.rs"
 
 [[test]]
-name = "test_macros"
-path = "tests/test_macros.rs"
-
-[[test]]
-name = "compiletest"
-path = "tests/compiletest.rs"
+name = "test_chain"
+path = "tests/test_chain.rs"
 
 [[test]]
 name = "test_context"
 path = "tests/test_context.rs"
 
 [[test]]
-name = "test_ffi"
-path = "tests/test_ffi.rs"
+name = "test_convert"
+path = "tests/test_convert.rs"
 
 [[test]]
 name = "test_downcast"
 path = "tests/test_downcast.rs"
 
+[[test]]
+name = "test_ensure"
+path = "tests/test_ensure.rs"
+
+[[test]]
+name = "test_ffi"
+path = "tests/test_ffi.rs"
+
+[[test]]
+name = "test_fmt"
+path = "tests/test_fmt.rs"
+
+[[test]]
+name = "test_macros"
+path = "tests/test_macros.rs"
+
+[[test]]
+name = "test_repr"
+path = "tests/test_repr.rs"
+
+[[test]]
+name = "test_source"
+path = "tests/test_source.rs"
+
 [dependencies.backtrace]
 version = "0.3.51"
 optional = true
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/Cargo.toml.orig
similarity index 92%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/Cargo.toml.orig
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/Cargo.toml.orig
index f91b724a..41ab1000 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.87"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 categories = ["rust-patterns", "no-std"]
 description = "Flexible concrete Error type built on std::error::Error"
@@ -34,4 +34,4 @@
 
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
-rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"]
+rustdoc-args = ["--generate-link-to-definition"]
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/LICENSE-APACHE
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/LICENSE-APACHE
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/LICENSE-APACHE
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/LICENSE-MIT
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/LICENSE-MIT
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/LICENSE-MIT
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/README.md b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/README.md
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/README.md
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/README.md
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build.rs
similarity index 95%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build.rs
index 0d757e1..a065e04c5 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build.rs
@@ -67,10 +67,10 @@
 
     if rustc >= 80 {
         println!("cargo:rustc-check-cfg=cfg(anyhow_nightly_testing)");
+        println!("cargo:rustc-check-cfg=cfg(anyhow_no_core_error)");
         println!("cargo:rustc-check-cfg=cfg(anyhow_no_fmt_arguments_as_str)");
         println!("cargo:rustc-check-cfg=cfg(anyhow_no_ptr_addr_of)");
         println!("cargo:rustc-check-cfg=cfg(anyhow_no_unsafe_op_in_unsafe_fn_lint)");
-        println!("cargo:rustc-check-cfg=cfg(doc_cfg)");
         println!("cargo:rustc-check-cfg=cfg(error_generic_member_access)");
         println!("cargo:rustc-check-cfg=cfg(std_backtrace)");
     }
@@ -96,6 +96,12 @@
         // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis
         println!("cargo:rustc-cfg=std_backtrace");
     }
+
+    if rustc < 81 {
+        // core::error::Error
+        // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror
+        println!("cargo:rustc-cfg=anyhow_no_core_error");
+    }
 }
 
 fn compile_probe(rustc_bootstrap: bool) -> bool {
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build/probe.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build/probe.rs
similarity index 91%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build/probe.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build/probe.rs
index 21e776d..742d15c 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/build/probe.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/build/probe.rs
@@ -4,9 +4,9 @@
 
 #![feature(error_generic_member_access)]
 
+use core::error::{self, Error, Request};
+use core::fmt::{self, Debug, Display};
 use std::backtrace::Backtrace;
-use std::error::{self, Error, Request};
-use std::fmt::{self, Debug, Display};
 
 struct MyError(Thing);
 struct Thing;
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/rust-toolchain.toml b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/rust-toolchain.toml
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/rust-toolchain.toml
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/rust-toolchain.toml
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/backtrace.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/backtrace.rs
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/backtrace.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/backtrace.rs
index 44fb66c2..c9ca1a8f 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/backtrace.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/backtrace.rs
@@ -38,7 +38,8 @@
 #[cfg(error_generic_member_access)]
 macro_rules! backtrace_if_absent {
     ($err:expr) => {
-        match std::error::request_ref::<std::backtrace::Backtrace>($err as &dyn std::error::Error) {
+        match core::error::request_ref::<std::backtrace::Backtrace>($err as &dyn core::error::Error)
+        {
             Some(_) => None,
             None => backtrace!(),
         }
@@ -46,7 +47,7 @@
 }
 
 #[cfg(all(
-    feature = "std",
+    any(feature = "std", not(anyhow_no_core_error)),
     not(error_generic_member_access),
     any(std_backtrace, feature = "backtrace")
 ))]
@@ -56,7 +57,11 @@
     };
 }
 
-#[cfg(all(feature = "std", not(std_backtrace), not(feature = "backtrace")))]
+#[cfg(all(
+    any(feature = "std", not(anyhow_no_core_error)),
+    not(std_backtrace),
+    not(feature = "backtrace"),
+))]
 macro_rules! backtrace_if_absent {
     ($err:expr) => {
         None
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/chain.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/chain.rs
similarity index 82%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/chain.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/chain.rs
index b75885d..e56bc66 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/chain.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/chain.rs
@@ -1,13 +1,13 @@
 use self::ChainState::*;
 use crate::StdError;
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 use alloc::vec::{self, Vec};
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 pub(crate) use crate::Chain;
 
-#[cfg(not(feature = "std"))]
+#[cfg(all(not(feature = "std"), anyhow_no_core_error))]
 pub(crate) struct Chain<'a> {
     state: ChainState<'a>,
 }
@@ -17,7 +17,7 @@
     Linked {
         next: Option<&'a (dyn StdError + 'static)>,
     },
-    #[cfg(feature = "std")]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     Buffered {
         rest: vec::IntoIter<&'a (dyn StdError + 'static)>,
     },
@@ -42,7 +42,7 @@
                 *next = error.source();
                 Some(error)
             }
-            #[cfg(feature = "std")]
+            #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
             Buffered { rest } => rest.next(),
         }
     }
@@ -53,7 +53,7 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl DoubleEndedIterator for Chain<'_> {
     fn next_back(&mut self) -> Option<Self::Item> {
         match &mut self.state {
@@ -84,13 +84,13 @@
                 }
                 len
             }
-            #[cfg(feature = "std")]
+            #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
             Buffered { rest } => rest.len(),
         }
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl Default for Chain<'_> {
     fn default() -> Self {
         Chain {
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/context.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/context.rs
similarity index 96%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/context.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/context.rs
index 11b31ba..b52f682 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/context.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/context.rs
@@ -4,7 +4,7 @@
 use core::fmt::{self, Debug, Display, Write};
 
 #[cfg(error_generic_member_access)]
-use std::error::Request;
+use core::error::Request;
 
 mod ext {
     use super::*;
@@ -15,10 +15,10 @@
             C: Display + Send + Sync + 'static;
     }
 
-    #[cfg(feature = "std")]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     impl<E> StdError for E
     where
-        E: std::error::Error + Send + Sync + 'static,
+        E: crate::StdError + Send + Sync + 'static,
     {
         fn ext_context<C>(self, context: C) -> Error
         where
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/ensure.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/ensure.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/ensure.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/ensure.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/error.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/error.rs
similarity index 95%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/error.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/error.rs
index f24c4a6..6d8b54d 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/error.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/error.rs
@@ -1,21 +1,20 @@
 use crate::backtrace::Backtrace;
 use crate::chain::Chain;
-#[cfg(any(feature = "std", anyhow_no_ptr_addr_of))]
+#[cfg(any(feature = "std", not(anyhow_no_core_error), anyhow_no_ptr_addr_of))]
 use crate::ptr::Mut;
 use crate::ptr::{Own, Ref};
 use crate::{Error, StdError};
 use alloc::boxed::Box;
 use core::any::TypeId;
+#[cfg(error_generic_member_access)]
+use core::error::{self, Request};
 use core::fmt::{self, Debug, Display};
 use core::mem::ManuallyDrop;
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
+use core::ops::{Deref, DerefMut};
 #[cfg(not(anyhow_no_ptr_addr_of))]
 use core::ptr;
 use core::ptr::NonNull;
-#[cfg(error_generic_member_access)]
-use std::error::{self, Request};
-
-#[cfg(feature = "std")]
-use core::ops::{Deref, DerefMut};
 
 impl Error {
     /// Create a new error object from any error type.
@@ -25,8 +24,7 @@
     ///
     /// If the error type does not provide a backtrace, a backtrace will be
     /// created here to ensure that a backtrace exists.
-    #[cfg(feature = "std")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     #[cold]
     #[must_use]
     pub fn new<E>(error: E) -> Self
@@ -83,7 +81,7 @@
         Error::from_adhoc(message, backtrace!())
     }
 
-    #[cfg(feature = "std")]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     #[cold]
     pub(crate) fn from_std<E>(error: E, backtrace: Option<Backtrace>) -> Self
     where
@@ -120,7 +118,7 @@
         let vtable = &ErrorVTable {
             object_drop: object_drop::<MessageError<M>>,
             object_ref: object_ref::<MessageError<M>>,
-            #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
+            #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))]
             object_mut: object_mut::<MessageError<M>>,
             object_boxed: object_boxed::<MessageError<M>>,
             object_downcast: object_downcast::<M>,
@@ -149,7 +147,7 @@
         let vtable = &ErrorVTable {
             object_drop: object_drop::<DisplayError<M>>,
             object_ref: object_ref::<DisplayError<M>>,
-            #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
+            #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))]
             object_mut: object_mut::<DisplayError<M>>,
             object_boxed: object_boxed::<DisplayError<M>>,
             object_downcast: object_downcast::<M>,
@@ -168,7 +166,7 @@
         unsafe { Error::construct(error, vtable, backtrace) }
     }
 
-    #[cfg(feature = "std")]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     #[cold]
     pub(crate) fn from_context<C, E>(context: C, error: E, backtrace: Option<Backtrace>) -> Self
     where
@@ -198,7 +196,7 @@
         unsafe { Error::construct(error, vtable, backtrace) }
     }
 
-    #[cfg(feature = "std")]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     #[cold]
     pub(crate) fn from_boxed(
         error: Box<dyn StdError + Send + Sync>,
@@ -325,7 +323,7 @@
         let vtable = &ErrorVTable {
             object_drop: object_drop::<ContextError<C, Error>>,
             object_ref: object_ref::<ContextError<C, Error>>,
-            #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
+            #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))]
             object_mut: object_mut::<ContextError<C, Error>>,
             object_boxed: object_boxed::<ContextError<C, Error>>,
             object_downcast: context_chain_downcast::<C>,
@@ -399,8 +397,7 @@
     ///     None
     /// }
     /// ```
-    #[cfg(feature = "std")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     #[cold]
     pub fn chain(&self) -> Chain {
         unsafe { ErrorImpl::chain(self.inner.by_ref()) }
@@ -411,8 +408,7 @@
     ///
     /// The root cause is the last error in the iterator produced by
     /// [`chain()`][Error::chain].
-    #[cfg(feature = "std")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     pub fn root_cause(&self) -> &(dyn StdError + 'static) {
         self.chain().last().unwrap()
     }
@@ -554,8 +550,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl<E> From<E> for Error
 where
     E: StdError + Send + Sync + 'static,
@@ -567,8 +562,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl Deref for Error {
     type Target = dyn StdError + Send + Sync + 'static;
 
@@ -577,8 +571,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl DerefMut for Error {
     fn deref_mut(&mut self) -> &mut Self::Target {
         unsafe { ErrorImpl::error_mut(self.inner.by_mut()) }
@@ -609,7 +602,7 @@
 struct ErrorVTable {
     object_drop: unsafe fn(Own<ErrorImpl>),
     object_ref: unsafe fn(Ref<ErrorImpl>) -> Ref<dyn StdError + Send + Sync + 'static>,
-    #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
+    #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))]
     object_mut: unsafe fn(Mut<ErrorImpl>) -> &mut (dyn StdError + Send + Sync + 'static),
     object_boxed: unsafe fn(Own<ErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
     object_downcast: unsafe fn(Ref<ErrorImpl>, TypeId) -> Option<Ref<()>>,
@@ -661,7 +654,7 @@
 
 // Safety: requires layout of *e to match ErrorImpl<E>, and for `e` to be derived
 // from a `&mut`
-#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
+#[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))]
 unsafe fn object_mut<E>(e: Mut<ErrorImpl>) -> &mut (dyn StdError + Send + Sync + 'static)
 where
     E: StdError + Send + Sync + 'static,
@@ -734,7 +727,7 @@
 }
 
 // Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 unsafe fn context_downcast<C, E>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
 where
     C: 'static,
@@ -774,7 +767,7 @@
 }
 
 // Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 unsafe fn context_drop_rest<C, E>(e: Own<ErrorImpl>, target: TypeId)
 where
     C: 'static,
@@ -906,7 +899,7 @@
         unsafe { (vtable(this.ptr).object_ref)(this).deref() }
     }
 
-    #[cfg(feature = "std")]
+    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
     pub(crate) unsafe fn error_mut(this: Mut<Self>) -> &mut (dyn StdError + Send + Sync + 'static) {
         // Use vtable to attach E's native StdError vtable for the right
         // original type E.
@@ -1009,14 +1002,14 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl AsRef<dyn StdError + Send + Sync> for Error {
     fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
         &**self
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl AsRef<dyn StdError> for Error {
     fn as_ref(&self) -> &(dyn StdError + 'static) {
         &**self
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/fmt.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/fmt.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/fmt.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/fmt.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/kind.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/kind.rs
similarity index 89%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/kind.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/kind.rs
index 15d9f9b8..042af32 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/kind.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/kind.rs
@@ -47,9 +47,9 @@
 use crate::Error;
 use core::fmt::{Debug, Display};
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 use crate::StdError;
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 use alloc::boxed::Box;
 
 pub struct Adhoc;
@@ -96,10 +96,10 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 pub struct Boxed;
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 #[doc(hidden)]
 pub trait BoxedKind: Sized {
     #[inline]
@@ -108,10 +108,10 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl BoxedKind for Box<dyn StdError + Send + Sync> {}
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl Boxed {
     #[cold]
     pub fn new(self, error: Box<dyn StdError + Send + Sync>) -> Error {
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/lib.rs
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/lib.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/lib.rs
index 3991234..c0e20f350 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/lib.rs
@@ -206,9 +206,8 @@
 //! will require an explicit `.map_err(Error::msg)` when working with a
 //! non-Anyhow error type inside a function that returns Anyhow's error type.
 
-#![doc(html_root_url = "https://docs.rs/anyhow/1.0.85")]
+#![doc(html_root_url = "https://docs.rs/anyhow/1.0.87")]
 #![cfg_attr(error_generic_member_access, feature(error_generic_member_access))]
-#![cfg_attr(doc_cfg, feature(doc_cfg))]
 #![no_std]
 #![deny(dead_code, unused_imports, unused_mut)]
 #![cfg_attr(
@@ -266,13 +265,16 @@
 use crate::ptr::Own;
 use core::fmt::Display;
 
-#[cfg(not(feature = "std"))]
+#[cfg(all(not(feature = "std"), anyhow_no_core_error))]
 use core::fmt::Debug;
 
 #[cfg(feature = "std")]
 use std::error::Error as StdError;
 
-#[cfg(not(feature = "std"))]
+#[cfg(not(any(feature = "std", anyhow_no_core_error)))]
+use core::error::Error as StdError;
+
+#[cfg(all(not(feature = "std"), anyhow_no_core_error))]
 trait StdError: Debug + Display {
     fn source(&self) -> Option<&(dyn StdError + 'static)> {
         None
@@ -407,8 +409,7 @@
 ///     None
 /// }
 /// ```
-#[cfg(feature = "std")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 #[derive(Clone)]
 pub struct Chain<'a> {
     state: crate::chain::ChainState<'a>,
@@ -670,7 +671,7 @@
         #[doc(hidden)]
         pub use crate::kind::{AdhocKind, TraitKind};
 
-        #[cfg(feature = "std")]
+        #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
         #[doc(hidden)]
         pub use crate::kind::BoxedKind;
     }
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/macros.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/macros.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/macros.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/macros.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/ptr.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/ptr.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/ptr.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/ptr.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/wrapper.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/wrapper.rs
similarity index 84%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/wrapper.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/wrapper.rs
index 9726ae5..6f46779 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/src/wrapper.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/src/wrapper.rs
@@ -1,11 +1,11 @@
 use crate::StdError;
 use core::fmt::{self, Debug, Display};
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 use alloc::boxed::Box;
 
 #[cfg(error_generic_member_access)]
-use std::error::Request;
+use core::error::Request;
 
 #[repr(transparent)]
 pub struct MessageError<M>(pub M);
@@ -53,25 +53,25 @@
 
 impl<M> StdError for DisplayError<M> where M: Display + 'static {}
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 #[repr(transparent)]
 pub struct BoxedError(pub Box<dyn StdError + Send + Sync>);
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl Debug for BoxedError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         Debug::fmt(&self.0, f)
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl Display for BoxedError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         Display::fmt(&self.0, f)
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
 impl StdError for BoxedError {
     fn source(&self) -> Option<&(dyn StdError + 'static)> {
         self.0.source()
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/common/mod.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/common/mod.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/common/mod.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/common/mod.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/compiletest.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/compiletest.rs
new file mode 100644
index 0000000..23a6a06
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/compiletest.rs
@@ -0,0 +1,7 @@
+#[rustversion::attr(not(nightly), ignore = "requires nightly")]
+#[cfg_attr(miri, ignore = "incompatible with miri")]
+#[test]
+fn ui() {
+    let t = trybuild::TestCases::new();
+    t.compile_fail("tests/ui/*.rs");
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/drop/mod.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/drop/mod.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/drop/mod.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/drop/mod.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_autotrait.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_autotrait.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_autotrait.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_autotrait.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_backtrace.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_backtrace.rs
similarity index 88%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_backtrace.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_backtrace.rs
index c89559e..938c1c24 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_backtrace.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_backtrace.rs
@@ -1,7 +1,7 @@
 #![allow(clippy::let_underscore_untyped)]
 
 #[rustversion::not(nightly)]
-#[ignore]
+#[ignore = "requires nightly"]
 #[test]
 fn test_backtrace() {}
 
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_boxed.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_boxed.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_boxed.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_boxed.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_chain.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_chain.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_chain.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_chain.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_context.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_context.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_context.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_context.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_convert.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_convert.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_convert.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_convert.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_downcast.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_downcast.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_downcast.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_downcast.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_ensure.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_ensure.rs
similarity index 96%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_ensure.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_ensure.rs
index 96c236db..f41ad37 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_ensure.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_ensure.rs
@@ -153,18 +153,18 @@
     // identifier, nor as `(S + move || 1) == (1)` by misinterpreting the
     // closure precedence.
     let test = || Ok(ensure!(S + move || 1 == 1));
-    assert_err(test, "Condition failed: `S + (move || 1 == 1)`");
+    assert_err(test, "Condition failed: `S + move || 1 == 1`");
 
     let test = || Ok(ensure!(S + || 1 == 1));
-    assert_err(test, "Condition failed: `S + (|| 1 == 1)`");
+    assert_err(test, "Condition failed: `S + || 1 == 1`");
 
     // Must not partition as `S + ((move | ()) | 1) == 1` by treating those
     // pipes as bitwise-or.
     let test = || Ok(ensure!(S + move |()| 1 == 1));
-    assert_err(test, "Condition failed: `S + (move |()| 1 == 1)`");
+    assert_err(test, "Condition failed: `S + move |()| 1 == 1`");
 
     let test = || Ok(ensure!(S + |()| 1 == 1));
-    assert_err(test, "Condition failed: `S + (|()| 1 == 1)`");
+    assert_err(test, "Condition failed: `S + |()| 1 == 1`");
 }
 
 #[test]
@@ -224,7 +224,7 @@
     let test = || Ok(ensure!(if let | 1 | 2 = 2 {}.t(1) == 2));
     assert_err(
         test,
-        "Condition failed: `if let 1 | 2 = 2 {}.t(1) == 2` (1 vs 2)",
+        "Condition failed: `if let | 1 | 2 = 2 {}.t(1) == 2` (1 vs 2)",
     );
 }
 
@@ -269,7 +269,7 @@
     let test = || Ok(ensure!(for | _x in iter::once(0) {}.t(1) == 2));
     assert_err(
         test,
-        "Condition failed: `for _x in iter::once(0) {}.t(1) == 2` (1 vs 2)",
+        "Condition failed: `for | _x in iter::once(0) {}.t(1) == 2` (1 vs 2)",
     );
 
     #[rustfmt::skip]
@@ -286,7 +286,7 @@
     let test = || Ok(ensure!(match 1 == 1 { true => 1, false => 0 } == 2));
     assert_err(
         test,
-        "Condition failed: `match 1 == 1 { true => 1, false => 0, } == 2` (1 vs 2)",
+        "Condition failed: `match 1 == 1 { true => 1, false => 0 } == 2` (1 vs 2)",
     );
 }
 
@@ -343,7 +343,7 @@
     let test = || Ok(ensure!(Error::msg::<&str,>.t(1) == 2));
     assert_err(
         test,
-        "Condition failed: `Error::msg::<&str>.t(1) == 2` (1 vs 2)",
+        "Condition failed: `Error::msg::<&str,>.t(1) == 2` (1 vs 2)",
     );
 
     let test = || Ok(ensure!(Error::msg::<<str as ToOwned>::Owned>.t(1) == 2));
@@ -362,7 +362,7 @@
     let test = || Ok(ensure!(Chain::<'static,>::new.t(1) == 2));
     assert_err(
         test,
-        "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)",
+        "Condition failed: `Chain::<'static,>::new.t(1) == 2` (1 vs 2)",
     );
 
     fn f<const I: isize>() {}
@@ -394,7 +394,7 @@
 
     #[rustfmt::skip]
     let test = || Ok(ensure!(E::U::<u8,>>E::U));
-    assert_err(test, "Condition failed: `E::U::<u8> > E::U` (U vs U)");
+    assert_err(test, "Condition failed: `E::U::<u8,> > E::U` (U vs U)");
 
     let test = || Ok(ensure!(Generic::<dyn Debug + Sync> != Generic));
     assert_err(
@@ -416,7 +416,7 @@
     };
     assert_err(
         test,
-        "Condition failed: `Generic::<dyn Fn() + ::std::marker::Sync> != Generic` (Generic vs Generic)",
+        "Condition failed: `Generic::<dyn Fn::() + ::std::marker::Sync> != Generic` (Generic vs Generic)",
     );
 }
 
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_ffi.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_ffi.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_ffi.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_ffi.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_fmt.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_fmt.rs
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_fmt.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_fmt.rs
index 9766d366e..8206f22 100644
--- a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_fmt.rs
+++ b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_fmt.rs
@@ -79,7 +79,6 @@
 }
 
 #[test]
-#[cfg_attr(not(std_backtrace), ignore)]
 fn test_debug() {
     assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err()));
     assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err()));
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_macros.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_macros.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_macros.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_macros.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_repr.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_repr.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_repr.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_repr.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_source.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_source.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/test_source.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/test_source.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/chained-comparison.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/chained-comparison.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/chained-comparison.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/chained-comparison.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/chained-comparison.stderr b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/chained-comparison.stderr
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/chained-comparison.stderr
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/chained-comparison.stderr
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/empty-ensure.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/empty-ensure.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/empty-ensure.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/empty-ensure.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/empty-ensure.stderr b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/empty-ensure.stderr
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/empty-ensure.stderr
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/empty-ensure.stderr
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/ensure-nonbool.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/ensure-nonbool.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/ensure-nonbool.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/ensure-nonbool.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/ensure-nonbool.stderr b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/ensure-nonbool.stderr
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/ensure-nonbool.stderr
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/ensure-nonbool.stderr
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/must-use.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/must-use.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/must-use.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/must-use.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/must-use.stderr b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/must-use.stderr
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/must-use.stderr
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/must-use.stderr
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/no-impl.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/no-impl.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/no-impl.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/no-impl.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/no-impl.stderr b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/no-impl.stderr
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/no-impl.stderr
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/no-impl.stderr
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/temporary-value.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/temporary-value.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/temporary-value.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/temporary-value.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/temporary-value.stderr b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/temporary-value.stderr
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/temporary-value.stderr
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/temporary-value.stderr
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/wrong-interpolation.rs b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/wrong-interpolation.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/wrong-interpolation.rs
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/wrong-interpolation.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/wrong-interpolation.stderr b/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/wrong-interpolation.stderr
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/anyhow-1.0.86/tests/ui/wrong-interpolation.stderr
rename to third_party/rust/chromium_crates_io/vendor/anyhow-1.0.87/tests/ui/wrong-interpolation.stderr
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.cargo_vcs_info.json
deleted file mode 100644
index 0b1b236..0000000
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "git": {
-    "sha1": "dc059fd187c45cd9739aeedabd5e75e527058f90"
-  },
-  "path_in_vcs": ""
-}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.cargo-checksum.json
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.cargo-checksum.json
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.cargo-checksum.json
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.cargo/config.toml b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.cargo/config.toml
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.cargo/config.toml
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.cargo/config.toml
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.cargo_vcs_info.json
new file mode 100644
index 0000000..6f7d6f5
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "860c391345a2ec61fecf3cd46bcdde1add01caf9"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.github/FUNDING.yml b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.github/FUNDING.yml
similarity index 99%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.github/FUNDING.yml
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.github/FUNDING.yml
index 3509ccc1..d95e9c2 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.github/FUNDING.yml
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.github/FUNDING.yml
@@ -1,3 +1,3 @@
-# These are supported funding model platforms

-

-github: [Lokathor]

+# These are supported funding model platforms
+
+github: [Lokathor]
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.github/workflows/rust.yml b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.github/workflows/rust.yml
similarity index 99%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.github/workflows/rust.yml
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.github/workflows/rust.yml
index 5f39410..19ae2c55 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.github/workflows/rust.yml
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.github/workflows/rust.yml
@@ -1,111 +1,111 @@
-name: Rust

-

-on:

-  push: {}

-  pull_request: {}

-

-env:

-  RUST_BACKTRACE: 1

-

-jobs:

-  test:

-    name: Test Rust ${{ matrix.rust }} on ${{ matrix.os }}

-    runs-on: ${{ matrix.os }}

-    strategy:

-      matrix:

-        # it's a little tempting to use `matrix` to do a cartesian product with

-        # our `--feature` config here, but doing so will be very slow, as the

-        # free tier only supports up to 20 job runners at a time.

-        include:

-        # versions (all on linux-x86_64)

-        - { rust: 1.34.0, os: ubuntu-latest }

-        - { rust: stable, os: ubuntu-latest }

-        - { rust: beta, os: ubuntu-latest }

-        - { rust: nightly, os: ubuntu-latest }

-        # non-linux platforms (ones which don't require `cross`)

-        - { rust: stable, os: macos-latest }

-        - { rust: stable, os: windows-latest }

-        - { rust: stable-x86_64-gnu, os: windows-latest }

-        - { rust: stable-i686-msvc, os: windows-latest }

-        - { rust: stable-i686-gnu, os: windows-latest }

-    steps:

-    - uses: hecrj/setup-rust-action@v1

-      with:

-        rust-version: ${{ matrix.rust }}

-    - uses: actions/checkout@v3

-    - run: cargo test --verbose

-    - run: cargo test --verbose --no-default-features

-    - run: cargo test --verbose

-    - run: cargo test --verbose --all-features

-      if: matrix.rust == 'nightly'

-    - run: cargo test --verbose --manifest-path=derive/Cargo.toml --all-features

-      if: matrix.rust == 'nightly'

-

-  cross-test:

-    name: Test on ${{ matrix.target }} with cross

-    runs-on: ubuntu-latest

-    strategy:

-      matrix:

-        # we once had mips runners for Big-endian coverage but those got demoted to tier 3.

-        target: [i686-unknown-linux-gnu]

-    steps:

-    - uses: hecrj/setup-rust-action@v1

-      with:

-        rust-version: nightly

-    - uses: actions/checkout@v3

-    - run: cargo install cross

-    - run: cross test --verbose --target=${{ matrix.target }} --no-default-features

-    - run: cross test --verbose --target=${{ matrix.target }}

-    - run: cross test --verbose --target=${{ matrix.target }} --all-features

-      if: matrix.rust == 'nightly'

-    - run: cross test --verbose --target=${{ matrix.target }} --manifest-path=derive/Cargo.toml --all-features

-      if: matrix.rust == 'nightly'

-

-  miri-test:

-    name: Test with miri

-    runs-on: ubuntu-latest

-    steps:

-    - uses: hecrj/setup-rust-action@v1

-      with:

-        rust-version: nightly

-        components: miri

-    - uses: actions/checkout@v3

-    # Note(Lokathor): We got some cached json errors, and so we cargo clean for this run.

-    - run: rm -fr target

-    - run: cargo miri test --verbose --no-default-features

-    - run: cargo miri test --verbose --all-features

-    - run: cd derive && rm -fr target && cargo miri test --verbose --all-features

-

-  sanitizer-test:

-    name: Test with -Zsanitizer=${{ matrix.sanitizer }}

-    runs-on: ubuntu-latest

-    strategy:

-      fail-fast: false

-      matrix:

-        sanitizer: [address, memory, leak]

-    steps:

-    - uses: actions/checkout@v3

-    - uses: hecrj/setup-rust-action@v1

-      with:

-        rust-version: nightly

-        components: rust-src

-    - name: Test with sanitizer

-      env:

-        RUSTFLAGS: -Zsanitizer=${{ matrix.sanitizer }}

-        RUSTDOCFLAGS: -Zsanitizer=${{ matrix.sanitizer }}

-        ASAN_OPTIONS: detect_stack_use_after_return=1

-        # Asan's leak detection occasionally complains about some small leaks if

-        # backtraces are captured.

-        RUST_BACKTRACE: 0

-      # We don't run `derive`'s unit tests here the way we do elsewhere (for

-      # example, in `miri-test` above), as at the moment we can't easily build

-      # the `proc_macro` runtime with sanitizers on. IIUC doing this would

-      # require a custom rustc build, and... lol nope.

-      #

-      # This would mean only part of the code running under the sanitizer would

-      # actually include the sanitizer's checks, which is a recipe for false

-      # positives, so we just skip it, the generated code is what we care

-      # about anyway.

-      run: |

-        cargo test -Zbuild-std --verbose --target=x86_64-unknown-linux-gnu --no-default-features

-        cargo test -Zbuild-std --verbose --target=x86_64-unknown-linux-gnu --all-features

+name: Rust
+
+on:
+  push: {}
+  pull_request: {}
+
+env:
+  RUST_BACKTRACE: 1
+
+jobs:
+  test:
+    name: Test Rust ${{ matrix.rust }} on ${{ matrix.os }}
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        # it's a little tempting to use `matrix` to do a cartesian product with
+        # our `--feature` config here, but doing so will be very slow, as the
+        # free tier only supports up to 20 job runners at a time.
+        include:
+        # versions (all on linux-x86_64)
+        - { rust: 1.34.0, os: ubuntu-latest }
+        - { rust: stable, os: ubuntu-latest }
+        - { rust: beta, os: ubuntu-latest }
+        - { rust: nightly, os: ubuntu-latest }
+        # non-linux platforms (ones which don't require `cross`)
+        - { rust: stable, os: macos-latest }
+        - { rust: stable, os: windows-latest }
+        - { rust: stable-x86_64-gnu, os: windows-latest }
+        - { rust: stable-i686-msvc, os: windows-latest }
+        - { rust: stable-i686-gnu, os: windows-latest }
+    steps:
+    - uses: hecrj/setup-rust-action@v1
+      with:
+        rust-version: ${{ matrix.rust }}
+    - uses: actions/checkout@v3
+    - run: cargo test --verbose
+    - run: cargo test --verbose --no-default-features
+    - run: cargo test --verbose
+    - run: cargo test --verbose --all-features
+      if: matrix.rust == 'nightly'
+    - run: cargo test --verbose --manifest-path=derive/Cargo.toml --all-features
+      if: matrix.rust == 'nightly'
+
+  cross-test:
+    name: Test on ${{ matrix.target }} with cross
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        # we once had mips runners for Big-endian coverage but those got demoted to tier 3.
+        target: [i686-unknown-linux-gnu]
+    steps:
+    - uses: hecrj/setup-rust-action@v1
+      with:
+        rust-version: nightly
+    - uses: actions/checkout@v3
+    - run: cargo install cross
+    - run: cross test --verbose --target=${{ matrix.target }} --no-default-features
+    - run: cross test --verbose --target=${{ matrix.target }}
+    - run: cross test --verbose --target=${{ matrix.target }} --all-features
+      if: matrix.rust == 'nightly'
+    - run: cross test --verbose --target=${{ matrix.target }} --manifest-path=derive/Cargo.toml --all-features
+      if: matrix.rust == 'nightly'
+
+  miri-test:
+    name: Test with miri
+    runs-on: ubuntu-latest
+    steps:
+    - uses: hecrj/setup-rust-action@v1
+      with:
+        rust-version: nightly
+        components: miri
+    - uses: actions/checkout@v3
+    # Note(Lokathor): We got some cached json errors, and so we cargo clean for this run.
+    - run: rm -fr target
+    - run: cargo miri test --verbose --no-default-features
+    - run: cargo miri test --verbose --all-features
+    - run: cd derive && rm -fr target && cargo miri test --verbose --all-features
+
+  sanitizer-test:
+    name: Test with -Zsanitizer=${{ matrix.sanitizer }}
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        sanitizer: [address, memory, leak]
+    steps:
+    - uses: actions/checkout@v3
+    - uses: hecrj/setup-rust-action@v1
+      with:
+        rust-version: nightly
+        components: rust-src
+    - name: Test with sanitizer
+      env:
+        RUSTFLAGS: -Zsanitizer=${{ matrix.sanitizer }}
+        RUSTDOCFLAGS: -Zsanitizer=${{ matrix.sanitizer }}
+        ASAN_OPTIONS: detect_stack_use_after_return=1
+        # Asan's leak detection occasionally complains about some small leaks if
+        # backtraces are captured.
+        RUST_BACKTRACE: 0
+      # We don't run `derive`'s unit tests here the way we do elsewhere (for
+      # example, in `miri-test` above), as at the moment we can't easily build
+      # the `proc_macro` runtime with sanitizers on. IIUC doing this would
+      # require a custom rustc build, and... lol nope.
+      #
+      # This would mean only part of the code running under the sanitizer would
+      # actually include the sanitizer's checks, which is a recipe for false
+      # positives, so we just skip it, the generated code is what we care
+      # about anyway.
+      run: |
+        cargo test -Zbuild-std --verbose --target=x86_64-unknown-linux-gnu --no-default-features
+        cargo test -Zbuild-std --verbose --target=x86_64-unknown-linux-gnu --all-features
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.gitignore b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.gitignore
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/.gitignore
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/.gitignore
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/Cargo.toml
similarity index 93%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/Cargo.toml
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/Cargo.toml
index 819a6e7..c2d2b725c 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/Cargo.toml
@@ -12,7 +12,7 @@
 [package]
 edition = "2018"
 name = "bytemuck"
-version = "1.17.1"
+version = "1.18.0"
 authors = ["Lokathor <zefria@gmail.com>"]
 build = false
 exclude = ["/pedantic.bat"]
@@ -37,28 +37,16 @@
 [package.metadata.docs.rs]
 features = [
     "nightly_docs",
-    "derive",
+    "latest_stable_rust",
     "extern_crate_alloc",
     "extern_crate_std",
-    "zeroable_maybe_uninit",
-    "zeroable_atomics",
-    "min_const_generics",
-    "wasm_simd",
-    "must_cast",
-    "const_zeroed",
 ]
 
 [package.metadata.playground]
 features = [
-    "derive",
+    "latest_stable_rust",
     "extern_crate_alloc",
     "extern_crate_std",
-    "zeroable_maybe_uninit",
-    "zeroable_atomics",
-    "min_const_generics",
-    "wasm_simd",
-    "must_cast",
-    "const_zeroed",
 ]
 
 [lib]
@@ -112,6 +100,17 @@
 derive = ["bytemuck_derive"]
 extern_crate_alloc = []
 extern_crate_std = ["extern_crate_alloc"]
+latest_stable_rust = [
+    "aarch64_simd",
+    "align_offset",
+    "const_zeroed",
+    "derive",
+    "min_const_generics",
+    "must_cast",
+    "wasm_simd",
+    "zeroable_atomics",
+    "zeroable_maybe_uninit",
+]
 min_const_generics = []
 must_cast = []
 nightly_docs = []
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/Cargo.toml.orig
similarity index 84%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/Cargo.toml.orig
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/Cargo.toml.orig
index 337caa7d..c6577dbb 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/Cargo.toml.orig
@@ -1,7 +1,7 @@
 [package]
 name = "bytemuck"
 description = "A crate for mucking around with piles of bytes."
-version = "1.17.1"
+version = "1.18.0"
 authors = ["Lokathor <zefria@gmail.com>"]
 repository = "https://github.com/Lokathor/bytemuck"
 readme = "README.md"
@@ -39,6 +39,23 @@
 # Do not use if you can avoid it, because this is **unsound**!!!!
 unsound_ptr_pod_impl = []
 
+# Enables all features that are both sound and supported on the latest stable
+# version of Rust, with the exception of `extern_crate_alloc` and
+# `extern_crate_std`.
+# Note: Enabling this feature opts out of any MSRV guarantees!
+latest_stable_rust = [
+  # Keep this list sorted.
+  "aarch64_simd",
+  "align_offset",
+  "const_zeroed",
+  "derive",
+  "min_const_generics",
+  "must_cast",
+  "wasm_simd",
+  "zeroable_atomics",
+  "zeroable_maybe_uninit",
+]
+
 # NOT SEMVER SUPPORTED! TEMPORARY ONLY!
 nightly_portable_simd = []
 nightly_stdsimd = []
@@ -58,27 +75,15 @@
 # Note(Lokathor): Don't use all-features or it would use `unsound_ptr_pod_impl` too.
 features = [
   "nightly_docs",
-  "derive",
+  "latest_stable_rust",
   "extern_crate_alloc",
   "extern_crate_std",
-  "zeroable_maybe_uninit",
-  "zeroable_atomics",
-  "min_const_generics",
-  "wasm_simd",
-  "must_cast",
-  "const_zeroed",
 ]
 
 [package.metadata.playground]
 # Note(Lokathor): Don't use all-features or it would use `unsound_ptr_pod_impl` too.
 features = [
-  "derive",
+  "latest_stable_rust",
   "extern_crate_alloc",
   "extern_crate_std",
-  "zeroable_maybe_uninit",
-  "zeroable_atomics",
-  "min_const_generics",
-  "wasm_simd",
-  "must_cast",
-  "const_zeroed",
 ]
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-APACHE
similarity index 99%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-APACHE
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-APACHE
index 1d02268d..136d9004 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-APACHE
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-APACHE
@@ -1,61 +1,61 @@
-Apache License

-Version 2.0, January 2004

-http://www.apache.org/licenses/

-

-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

-    1. Definitions.

-

-        "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.

-

-        "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.

-

-        "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.

-

-        "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.

-

-        "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.

-

-        "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.

-

-        "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).

-

-        "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.

-

-        "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."

-

-        "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.

-    2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.

-    3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.

-    4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:

-        (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and

-        (b) You must cause any modified files to carry prominent notices stating that You changed the files; and

-        (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and

-        (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.

-

-        You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.

-    5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.

-    6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.

-    7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.

-    8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.

-    9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.

-

-END OF TERMS AND CONDITIONS

-

-APPENDIX: How to apply the Apache License to your work.

-

-To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.

-

-Copyright [yyyy] [name of copyright owner]

-

-Licensed under the Apache License, Version 2.0 (the "License");

-you may not use this file except in compliance with the License.

-You may obtain a copy of the License at

-

-http://www.apache.org/licenses/LICENSE-2.0

-

-Unless required by applicable law or agreed to in writing, software

-distributed under the License is distributed on an "AS IS" BASIS,

-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-See the License for the specific language governing permissions and

-limitations under the License.

+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+    1. Definitions.
+
+        "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+        "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+        "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+        "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+        "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+        "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+        "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+        "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+        "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+        "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+    2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+    3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+    4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+        (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+        (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+        (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+        (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+        You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+    5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+    6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+    7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+    8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+    9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-MIT
similarity index 99%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-MIT
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-MIT
index 0aa88160..164045fa 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-MIT
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-MIT
@@ -1,9 +1,9 @@
-MIT License

-

-Copyright (c) 2019 Daniel "Lokathor" Gee.

-

-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

-

-The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

-

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+MIT License
+
+Copyright (c) 2019 Daniel "Lokathor" Gee.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-ZLIB b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-ZLIB
similarity index 99%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-ZLIB
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-ZLIB
index aa2dabe..d70707c75 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/LICENSE-ZLIB
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/LICENSE-ZLIB
@@ -1,11 +1,11 @@
-Copyright (c) 2019 Daniel "Lokathor" Gee.

-

-This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

-

-Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

-

-1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.

-

-2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.

-

-3. This notice may not be removed or altered from any source distribution.

+Copyright (c) 2019 Daniel "Lokathor" Gee.
+
+This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/README.md b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/README.md
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/README.md
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/README.md
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/changelog.md b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/changelog.md
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/changelog.md
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/changelog.md
index b9fbf0f9..7cc8069f 100644
--- a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/changelog.md
+++ b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/changelog.md
@@ -1,12 +1,13 @@
 # `bytemuck` changelog
 
+## 1.18
+
+* Adds the `latest_stable_rust` cargo feature, which is a blanket feature that turns all other features on that are both sound and compatible with Stable rust.
+
 ## 1.17.1
 
 * Adds `#[repr(C)]` to the `union Transmute<A, B>` type that's used internally
-  for most of the transmutations. This doesn't matter in any current case and
-  there's no actual bug being fixed here, but it's a mild futureproof, and it's
-  probably best practice to have for when people who know the code less deeply
-  try to copy what we're doing into other contexts, so we'll go with it.
+  for most of the transmutations.
 
 ## 1.17.0
 
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/rustfmt.toml b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/rustfmt.toml
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/rustfmt.toml
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/rustfmt.toml
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/allocation.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/allocation.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/allocation.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/allocation.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/anybitpattern.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/anybitpattern.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/anybitpattern.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/anybitpattern.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/checked.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/checked.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/checked.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/checked.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/contiguous.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/contiguous.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/contiguous.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/contiguous.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/internal.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/internal.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/internal.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/internal.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/lib.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/lib.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/lib.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/must.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/must.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/must.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/must.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/no_uninit.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/no_uninit.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/no_uninit.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/no_uninit.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/offset_of.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/offset_of.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/offset_of.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/offset_of.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/pod.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/pod.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/pod.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/pod.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/pod_in_option.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/pod_in_option.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/pod_in_option.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/pod_in_option.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/transparent.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/transparent.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/transparent.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/transparent.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/zeroable.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/zeroable.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/zeroable.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/zeroable.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/zeroable_in_option.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/zeroable_in_option.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/src/zeroable_in_option.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/src/zeroable_in_option.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/array_tests.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/array_tests.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/array_tests.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/array_tests.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/cast_slice_tests.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/cast_slice_tests.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/cast_slice_tests.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/cast_slice_tests.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/checked_tests.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/checked_tests.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/checked_tests.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/checked_tests.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/derive.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/derive.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/derive.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/derive.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/doc_tests.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/doc_tests.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/doc_tests.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/doc_tests.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/offset_of_tests.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/offset_of_tests.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/offset_of_tests.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/offset_of_tests.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/std_tests.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/std_tests.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/std_tests.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/std_tests.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/transparent.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/transparent.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/transparent.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/transparent.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/wrapper_forgets.rs b/third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/wrapper_forgets.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/bytemuck-1.17.1/tests/wrapper_forgets.rs
rename to third_party/rust/chromium_crates_io/vendor/bytemuck-1.18.0/tests/wrapper_forgets.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/cc-1.1.16/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/cc-1.1.18/.cargo-checksum.json
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/cc-1.1.16/.cargo-checksum.json
rename to third_party/rust/chromium_crates_io/vendor/cc-1.1.18/.cargo-checksum.json
diff --git a/third_party/rust/chromium_crates_io/vendor/cc-1.1.16/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/cc-1.1.18/Cargo.toml
similarity index 96%
rename from third_party/rust/chromium_crates_io/vendor/cc-1.1.16/Cargo.toml
rename to third_party/rust/chromium_crates_io/vendor/cc-1.1.18/Cargo.toml
index dd2029b5..0ce2876 100644
--- a/third_party/rust/chromium_crates_io/vendor/cc-1.1.16/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/cc-1.1.18/Cargo.toml
@@ -10,7 +10,7 @@
 
 [package]
 name = "cc"
-version = "1.1.16"
+version = "1.1.18"
 
 [features]
 "jobserver" = []
diff --git a/third_party/rust/chromium_crates_io/vendor/cc-1.1.16/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/cc-1.1.18/src/lib.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/cc-1.1.16/src/lib.rs
rename to third_party/rust/chromium_crates_io/vendor/cc-1.1.18/src/lib.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
index 5bf7bb3..8016b8b 100644
--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
+++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/adam7.rs
@@ -1,6 +1,42 @@
-//! Utility functions
-use std::iter::StepBy;
-use std::ops::Range;
+//! Utility functions related to handling of
+//! [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm).
+
+/// Describes which stage of
+/// [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm)
+/// applies to a decoded row.
+///
+/// See also [crate::decoder::Reader::next_interlaced_row].
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct Adam7Info {
+    pub(crate) pass: u8,
+    pub(crate) line: u32,
+    pub(crate) width: u32,
+}
+
+impl Adam7Info {
+    /// Creates a new `Adam7Info`.  May panic if the arguments are out of range (e.g. if `pass` is
+    /// 0 or greater than 8).
+    ///
+    /// * `pass` corresponds to a pass of the
+    ///   [the Adam7 algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm)
+    /// * `line` is the number of a line within a pass (starting with 0).  For example,
+    ///   in an image of height 8, `line` can be beteween `0..4` in the 7th `pass`
+    ///   (those 4 interlaced rows correspond to 2nd, 4th, 6th, and 8th row of the full image).
+    /// * `width` describes how many pixels are in an interlaced row.  For example,
+    ///   in the 7th `pass`, the `width` is be the same as full image width, but in
+    ///   in the 1st `pass`, the `width` is be 1/8th of the image width (rounded up as
+    ///   necessary).
+    ///
+    /// Note that in typical usage, `Adam7Info`s are returned by [Reader::next_interlaced_row]
+    /// and there is no need to create them by calling `Adam7Info::new`.  `Adam7Info::new` is
+    /// nevertheless exposed as a public API, because it helps to provide self-contained example
+    /// usage of [expand_interlaced_row].
+    pub fn new(pass: u8, line: u32, width: u32) -> Self {
+        assert!(1 <= pass && pass <= 7);
+        assert!(width > 0);
+        Self { pass, line, width }
+    }
+}
 
 /// This iterator iterates over the different passes of an image Adam7 encoded
 /// PNG image
@@ -63,14 +99,18 @@
     }
 }
 
-/// Iterates over the (passes, lines, widths)
+/// Iterates over `Adam7Info`s.
 impl Iterator for Adam7Iterator {
-    type Item = (u8, u32, u32);
+    type Item = Adam7Info;
     fn next(&mut self) -> Option<Self::Item> {
         if self.line < self.lines && self.line_width > 0 {
             let this_line = self.line;
             self.line += 1;
-            Some((self.current_pass, this_line, self.line_width))
+            Some(Adam7Info {
+                pass: self.current_pass,
+                line: this_line,
+                width: self.line_width,
+            })
         } else if self.current_pass < 7 {
             self.current_pass += 1;
             self.init_pass();
@@ -100,14 +140,18 @@
         })
 }
 
-/// Given pass, image width, and line number, produce an iterator of bit positions of pixels to copy
-/// from the input scanline to the image buffer.
+/// Given `row_stride`, interlace `info`, and bits-per-pixel, produce an iterator of bit positions
+/// of pixels to copy from the input scanline to the image buffer.  The positions are expressed as
+/// bit offsets from position (0,0) in the frame that is currently being decoded.
 fn expand_adam7_bits(
-    pass: u8,
-    width: usize,
-    line_no: usize,
+    row_stride_in_bytes: usize,
+    info: &Adam7Info,
     bits_pp: usize,
-) -> StepBy<Range<usize>> {
+) -> impl Iterator<Item = usize> {
+    let line_no = info.line as usize;
+    let pass = info.pass;
+    let interlaced_width = info.width as usize;
+
     let (line_mul, line_off, samp_mul, samp_off) = match pass {
         1 => (8, 0, 8, 0),
         2 => (8, 0, 8, 4),
@@ -116,49 +160,77 @@
         5 => (4, 2, 2, 0),
         6 => (2, 0, 2, 1),
         7 => (2, 1, 1, 0),
-        _ => panic!("Adam7 pass out of range: {}", pass),
+        _ => {
+            // `Adam7Info.pass` is a non-`pub`lic field.  `InterlaceInfo` is expected
+            // to maintain an invariant that `pass` is valid.
+            panic!("Invalid `Adam7Info.pass`");
+        }
     };
 
     // the equivalent line number in progressive scan
     let prog_line = line_mul * line_no + line_off;
-    // line width is rounded up to the next byte
-    let line_width = (width * bits_pp + 7) & !7;
-    let line_start = prog_line * line_width;
-    let start = line_start + (samp_off * bits_pp);
-    let stop = line_start + (width * bits_pp);
+    let line_start = prog_line * row_stride_in_bytes * 8;
 
-    (start..stop).step_by(bits_pp * samp_mul)
+    (0..interlaced_width)
+        .map(move |i| i * samp_mul + samp_off)
+        .map(move |i| i * bits_pp)
+        .map(move |bits_offset| bits_offset + line_start)
 }
 
-/// Expands an Adam 7 pass
+/// Copies pixels from `interlaced_row` into the right location in `img`.
+///
+/// First bytes of `img` should belong to the top-left corner of the currently decoded frame.
+///
+/// `img_row_stride` specifies an offset in bytes between subsequent rows of `img`.
+/// This can be the width of the current frame being decoded, but this is not required - a bigger
+/// stride may be useful if the frame being decoded is a sub-region of `img`.
+///
+/// `interlaced_row` and `interlace_info` typically come from
+/// [crate::decoder::Reader::next_interlaced_row], but this is not required.  In particular, before
+/// calling `expand_interlaced_row` one may need to expand the decoded row, so that its format and
+/// `bits_per_pixel` matches that of `img`.  Note that in initial Adam7 passes the `interlaced_row`
+/// may contain less pixels that the width of the frame being decoded (e.g. it contains only 1/8th
+/// of pixels in the initial pass).
+///
+/// Example:
+///
+/// ```
+/// use png::{expand_interlaced_row, Adam7Info};
+/// let info = Adam7Info::new(5, 0, 4);  // 1st line of 5th pass has 4 pixels.
+/// let mut img = vec![0; 8 * 8];
+/// let row = vec![1, 2, 3, 4];
+/// expand_interlaced_row(&mut img, 8, &row, &info, 8);
+/// assert_eq!(&img, &[
+///     0, 0, 0, 0, 0, 0, 0, 0,
+///     0, 0, 0, 0, 0, 0, 0, 0,
+///     1, 0, 2, 0, 3, 0, 4, 0,  // <= this is where the 1st line of 5s appears
+///     0, 0, 0, 0, 0, 0, 0, 0,  //    in the schematic drawing of the passes at
+///     0, 0, 0, 0, 0, 0, 0, 0,  //    https://en.wikipedia.org/wiki/Adam7_algorithm
+///     0, 0, 0, 0, 0, 0, 0, 0,
+///     0, 0, 0, 0, 0, 0, 0, 0,
+///     0, 0, 0, 0, 0, 0, 0, 0,
+/// ]);
+/// ```
 pub fn expand_pass(
     img: &mut [u8],
-    width: u32,
-    scanline: &[u8],
-    pass: u8,
-    line_no: u32,
-    bits_pp: u8,
+    img_row_stride: usize,
+    interlaced_row: &[u8],
+    interlace_info: &Adam7Info,
+    bits_per_pixel: u8,
 ) {
-    let width = width as usize;
-    let line_no = line_no as usize;
-    let bits_pp = bits_pp as usize;
+    let bits_pp = bits_per_pixel as usize;
 
-    // pass is out of range but don't blow up
-    if pass == 0 || pass > 7 {
-        return;
-    }
-
-    let bit_indices = expand_adam7_bits(pass, width, line_no, bits_pp);
+    let bit_indices = expand_adam7_bits(img_row_stride, interlace_info, bits_pp);
 
     if bits_pp < 8 {
-        for (pos, px) in bit_indices.zip(subbyte_pixels(scanline, bits_pp)) {
+        for (pos, px) in bit_indices.zip(subbyte_pixels(interlaced_row, bits_pp)) {
             let rem = 8 - pos % 8 - bits_pp;
             img[pos / 8] |= px << rem as u8;
         }
     } else {
         let bytes_pp = bits_pp / 8;
 
-        for (bitpos, px) in bit_indices.zip(scanline.chunks(bytes_pp)) {
+        for (bitpos, px) in bit_indices.zip(interlaced_row.chunks(bytes_pp)) {
             for (offset, val) in px.iter().enumerate() {
                 img[bitpos / 8 + offset] = *val;
             }
@@ -179,13 +251,41 @@
     assert_eq!(
         &*passes,
         &[
-            (1, 0, 1),
-            (4, 0, 1),
-            (5, 0, 2),
-            (6, 0, 2),
-            (6, 1, 2),
-            (7, 0, 4),
-            (7, 1, 4)
+            Adam7Info {
+                pass: 1,
+                line: 0,
+                width: 1
+            },
+            Adam7Info {
+                pass: 4,
+                line: 0,
+                width: 1
+            },
+            Adam7Info {
+                pass: 5,
+                line: 0,
+                width: 2
+            },
+            Adam7Info {
+                pass: 6,
+                line: 0,
+                width: 2
+            },
+            Adam7Info {
+                pass: 6,
+                line: 1,
+                width: 2
+            },
+            Adam7Info {
+                pass: 7,
+                line: 0,
+                width: 4
+            },
+            Adam7Info {
+                pass: 7,
+                line: 1,
+                width: 4
+            }
         ]
     );
 }
@@ -203,6 +303,8 @@
 fn test_expand_adam7_bits() {
     let width = 32;
     let bits_pp = 1;
+    let stride = width / 8;
+    let info = |pass, line, img_width| create_adam7_info_for_tests(pass, line as u32, img_width);
 
     let expected = |offset: usize, step: usize, count: usize| {
         (0..count)
@@ -214,21 +316,21 @@
         let start = 8 * line_no * width;
 
         assert_eq!(
-            expand_adam7_bits(1, width, line_no, bits_pp).collect::<Vec<_>>(),
+            expand_adam7_bits(stride, &info(1, line_no, width), bits_pp).collect::<Vec<_>>(),
             expected(start, 8, 4)
         );
 
         let start = start + 4;
 
         assert_eq!(
-            expand_adam7_bits(2, width, line_no, bits_pp).collect::<Vec<_>>(),
+            expand_adam7_bits(stride, &info(2, line_no, width), bits_pp).collect::<Vec<_>>(),
             expected(start, 8, 4)
         );
 
         let start = (8 * line_no + 4) * width;
 
         assert_eq!(
-            expand_adam7_bits(3, width, line_no, bits_pp).collect::<Vec<_>>(),
+            expand_adam7_bits(stride, &info(3, line_no, width), bits_pp).collect::<Vec<_>>(),
             expected(start, 4, 8)
         );
     }
@@ -237,14 +339,14 @@
         let start = 4 * line_no * width + 2;
 
         assert_eq!(
-            expand_adam7_bits(4, width, line_no, bits_pp).collect::<Vec<_>>(),
+            expand_adam7_bits(stride, &info(4, line_no, width), bits_pp).collect::<Vec<_>>(),
             expected(start, 4, 8)
         );
 
         let start = (4 * line_no + 2) * width;
 
         assert_eq!(
-            expand_adam7_bits(5, width, line_no, bits_pp).collect::<Vec<_>>(),
+            expand_adam7_bits(stride, &info(5, line_no, width), bits_pp).collect::<Vec<_>>(),
             expected(start, 2, 16)
         )
     }
@@ -253,7 +355,7 @@
         let start = 2 * line_no * width + 1;
 
         assert_eq!(
-            expand_adam7_bits(6, width, line_no, bits_pp).collect::<Vec<_>>(),
+            expand_adam7_bits(stride, &info(6, line_no, width), bits_pp).collect::<Vec<_>>(),
             expected(start, 2, 16),
             "line_no: {}",
             line_no
@@ -262,67 +364,94 @@
         let start = (2 * line_no + 1) * width;
 
         assert_eq!(
-            expand_adam7_bits(7, width, line_no, bits_pp).collect::<Vec<_>>(),
+            expand_adam7_bits(stride, &info(7, line_no, width), bits_pp).collect::<Vec<_>>(),
             expected(start, 1, 32)
         );
     }
 }
 
 #[test]
+fn test_expand_adam7_bits_independent_row_stride() {
+    let pass = 1;
+    let line_no = 1;
+    let width = 32;
+    let bits_pp = 8;
+    let info = create_adam7_info_for_tests;
+
+    {
+        let stride = width;
+        assert_eq!(
+            expand_adam7_bits(stride, &info(pass, line_no, width), bits_pp).collect::<Vec<_>>(),
+            vec![2048, 2112, 2176, 2240],
+        );
+    }
+
+    {
+        let stride = 10000;
+        assert_eq!(
+            expand_adam7_bits(stride, &info(pass, line_no, width), bits_pp).collect::<Vec<_>>(),
+            vec![640000, 640064, 640128, 640192],
+        );
+    }
+}
+
+#[test]
 fn test_expand_pass_subbyte() {
     let mut img = [0u8; 8];
     let width = 8;
+    let stride = width / 8;
     let bits_pp = 1;
+    let info = create_adam7_info_for_tests;
 
-    expand_pass(&mut img, width, &[0b10000000], 1, 0, bits_pp);
+    expand_pass(&mut img, stride, &[0b10000000], &info(1, 0, width), bits_pp);
     assert_eq!(img, [0b10000000u8, 0, 0, 0, 0, 0, 0, 0]);
 
-    expand_pass(&mut img, width, &[0b10000000], 2, 0, bits_pp);
+    expand_pass(&mut img, stride, &[0b10000000], &info(2, 0, width), bits_pp);
     assert_eq!(img, [0b10001000u8, 0, 0, 0, 0, 0, 0, 0]);
 
-    expand_pass(&mut img, width, &[0b11000000], 3, 0, bits_pp);
+    expand_pass(&mut img, stride, &[0b11000000], &info(3, 0, width), bits_pp);
     assert_eq!(img, [0b10001000u8, 0, 0, 0, 0b10001000, 0, 0, 0]);
 
-    expand_pass(&mut img, width, &[0b11000000], 4, 0, bits_pp);
+    expand_pass(&mut img, stride, &[0b11000000], &info(4, 0, width), bits_pp);
     assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10001000, 0, 0, 0]);
 
-    expand_pass(&mut img, width, &[0b11000000], 4, 1, bits_pp);
+    expand_pass(&mut img, stride, &[0b11000000], &info(4, 1, width), bits_pp);
     assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10101010, 0, 0, 0]);
 
-    expand_pass(&mut img, width, &[0b11110000], 5, 0, bits_pp);
+    expand_pass(&mut img, stride, &[0b11110000], &info(5, 0, width), bits_pp);
     assert_eq!(img, [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0, 0]);
 
-    expand_pass(&mut img, width, &[0b11110000], 5, 1, bits_pp);
+    expand_pass(&mut img, stride, &[0b11110000], &info(5, 1, width), bits_pp);
     assert_eq!(
         img,
         [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]
     );
 
-    expand_pass(&mut img, width, &[0b11110000], 6, 0, bits_pp);
+    expand_pass(&mut img, stride, &[0b11110000], &info(6, 0, width), bits_pp);
     assert_eq!(
         img,
         [0b11111111u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]
     );
 
-    expand_pass(&mut img, width, &[0b11110000], 6, 1, bits_pp);
+    expand_pass(&mut img, stride, &[0b11110000], &info(6, 1, width), bits_pp);
     assert_eq!(
         img,
         [0b11111111u8, 0, 0b11111111, 0, 0b10101010, 0, 0b10101010, 0]
     );
 
-    expand_pass(&mut img, width, &[0b11110000], 6, 2, bits_pp);
+    expand_pass(&mut img, stride, &[0b11110000], &info(6, 2, width), bits_pp);
     assert_eq!(
         img,
         [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b10101010, 0]
     );
 
-    expand_pass(&mut img, width, &[0b11110000], 6, 3, bits_pp);
+    expand_pass(&mut img, stride, &[0b11110000], &info(6, 3, width), bits_pp);
     assert_eq!(
         [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b11111111, 0],
         img
     );
 
-    expand_pass(&mut img, width, &[0b11111111], 7, 0, bits_pp);
+    expand_pass(&mut img, stride, &[0b11111111], &info(7, 0, width), bits_pp);
     assert_eq!(
         [
             0b11111111u8,
@@ -337,7 +466,7 @@
         img
     );
 
-    expand_pass(&mut img, width, &[0b11111111], 7, 1, bits_pp);
+    expand_pass(&mut img, stride, &[0b11111111], &info(7, 1, width), bits_pp);
     assert_eq!(
         [
             0b11111111u8,
@@ -352,7 +481,7 @@
         img
     );
 
-    expand_pass(&mut img, width, &[0b11111111], 7, 2, bits_pp);
+    expand_pass(&mut img, stride, &[0b11111111], &info(7, 2, width), bits_pp);
     assert_eq!(
         [
             0b11111111u8,
@@ -367,7 +496,7 @@
         img
     );
 
-    expand_pass(&mut img, width, &[0b11111111], 7, 3, bits_pp);
+    expand_pass(&mut img, stride, &[0b11111111], &info(7, 3, width), bits_pp);
     assert_eq!(
         [
             0b11111111u8,
@@ -382,3 +511,17 @@
         img
     );
 }
+
+#[cfg(test)]
+fn create_adam7_info_for_tests(pass: u8, line: u32, img_width: usize) -> Adam7Info {
+    let width = {
+        let img_height = 8;
+        Adam7Iterator::new(img_width as u32, img_height)
+            .filter(|info| info.pass == pass)
+            .map(|info| info.width)
+            .next()
+            .unwrap()
+    };
+
+    Adam7Info { pass, line, width }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
index ce14edc..7ee6287 100644
--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
+++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/mod.rs
@@ -99,19 +99,26 @@
         self.data
     }
 
-    pub fn interlace(&self) -> InterlaceInfo {
-        self.interlace
+    pub fn interlace(&self) -> &InterlaceInfo {
+        &self.interlace
     }
 }
 
+/// Describes which interlacing algorithm applies to a decoded row.
+///
 /// PNG (2003) specifies two interlace modes, but reserves future extensions.
+///
+/// See also [Reader::next_interlaced_row].
 #[derive(Clone, Copy, Debug)]
 pub enum InterlaceInfo {
-    /// the null method means no interlacing
+    /// The `null` method means no interlacing.
     Null,
-    /// Adam7 derives its name from doing 7 passes over the image, only decoding a subset of all pixels in each pass.
-    /// The following table shows pictorially what parts of each 8x8 area of the image is found in each pass:
+    /// [The `Adam7` algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm) derives its name
+    /// from doing 7 passes over the image, only decoding a subset of all pixels in each pass.
+    /// The following table shows pictorially what parts of each 8x8 area of the image is found in
+    /// each pass:
     ///
+    /// ```txt
     /// 1 6 4 6 2 6 4 6
     /// 7 7 7 7 7 7 7 7
     /// 5 6 5 6 5 6 5 6
@@ -120,7 +127,17 @@
     /// 7 7 7 7 7 7 7 7
     /// 5 6 5 6 5 6 5 6
     /// 7 7 7 7 7 7 7 7
-    Adam7 { pass: u8, line: u32, width: u32 },
+    /// ```
+    Adam7(adam7::Adam7Info),
+}
+
+impl InterlaceInfo {
+    fn get_adam7_info(&self) -> Option<&adam7::Adam7Info> {
+        match self {
+            InterlaceInfo::Null => None,
+            InterlaceInfo::Adam7(adam7info) => Some(adam7info),
+        }
+    }
 }
 
 /// A row of data without interlace information.
@@ -520,20 +537,19 @@
         self.data_stream.clear();
         self.current_start = 0;
         self.prev_start = 0;
-        let width = self.info().width;
         if self.info().interlaced {
+            let stride = self.output_line_size(self.info().width);
+            let samples = color_type.samples() as u8;
+            let bits_pp = samples * (bit_depth as u8);
             while let Some(InterlacedRow {
                 data: row,
                 interlace,
                 ..
             }) = self.next_interlaced_row()?
             {
-                let (line, pass) = match interlace {
-                    InterlaceInfo::Adam7 { line, pass, .. } => (line, pass),
-                    InterlaceInfo::Null => unreachable!("expected interlace information"),
-                };
-                let samples = color_type.samples() as u8;
-                adam7::expand_pass(buf, width, row, pass, line, samples * (bit_depth as u8));
+                // `unwrap` won't panic, because we checked `self.info().interlaced` above.
+                let adam7info = interlace.get_adam7_info().unwrap();
+                adam7::expand_pass(buf, stride, row, &adam7info, bits_pp);
             }
         } else {
             for row in buf
@@ -583,7 +599,7 @@
             None => return Ok(None),
         };
 
-        let width = if let InterlaceInfo::Adam7 { width, .. } = interlace {
+        let width = if let InterlaceInfo::Adam7(adam7::Adam7Info { width, .. }) = interlace {
             width
         } else {
             self.subframe.width
@@ -699,12 +715,12 @@
         match self.subframe.interlace {
             InterlaceIter::Adam7(ref mut adam7) => {
                 let last_pass = adam7.current_pass();
-                let (pass, line, width) = adam7.next()?;
-                let rowlen = self.info().raw_row_length_from_width(width);
-                if last_pass != pass {
+                let adam7info = adam7.next()?;
+                let rowlen = self.info().raw_row_length_from_width(adam7info.width);
+                if last_pass != adam7info.pass {
                     self.prev_start = self.current_start;
                 }
-                Some((rowlen, InterlaceInfo::Adam7 { pass, line, width }))
+                Some((rowlen, InterlaceInfo::Adam7(adam7info)))
             }
             InterlaceIter::None(ref mut height) => {
                 let _ = height.next()?;
diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs
index 72dc88f1..91e5326e 100644
--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs
+++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/decoder/transform/palette.rs
@@ -5,7 +5,7 @@
 //!
 //! To achieve higher throughput, `create_rgba_palette` combines entries from
 //! `PLTE` and `trNS` chunks into a single lookup table.  This is based on the
-//! ideas explored in https://crbug.com/706134.
+//! ideas explored in <https://crbug.com/706134>.
 //!
 //! Memoization is a trade-off:
 //! * On one hand, memoization requires spending X ns before starting to call
diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs
index b7e151a2..72450abf 100644
--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/lib.rs
@@ -74,9 +74,12 @@
 pub mod text_metadata;
 mod traits;
 
+pub use crate::adam7::expand_pass as expand_interlaced_row;
+pub use crate::adam7::Adam7Info;
 pub use crate::common::*;
 pub use crate::decoder::{
-    DecodeOptions, Decoded, Decoder, DecodingError, Limits, OutputInfo, Reader, StreamingDecoder,
+    DecodeOptions, Decoded, Decoder, DecodingError, InterlaceInfo, InterlacedRow, Limits,
+    OutputInfo, Reader, StreamingDecoder,
 };
 pub use crate::encoder::{Encoder, EncodingError, StreamWriter, Writer};
 pub use crate::filter::{AdaptiveFilterType, FilterType};
diff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs
index 18a2abe9..7fc730f 100644
--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs
+++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.13/src/text_metadata.rs
@@ -145,7 +145,7 @@
 
 /// A generalized text chunk trait
 pub trait EncodableTextChunk {
-    /// Encode text chunk as Vec<u8> to a `Write`
+    /// Encode text chunk as `Vec<u8>` to a `Write`
     fn encode<W: Write>(&self, w: &mut W) -> Result<(), EncodingError>;
 }
 
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/.cargo_vcs_info.json
deleted file mode 100644
index 4b12b88..0000000
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "git": {
-    "sha1": "30752ac4ffdaa284606eda34055ad185e28c5499"
-  },
-  "path_in_vcs": "serde"
-}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/.cargo-checksum.json
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/.cargo-checksum.json
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/.cargo-checksum.json
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/.cargo_vcs_info.json
new file mode 100644
index 0000000..4dd830f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "89c4b02bf32ceae5b17d89f93a452ccc195ca038"
+  },
+  "path_in_vcs": "serde"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/Cargo.toml
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/Cargo.toml
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/Cargo.toml
index 4486dcd..e6d535d 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2018"
 rust-version = "1.31"
 name = "serde"
-version = "1.0.209"
+version = "1.0.210"
 authors = [
     "Erick Tryzelaar <erick.tryzelaar@gmail.com>",
     "David Tolnay <dtolnay@gmail.com>",
@@ -76,4 +76,4 @@
 unstable = []
 
 [target."cfg(any())".dependencies.serde_derive]
-version = "=1.0.209"
+version = "=1.0.210"
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/Cargo.toml.orig
similarity index 96%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/Cargo.toml.orig
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/Cargo.toml.orig
index 7f3a9cc..b6ad576 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "serde"
-version = "1.0.209"
+version = "1.0.210"
 authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
 build = "build.rs"
 categories = ["encoding", "no-std", "no-std::no-alloc"]
@@ -37,7 +37,7 @@
 # is compatible with exactly one serde release because the generated code
 # involves nonpublic APIs which are not bound by semver.
 [target.'cfg(any())'.dependencies]
-serde_derive = { version = "=1.0.209", path = "../serde_derive" }
+serde_derive = { version = "=1.0.210", path = "../serde_derive" }
 
 
 ### FEATURES #################################################################
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/LICENSE-APACHE
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/LICENSE-APACHE
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/LICENSE-APACHE
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/LICENSE-MIT
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/LICENSE-MIT
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/LICENSE-MIT
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/README.md b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/README.md
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/README.md
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/README.md
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/build.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/build.rs
similarity index 89%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/build.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/build.rs
index c32872b..8a4f725 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/build.rs
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/build.rs
@@ -15,6 +15,8 @@
 
     if minor >= 77 {
         println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
+        println!("cargo:rustc-check-cfg=cfg(no_core_error)");
+        println!("cargo:rustc-check-cfg=cfg(no_core_net)");
         println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
         println!("cargo:rustc-check-cfg=cfg(no_core_try_from)");
         println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
@@ -86,11 +88,23 @@
         println!("cargo:rustc-cfg=no_core_num_saturating");
     }
 
+    // Support for core::net stabilized in Rust 1.77.
+    // https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html
+    if minor < 77 {
+        println!("cargo:rustc-cfg=no_core_net");
+    }
+
     // Support for the `#[diagnostic]` tool attribute namespace
     // https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
     if minor < 78 {
         println!("cargo:rustc-cfg=no_diagnostic_namespace");
     }
+
+    // The Error trait became available in core in 1.81.
+    // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror
+    if minor < 81 {
+        println!("cargo:rustc-cfg=no_core_error");
+    }
 }
 
 fn rustc_minor_version() -> Option<u32> {
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/crates-io.md b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/crates-io.md
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/crates-io.md
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/crates-io.md
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/ignored_any.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/ignored_any.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/ignored_any.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/ignored_any.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/impls.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/impls.rs
similarity index 98%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/impls.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/impls.rs
index 02591d98..2d8c990 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/impls.rs
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/impls.rs
@@ -1583,12 +1583,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+#[cfg(any(feature = "std", not(no_core_net)))]
 macro_rules! parse_ip_impl {
-    (
-        $(#[$attr:meta])*
-        $ty:ty, $expecting:expr, $size:tt
-    ) => {
-        $(#[$attr])*
+    ($ty:ty, $expecting:expr, $size:tt) => {
         impl<'de> Deserialize<'de> for $ty {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -1604,7 +1601,7 @@
     };
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 macro_rules! variant_identifier {
     (
         $name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
@@ -1679,7 +1676,7 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 macro_rules! deserialize_enum {
     (
         $name:ident $name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
@@ -1716,8 +1713,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl<'de> Deserialize<'de> for net::IpAddr {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
@@ -1736,25 +1732,18 @@
     }
 }
 
-parse_ip_impl! {
-    #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
-    net::Ipv4Addr, "IPv4 address", 4
-}
+#[cfg(any(feature = "std", not(no_core_net)))]
+parse_ip_impl!(net::Ipv4Addr, "IPv4 address", 4);
 
-parse_ip_impl! {
-    #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
-    net::Ipv6Addr, "IPv6 address", 16
-}
+#[cfg(any(feature = "std", not(no_core_net)))]
+parse_ip_impl!(net::Ipv6Addr, "IPv6 address", 16);
 
+#[cfg(any(feature = "std", not(no_core_net)))]
 macro_rules! parse_socket_impl {
     (
-        $(#[$attr:meta])*
         $ty:ty, $expecting:tt,
         $new:expr,
     ) => {
-        $(#[$attr])*
         impl<'de> Deserialize<'de> for $ty {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -1770,8 +1759,7 @@
     };
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl<'de> Deserialize<'de> for net::SocketAddr {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
@@ -1790,16 +1778,14 @@
     }
 }
 
+#[cfg(any(feature = "std", not(no_core_net)))]
 parse_socket_impl! {
-    #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
     net::SocketAddrV4, "IPv4 socket address",
     |(ip, port)| net::SocketAddrV4::new(ip, port),
 }
 
+#[cfg(any(feature = "std", not(no_core_net)))]
 parse_socket_impl! {
-    #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
     net::SocketAddrV6, "IPv6 socket address",
     |(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0),
 }
@@ -3160,13 +3146,13 @@
     AtomicU64 "64"
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 struct FromStrVisitor<T> {
     expecting: &'static str,
     ty: PhantomData<T>,
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl<T> FromStrVisitor<T> {
     fn new(expecting: &'static str) -> Self {
         FromStrVisitor {
@@ -3176,7 +3162,7 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl<'de, T> Visitor<'de> for FromStrVisitor<T>
 where
     T: str::FromStr,
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/mod.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/mod.rs
similarity index 99%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/mod.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/mod.rs
index d6b9f5a..21cfd041 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/mod.rs
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/mod.rs
@@ -118,17 +118,16 @@
 
 pub mod value;
 
-mod format;
 mod ignored_any;
 mod impls;
 pub(crate) mod size_hint;
 
 pub use self::ignored_any::IgnoredAny;
 
-#[cfg(not(any(feature = "std", feature = "unstable")))]
+#[cfg(all(not(feature = "std"), no_core_error))]
 #[doc(no_inline)]
 pub use crate::std_error::Error as StdError;
-#[cfg(all(feature = "unstable", not(feature = "std")))]
+#[cfg(not(any(feature = "std", no_core_error)))]
 #[doc(no_inline)]
 pub use core::error::Error as StdError;
 #[cfg(feature = "std")]
@@ -1374,7 +1373,7 @@
         E: Error,
     {
         let mut buf = [0u8; 58];
-        let mut writer = format::Buf::new(&mut buf);
+        let mut writer = crate::format::Buf::new(&mut buf);
         fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
         Err(Error::invalid_type(
             Unexpected::Other(writer.as_str()),
@@ -1436,7 +1435,7 @@
         E: Error,
     {
         let mut buf = [0u8; 57];
-        let mut writer = format::Buf::new(&mut buf);
+        let mut writer = crate::format::Buf::new(&mut buf);
         fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
         Err(Error::invalid_type(
             Unexpected::Other(writer.as_str()),
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/seed.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/seed.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/seed.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/seed.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/size_hint.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/size_hint.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/size_hint.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/size_hint.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/value.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/value.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/value.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/value.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/format.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/format.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/format.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/format.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/integer128.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/integer128.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/integer128.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/integer128.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/lib.rs
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/lib.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/lib.rs
index e9fc96c..15710d8d 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/lib.rs
@@ -95,7 +95,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 // Serde types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/serde/1.0.209")]
+#![doc(html_root_url = "https://docs.rs/serde/1.0.210")]
 // Support using Serde without the standard library!
 #![cfg_attr(not(feature = "std"), no_std)]
 // Show which crate feature enables conditionally compiled APIs in documentation.
@@ -238,8 +238,13 @@
     #[cfg(feature = "std")]
     pub use std::ffi::CString;
 
+    #[cfg(all(not(no_core_net), not(feature = "std")))]
+    pub use self::core::net;
     #[cfg(feature = "std")]
-    pub use std::{error, net};
+    pub use std::net;
+
+    #[cfg(feature = "std")]
+    pub use std::error;
 
     #[cfg(feature = "std")]
     pub use std::collections::{HashMap, HashSet};
@@ -305,6 +310,8 @@
 pub mod de;
 pub mod ser;
 
+mod format;
+
 #[doc(inline)]
 pub use crate::de::{Deserialize, Deserializer};
 #[doc(inline)]
@@ -318,7 +325,7 @@
 #[path = "de/seed.rs"]
 mod seed;
 
-#[cfg(not(any(feature = "std", feature = "unstable")))]
+#[cfg(all(not(feature = "std"), no_core_error))]
 mod std_error;
 
 // Re-export #[derive(Serialize, Deserialize)].
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/macros.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/macros.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/macros.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/macros.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/de.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/de.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/de.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/de.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/doc.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/doc.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/doc.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/doc.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/mod.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/mod.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/mod.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/mod.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/ser.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/ser.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/ser.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/ser.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/fmt.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/fmt.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/fmt.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/fmt.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/impls.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/impls.rs
similarity index 96%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/impls.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/impls.rs
index 557b6aa..fb574ea 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/impls.rs
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/impls.rs
@@ -773,28 +773,17 @@
 /// statically known to never have more than a constant `MAX_LEN` bytes.
 ///
 /// Panics if the `Display` impl tries to write more than `MAX_LEN` bytes.
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 macro_rules! serialize_display_bounded_length {
     ($value:expr, $max:expr, $serializer:expr) => {{
         let mut buffer = [0u8; $max];
-        let remaining_len = {
-            let mut remaining = &mut buffer[..];
-            write!(remaining, "{}", $value).unwrap();
-            remaining.len()
-        };
-        let written_len = buffer.len() - remaining_len;
-        let written = &buffer[..written_len];
-
-        // write! only provides fmt::Formatter to Display implementations, which
-        // has methods write_str and write_char but no method to write arbitrary
-        // bytes. Therefore `written` must be valid UTF-8.
-        let written_str = str::from_utf8(written).expect("must be valid UTF-8");
-        $serializer.serialize_str(written_str)
+        let mut writer = crate::format::Buf::new(&mut buffer);
+        write!(&mut writer, "{}", $value).unwrap();
+        $serializer.serialize_str(writer.as_str())
     }};
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl Serialize for net::IpAddr {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -818,7 +807,7 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 const DEC_DIGITS_LUT: &[u8] = b"\
       0001020304050607080910111213141516171819\
       2021222324252627282930313233343536373839\
@@ -826,7 +815,7 @@
       6061626364656667686970717273747576777879\
       8081828384858687888990919293949596979899";
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 #[inline]
 fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
     if n >= 100 {
@@ -847,7 +836,7 @@
     }
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", not(no_core_net)))]
 #[test]
 fn test_format_u8() {
     let mut i = 0u8;
@@ -864,8 +853,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl Serialize for net::Ipv4Addr {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -889,8 +877,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl Serialize for net::Ipv6Addr {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -906,8 +893,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl Serialize for net::SocketAddr {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -931,8 +917,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl Serialize for net::SocketAddrV4 {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -948,8 +933,7 @@
     }
 }
 
-#[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[cfg(any(feature = "std", not(no_core_net)))]
 impl Serialize for net::SocketAddrV6 {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/impossible.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/impossible.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/impossible.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/impossible.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/mod.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/mod.rs
similarity index 99%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/mod.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/mod.rs
index 30a6480..fb0033e 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/mod.rs
+++ b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/mod.rs
@@ -115,10 +115,10 @@
 
 pub use self::impossible::Impossible;
 
-#[cfg(not(any(feature = "std", feature = "unstable")))]
+#[cfg(all(not(feature = "std"), no_core_error))]
 #[doc(no_inline)]
 pub use crate::std_error::Error as StdError;
-#[cfg(all(feature = "unstable", not(feature = "std")))]
+#[cfg(not(any(feature = "std", no_core_error)))]
 #[doc(no_inline)]
 pub use core::error::Error as StdError;
 #[cfg(feature = "std")]
diff --git a/third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/std_error.rs b/third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/std_error.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/std_error.rs
rename to third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/std_error.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/.cargo_vcs_info.json
deleted file mode 100644
index 9a2b9b0..0000000
--- a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "git": {
-    "sha1": "30752ac4ffdaa284606eda34055ad185e28c5499"
-  },
-  "path_in_vcs": "serde_derive"
-}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/.cargo-checksum.json
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/.cargo-checksum.json
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/.cargo-checksum.json
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/.cargo_vcs_info.json
new file mode 100644
index 0000000..f34c222
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "89c4b02bf32ceae5b17d89f93a452ccc195ca038"
+  },
+  "path_in_vcs": "serde_derive"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/Cargo.toml
similarity index 98%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/Cargo.toml
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/Cargo.toml
index 1266d01..2bd5bb34 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2015"
 rust-version = "1.56"
 name = "serde_derive"
-version = "1.0.209"
+version = "1.0.210"
 authors = [
     "Erick Tryzelaar <erick.tryzelaar@gmail.com>",
     "David Tolnay <dtolnay@gmail.com>",
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/Cargo.toml.orig
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/Cargo.toml.orig
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/Cargo.toml.orig
index 4476a5e6..d6e5c24e 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "serde_derive"
-version = "1.0.209"
+version = "1.0.210"
 authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
 categories = ["no-std", "no-std::no-alloc"]
 description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/LICENSE-APACHE
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/LICENSE-APACHE
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/LICENSE-APACHE
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/LICENSE-MIT
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/LICENSE-MIT
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/LICENSE-MIT
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/README.md b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/README.md
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/README.md
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/README.md
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/crates-io.md b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/crates-io.md
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/crates-io.md
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/crates-io.md
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/bound.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/bound.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/bound.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/bound.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/de.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/de.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/de.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/de.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/dummy.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/dummy.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/dummy.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/dummy.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/fragment.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/fragment.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/fragment.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/fragment.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/ast.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/ast.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/ast.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/ast.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/attr.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/attr.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/attr.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/attr.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/case.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/case.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/case.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/case.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/check.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/check.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/check.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/check.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/ctxt.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/ctxt.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/ctxt.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/ctxt.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/mod.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/mod.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/mod.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/mod.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/receiver.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/receiver.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/receiver.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/receiver.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/respan.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/respan.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/respan.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/respan.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/symbol.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/symbol.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/symbol.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/symbol.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/lib.rs
similarity index 97%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/lib.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/lib.rs
index 48104ed..bedd1cb 100644
--- a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/lib.rs
@@ -13,7 +13,7 @@
 //!
 //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
 
-#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.209")]
+#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.210")]
 #![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
 // Ignored clippy lints
 #![allow(
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/pretend.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/pretend.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/pretend.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/pretend.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/ser.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/ser.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/ser.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/ser.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/this.rs b/third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/this.rs
similarity index 100%
rename from third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/this.rs
rename to third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/this.rs
diff --git a/third_party/rust/serde/v1/BUILD.gn b/third_party/rust/serde/v1/BUILD.gn
index 78da49d2..44a0675 100644
--- a/third_party/rust/serde/v1/BUILD.gn
+++ b/third_party/rust/serde/v1/BUILD.gn
@@ -13,33 +13,33 @@
   epoch = "1"
   crate_type = "rlib"
   crate_root =
-      "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/lib.rs"
+      "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/lib.rs"
   sources = [
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/format.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/ignored_any.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/impls.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/mod.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/seed.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/size_hint.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/de/value.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/integer128.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/lib.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/macros.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/de.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/doc.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/mod.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/private/ser.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/fmt.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/impls.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/impossible.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/ser/mod.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/src/std_error.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/ignored_any.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/impls.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/seed.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/size_hint.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/de/value.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/format.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/integer128.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/macros.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/de.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/doc.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/private/ser.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/fmt.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/impls.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/impossible.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/ser/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/src/std_error.rs",
   ]
   inputs = []
 
   build_native_rust_unit_tests = false
   edition = "2018"
-  cargo_pkg_version = "1.0.209"
+  cargo_pkg_version = "1.0.210"
   cargo_pkg_authors = "Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "serde"
   cargo_pkg_description = "A generic serialization/deserialization framework"
@@ -56,7 +56,7 @@
     "std",
   ]
   build_root =
-      "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/build.rs"
+      "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/build.rs"
   build_sources =
-      [ "//third_party/rust/chromium_crates_io/vendor/serde-1.0.209/build.rs" ]
+      [ "//third_party/rust/chromium_crates_io/vendor/serde-1.0.210/build.rs" ]
 }
diff --git a/third_party/rust/serde/v1/README.chromium b/third_party/rust/serde/v1/README.chromium
index fecca647..a55341d 100644
--- a/third_party/rust/serde/v1/README.chromium
+++ b/third_party/rust/serde/v1/README.chromium
@@ -1,9 +1,9 @@
 Name: serde
 URL: https://crates.io/crates/serde
 Description: A generic serialization/deserialization framework
-Version: 1.0.209
+Version: 1.0.210
 Security Critical: yes
 Shipped: yes
 License: Apache 2.0
-License File: //third_party/rust/chromium_crates_io/vendor/serde-1.0.209/LICENSE-APACHE
-Revision: 30752ac4ffdaa284606eda34055ad185e28c5499
+License File: //third_party/rust/chromium_crates_io/vendor/serde-1.0.210/LICENSE-APACHE
+Revision: 89c4b02bf32ceae5b17d89f93a452ccc195ca038
diff --git a/third_party/rust/serde_derive/v1/BUILD.gn b/third_party/rust/serde_derive/v1/BUILD.gn
index 99254025..a0445c5 100644
--- a/third_party/rust/serde_derive/v1/BUILD.gn
+++ b/third_party/rust/serde_derive/v1/BUILD.gn
@@ -12,31 +12,31 @@
   crate_name = "serde_derive"
   epoch = "1"
   crate_type = "proc-macro"
-  crate_root = "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/lib.rs"
+  crate_root = "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/lib.rs"
   sources = [
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/bound.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/de.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/dummy.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/fragment.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/ast.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/attr.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/case.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/check.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/ctxt.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/mod.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/receiver.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/respan.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/internals/symbol.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/lib.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/pretend.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/ser.rs",
-    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/src/this.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/bound.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/de.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/dummy.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/fragment.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/ast.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/attr.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/case.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/check.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/ctxt.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/receiver.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/respan.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/internals/symbol.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/pretend.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/ser.rs",
+    "//third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/src/this.rs",
   ]
   inputs = []
 
   build_native_rust_unit_tests = false
   edition = "2015"
-  cargo_pkg_version = "1.0.209"
+  cargo_pkg_version = "1.0.210"
   cargo_pkg_authors = "Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "serde_derive"
   cargo_pkg_description =
diff --git a/third_party/rust/serde_derive/v1/README.chromium b/third_party/rust/serde_derive/v1/README.chromium
index e59467b..ee5c8ffa 100644
--- a/third_party/rust/serde_derive/v1/README.chromium
+++ b/third_party/rust/serde_derive/v1/README.chromium
@@ -1,9 +1,9 @@
 Name: serde_derive
 URL: https://crates.io/crates/serde_derive
 Description: Macros 1.1 implementation of #[derive(Serialize, Deserialize)]
-Version: 1.0.209
+Version: 1.0.210
 Security Critical: yes
 Shipped: yes
 License: Apache 2.0
-License File: //third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.209/LICENSE-APACHE
-Revision: 30752ac4ffdaa284606eda34055ad185e28c5499
+License File: //third_party/rust/chromium_crates_io/vendor/serde_derive-1.0.210/LICENSE-APACHE
+Revision: 89c4b02bf32ceae5b17d89f93a452ccc195ca038
diff --git a/third_party/skia b/third_party/skia
index 1fa3a29..7c2ab74 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 1fa3a29e66bd220f33202be998ae0a883c749bd2
+Subproject commit 7c2ab74e6d1b9c3017114a8d13a200a888fc5b10
diff --git a/third_party/swiftshader b/third_party/swiftshader
index 5561c71..8dd40811 160000
--- a/third_party/swiftshader
+++ b/third_party/swiftshader
@@ -1 +1 @@
-Subproject commit 5561c71fa64e5f7f726f74f23a8aac5cc308d18a
+Subproject commit 8dd40811c5715061393f1b36999139ef0813c291
diff --git a/tools/clang/plugins/UnsafeBuffersPlugin.cpp b/tools/clang/plugins/UnsafeBuffersPlugin.cpp
index f203be23..da0632fa 100644
--- a/tools/clang/plugins/UnsafeBuffersPlugin.cpp
+++ b/tools/clang/plugins/UnsafeBuffersPlugin.cpp
@@ -335,6 +335,13 @@
     engine.setSeverityForGroup(clang::diag::Flavor::WarningOrError,
                                "unsafe-buffer-usage",
                                clang::diag::Severity::Remark);
+
+    // TODO(https://crbug.com/364707242): directly ignore this diagnostic in
+    // HandleDiagnostic above after rolling clang with
+    // -Wunsafe-buffer-usage-in-libc-call.
+    engine.setSeverityForGroup(clang::diag::Flavor::WarningOrError,
+                               "unsafe-buffer-usage-in-libc-call",
+                               clang::diag::Severity::Ignored);
   }
 
   ~UnsafeBuffersASTConsumer() {
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 80ace255..f34d6a1 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -331,7 +331,7 @@
     "META": {"sizes": {"includes": [10]}},
     "includes": [3460],
   },
-  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/nearby_internals/resources.grd": {
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/nearby_internals/resources.grd": {
     "META": {"sizes": {"includes": [40]}},
     "includes": [3480],
   },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 88e1cf5c..a3734cb 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -2483,29 +2483,65 @@
   </description>
 </action>
 
+<action name="Actions.PinnedToolbarButton.Pinned">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    Recorded when the suffixed action is pinned to the toolbar.
+  </description>
+</action>
+
 <action name="Actions.PinnedToolbarButton.Pinned.ByContextMenu">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <description>
-    Recorded when the suffxied action is pinned to the toolbar through the
+    Recorded when the suffixed action is pinned to the toolbar through the
     context menu.
   </description>
 </action>
 
+<action name="Actions.PinnedToolbarButton.Pinned.ByCustomizeChromeSidePanel">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    Recorded when the suffixed action is pinned to the toolbar through the
+    customize chrome side panel.
+  </description>
+</action>
+
+<action name="Actions.PinnedToolbarButton.Unpinned">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    Recorded when the suffixed action is unpinned from the toolbar.
+  </description>
+</action>
+
 <action name="Actions.PinnedToolbarButton.Unpinned.ByContextMenu">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <description>
-    Recorded when the suffxied action unpinned from the toolbar through the
+    Recorded when the suffixed action unpinned from the toolbar through the
     context menu.
   </description>
 </action>
 
+<action name="Actions.PinnedToolbarButton.Unpinned.ByCustomizeChromeSidePanel">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    Recorded when the suffixed action (or any action if there is no suffixed
+    action) is unpinned from the toolbar through the customize chrome side
+    panel.
+  </description>
+</action>
+
 <action name="Actions.PinnedToolbarButtonActivation">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <description>
-    Recorded when an action pinned to the toolbar is activated.
+    Recorded when the suffixed action (or any action if there is no suffixed
+    action) is activated.
   </description>
 </action>
 
@@ -46219,11 +46255,28 @@
 </action-suffix>
 
 <action-suffix separator="." ordering="suffix">
+  <suffix name="kActionClearBrowsingData" label="Clear browsing data action"/>
+  <suffix name="kActionCopyUrl" label="Copy url action"/>
+  <suffix name="kActionDevTools" label="Developer tools action"/>
+  <suffix name="kActionNewIncognitoWindow" label="New incognito window action"/>
+  <suffix name="kActionPrint" label="Print action"/>
+  <suffix name="kActionQrCodeGenerator" label="QR code generator action"/>
+  <suffix name="kActionSendTabToSelf" label="Send tab to self action"/>
+  <suffix name="kActionShowAddressesBubbleOrPage"
+      label="Show addresses action"/>
+  <suffix name="kActionShowChromeLabs" label="Show Chrome Labs action"/>
+  <suffix name="kActionShowPasswordsBubbleOrPage"
+      label="Show passwords bubble or page action"/>
+  <suffix name="kActionShowPaymentsBubbleOrPage"
+      label="Show payments bubble or page action"/>
+  <suffix name="kActionShowTranslate" label="Show translate action"/>
   <suffix name="kActionSidePanelShowBookmarks"
       label="Show bookmarks side panel action"/>
   <suffix name="kActionSidePanelShowFeed" label="Show feed side panel action"/>
   <suffix name="kActionSidePanelShowHistoryCluster"
       label="Show history clusster side panel action"/>
+  <suffix name="kActionSidePanelShowLensOverlayResults"
+      label="Show lens overlay action"/>
   <suffix name="kActionSidePanelShowReadAnything"
       label="Show read anything side panel action"/>
   <suffix name="kActionSidePanelShowReadingList"
@@ -46232,8 +46285,16 @@
       label="Show search companion side panel action"/>
   <suffix name="kActionSidePanelShowUserNote"
       label="Show user note side panel action"/>
+  <suffix name="kActionTaskManager" label="Task manager action"/>
+  <affected-action name="Actions.PinnedToolbarButton.Pinned"/>
   <affected-action name="Actions.PinnedToolbarButton.Pinned.ByContextMenu"/>
+  <affected-action
+      name="Actions.PinnedToolbarButton.Pinned.ByCustomizeChromeSidePanel"/>
+  <affected-action name="Actions.PinnedToolbarButton.Unpinned"/>
   <affected-action name="Actions.PinnedToolbarButton.Unpinned.ByContextMenu"/>
+  <affected-action
+      name="Actions.PinnedToolbarButton.Unpinned.ByCustomizeChromeSidePanel"/>
+  <affected-action name="Actions.PinnedToolbarButtonActivation"/>
 </action-suffix>
 
 <action-suffix separator="." ordering="suffix">
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index f3215c5..24b0284 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -815,7 +815,7 @@
 </histogram>
 
 <histogram name="Android.BindingManger.ConnectionsDroppedDueToMaxSize"
-    units="connections" expires_after="2024-10-24">
+    units="connections" expires_after="2025-02-23">
   <owner>ckitagawa@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -3614,8 +3614,39 @@
   </summary>
 </histogram>
 
+<histogram name="Android.Pdf.DocumentLoad" enum="Boolean"
+    expires_after="2025-03-02">
+  <owner>shuyng@google.com</owner>
+  <owner>clank-large-form-factors@google.com</owner>
+  <summary>
+    Recorded when the pdf load starts. Used to compare against
+    Android.Pdf.DocumentLoadResult, which is recorded when the pdf load is
+    complete, to determine how many pdf loads are not complete.
+  </summary>
+</histogram>
+
+<histogram name="Android.Pdf.DocumentLoadResult" enum="Boolean"
+    expires_after="2025-03-02">
+  <owner>shuyng@google.com</owner>
+  <owner>clank-large-form-factors@google.com</owner>
+  <summary>
+    Records the pdf document load results. True means success and false means
+    failure. Recorded when the pdf load is complete.
+  </summary>
+</histogram>
+
+<histogram name="Android.Pdf.DocumentLoadTime" units="ms"
+    expires_after="2025-03-02">
+  <owner>shuyng@google.com</owner>
+  <owner>clank-large-form-factors@google.com</owner>
+  <summary>
+    Records the pdf document load time. Recorded when the pdf load is complete.
+    Records successful pdf loads only.
+  </summary>
+</histogram>
+
 <histogram name="Android.Pdf.DownloadUrlDecoded" enum="Boolean"
-    expires_after="2024-10-28">
+    expires_after="2025-03-02">
   <owner>shuyng@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -3626,7 +3657,7 @@
 </histogram>
 
 <histogram name="Android.Pdf.DownloadUrlEncoded" enum="Boolean"
-    expires_after="2024-10-28">
+    expires_after="2025-03-02">
   <owner>shuyng@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index f37d5b1..260c4df 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -315,15 +315,15 @@
   </summary>
 </histogram>
 
-<histogram name="Compositing.Display.Draw.AverageOverdraw" units="units"
+<histogram name="Compositing.Display.Draw.AverageOverdraw2" units="units"
     expires_after="2025-01-05">
   <owner>zoraiznaeem@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     The average overdraw of the aggregated compositor frame. It is logged once
-    per frame. Overdraw is expected to range is [1.0, 6.0]. An overdraw of 2.0
+    per frame. Overdraw is expected to range is [1.0, 12.0]. An overdraw of 2.0
     means that on average each pixel of the display is drawn twice. Note: The
-    overdraw value is logged as `overdraw * 100000`.
+    overdraw value is logged as `overdraw * 100,000`.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml
index c610fa8..bcae019 100644
--- a/tools/metrics/histograms/metadata/cookie/histograms.xml
+++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -935,7 +935,7 @@
 </histogram>
 
 <histogram name="Cookie.SameSiteAttributeValue" enum="CookieSameSiteString"
-    expires_after="2024-09-22">
+    expires_after="2025-03-22">
   <owner>bingler@chromium.org</owner>
   <owner>miketaylr@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index a204442..4a28a2a 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -5061,6 +5061,22 @@
   <summary>Uninstalls grouped by Extension::HistogramType.</summary>
 </histogram>
 
+<histogram name="Extensions.WAR.XOriginWebAccessible.{ManifestVersion}"
+    enum="Boolean" expires_after="2025-04-01">
+  <owner>solomonkinard@chromium.org</owner>
+  <owner>extensions-core@chromium.org</owner>
+  <summary>
+    Emitted each time a cross-origin extension navigation request occurs. Counts
+    whether or not the target URL is a web accessible resource. It's possible
+    that the upstream origin and target are different but both for the same
+    extension (i.e. one for a static URL and the other for its dynamic URL).
+  </summary>
+  <token key="ManifestVersion">
+    <variant name="MV2" summary="At most MV2"/>
+    <variant name="MV3" summary="At least MV3"/>
+  </token>
+</histogram>
+
 <histogram
     name="Extensions.WebRequest.BeforeRequestDeclarativeNetRequestEvaluationTime"
     units="ms" expires_after="2025-06-30">
diff --git a/tools/metrics/histograms/metadata/mobile/enums.xml b/tools/metrics/histograms/metadata/mobile/enums.xml
index 9448ac9..ad456cc 100644
--- a/tools/metrics/histograms/metadata/mobile/enums.xml
+++ b/tools/metrics/histograms/metadata/mobile/enums.xml
@@ -226,6 +226,7 @@
   <int value="58" label="Sort Drive Items By Opening Time"/>
   <int value="59" label="Select Drive Identity"/>
   <int value="60" label="Add Drive Account"/>
+  <int value="61" label="Manage In New Tab"/>
 </enum>
 
 <enum name="IOSMenuScenario">
@@ -260,6 +261,7 @@
   <int value="28" label="Sort Drive Items Entry"/>
   <int value="29" label="Select Drive Identity Entry"/>
   <int value="30" label="Tab Group Indicator Entry"/>
+  <int value="31" label="Autofill Manual Fallback Plus Address Entry"/>
 </enum>
 
 <enum name="IOSShareAction">
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml
index d064adc..779578e 100644
--- a/tools/metrics/histograms/metadata/mobile/histograms.xml
+++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -180,6 +180,8 @@
         summary="Autofill manual fallback password entry"/>
     <variant name="AutofillManualFallbackPaymentEntry"
         summary="Autofill manual fallback payment entry"/>
+    <variant name="AutofillManualFallbackPlusAddressEntry"
+        summary="Autofill manual fallback plus address entry"/>
     <variant name="BookmarkEntry" summary="Bookmark entry"/>
     <variant name="BookmarkFolder" summary="Bookmark folder"/>
     <variant name="HistoryEntry" summary="History entry"/>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 78c5159..e7a7da0 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -8094,22 +8094,6 @@
   </summary>
 </histogram>
 
-<histogram name="SB2.RemoteCall.InternalErrorStatusCode2"
-    enum="GooglePlayServicesConnectionResult" expires_after="never">
-<!-- expires-never: This tracks the result of connecting to GmsCore for
-Safe Browsing lookups, which is critical for security. -->
-
-  <owner>vakh@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    The status code provided by GmsCore if it is unable to respond to a URL
-    check request due to incorrect initialization, not being ready, etc. Logged
-    on each URL check that hits the internal error condition. The total number
-    of these should add up to the INTERNAL_ERROR reports under
-    SB2.RemoteCall.Result.
-  </summary>
-</histogram>
-
 <histogram name="SBIRS.DiscardedIncident" enum="IncidentType"
     expires_after="never">
 <!-- expires-never: This tracks health of the incident reporting feature and
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index bd51529..c6f5bfa 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -24,11 +24,8 @@
 
 <variants name="BackgroundSuffix">
   <variant name="" summary="never backgrounded during the navigation"/>
-  <variant name=".WasAppBackgrounded"
-      summary="app backgrounded at least once during the navigation"/>
   <variant name=".WasBackgrounded"
-      summary="backgrounded at least once during the navigation (this was
-               renamed to WasAppBackgrounded)"/>
+      summary="backgrounded at least once during the navigation"/>
 </variants>
 
 <variants name="BrowserInitializationStatus">
@@ -44,20 +41,7 @@
 <variants name="HiddenSuffix">
   <variant name="" summary="never hidden during the navigation"/>
   <variant name=".WasHidden"
-      summary="hidden at least once during the navigation (this was renamed
-               to WasTabHidden)"/>
-  <variant name=".WasTabHidden"
-      summary="tab hidden at least once during the navigation"/>
-</variants>
-
-<variants name="IncognitoSuffix">
-  <variant name=""
-      summary="the navigation opened in any profile, which includes incogniro
-               or guest mode"/>
-  <variant name=".Incognito"
-      summary="the navigation opened in an incognito mode"/>
-  <variant name=".NoIncognito"
-      summary="the navigation opened in the regular profile or guest mode"/>
+      summary="hidden at least once during the navigation"/>
 </variants>
 
 <variants name="LoadedIdleVisibility">
@@ -2236,7 +2220,7 @@
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.AbandonReasonAt.{NavigationMilestone}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{IncognitoSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.AbandonReasonAt.{NavigationMilestone}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     enum="NavigationAbandonReasonEnum" expires_after="2025-02-10">
   <owner>rakina@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2244,23 +2228,22 @@
     Logs the navigation abandonment reason that happens when the last milestone
     is {NavigationMilestone} on a main frame navigation for {ObservedNavigation}
     with {RTTBucketSuffix} connection, with potentially some suffixes detaling
-    the navigation {BackgroundSuffix}, {HiddenSuffix},
-    {ResponseFromCacheSuffix}, {NonSRPSuffix}, and/or {IncognitoSuffix}.
+    the navigation {BackgroundSuffix}, {HiddenSuffix}, {ResponseFromCacheSuffix}
+    and/or {NonSRPSuffix}.
 
     The metric is emitted when the navigation gets abandoned.
   </summary>
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
+  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="NavigationMilestone" variants="NavigationMilestone"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
-  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.LastMilestoneBeforeAbandon{NavigationAbandonReason}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{IncognitoSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.LastMilestoneBeforeAbandon{NavigationAbandonReason}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     enum="NavigationMilestoneEnum2" expires_after="2025-02-10">
   <owner>rakina@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2268,22 +2251,21 @@
     Logs the last navigation milestone reason that was reached when a main frame
     navigation for {ObservedNavigation} is abandoned due to
     {NavigationAbandonReason}, with potentially some suffixes detaling the
-    navigation {BackgroundSuffix}, {HiddenSuffix}, {ResponseFromCacheSuffix},
-    {NonSRPSuffix} and/or {IncognitoSuffix}. The metric is emitted when the
-    navigation gets abandoned.
+    navigation {BackgroundSuffix}, {HiddenSuffix}, {ResponseFromCacheSuffix}
+    and/or {NonSRPSuffix}. The metric is emitted when the navigation gets
+    abandoned.
   </summary>
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
+  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="NavigationAbandonReason" variants="NavigationAbandonReason"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
-  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.NavigationStartToRendererProcessInit{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{IncognitoSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.NavigationStartToRendererProcessInit{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     units="ms" expires_after="2024-12-08">
   <owner>rakina@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2291,22 +2273,21 @@
     The time relative to the navigation start that the final renderer process is
     created for a main frame navigation for {ObservedNavigation} with
     potentially some suffixes detaling the navigation {BackgroundSuffix},
-    {HiddenSuffix}, {ResponseFromCacheSuffix}, {NonSRPSuffix}, {IncognitoSuffix}
-    and {RTTBucketSuffix}. The metric is emitted when the navigation's commit
-    IPC is just sent out, if the renderer process is created after the
-    navigation started.
+    {HiddenSuffix}, {ResponseFromCacheSuffix}, {NonSRPSuffix}, and
+    {RTTBucketSuffix}. The metric is emitted when the navigation's commit IPC is
+    just sent out, if the renderer process is created after the navigation
+    started.
   </summary>
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
+  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
-  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.NavigationStartTo{NavigationMilestone}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{IncognitoSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.NavigationStartTo{NavigationMilestone}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     units="ms" expires_after="2025-02-10">
   <owner>rakina@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2314,28 +2295,26 @@
     The time relative to navigation start that a navigation reaches the the
     milestone {NavigationMilestone} on a main frame navigation for
     {ObservedNavigation}, with potentially some suffixes detaling the navigation
-    {BackgroundSuffix}, {HiddenSuffix}, {ResponseFromCacheSuffix},
-    {NonSRPSuffix}, and/or {IncognitoSuffix}. Only recorded for Search
-    navigations that didn't get terminally abandoned at least until the relevant
-    milestone. Note that abandonment from backgrounding or hiding are
-    non-terminal, so milestones after those types of abandonments will still be
-    logged. The metric is emitted when the navigation finishes committing or it
-    gets abandoned (which can happen multiple times during the navigation if
-    non-terminal, so only the milestones that haven't been logged will be
-    logged).
+    {BackgroundSuffix}, {HiddenSuffix},{ResponseFromCacheSuffix}, and/or
+    {NonSRPSuffix}. Only recorded for Search navigations that didn't get
+    terminally abandoned at least until the relevant milestone. Note that
+    abandonment from backgrounding or hiding are non-terminal, so milestones
+    after those types of abandonments will still be logged. The metric is
+    emitted when the navigation finishes committing or it gets abandoned (which
+    can happen multiple times during the navigation if non-terminal, so only the
+    milestones that haven't been logged will be logged).
   </summary>
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
+  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="NavigationMilestone" variants="NavigationMilestone"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
-  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.NavigationStart{BackgroundSuffix}{HiddenSuffix}{NonSRPSuffix}{IncognitoSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.NavigationStart{BackgroundSuffix}{HiddenSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     units="ms" expires_after="2025-02-10">
   <owner>rakina@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2348,13 +2327,12 @@
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.RendererProcessCreatedBeforeNav{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{IncognitoSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.RendererProcessCreatedBeforeNav{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     enum="Boolean" expires_after="2024-12-08">
   <owner>rakina@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2363,20 +2341,19 @@
     the navigation start or not, for a main frame navigation for
     {ObservedNavigation} with potentially some suffixes detaling the navigation
     {BackgroundSuffix}, {HiddenSuffix}, {ResponseFromCacheSuffix},
-    {NonSRPSuffix}, {IncognitoSuffix}, and {RTTBucketSuffix}. The metric is
-    emitted when the navigation's commit IPC is just sent out.
+    {NonSRPSuffix}, and {RTTBucketSuffix}. The metric is emitted when the
+    navigation's commit IPC is just sent out.
   </summary>
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
+  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
-  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.TimeToAbandonFromNavigationStart.{NavigationMilestone}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{IncognitoSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.TimeToAbandonFromNavigationStart.{NavigationMilestone}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     units="ms" expires_after="2024-12-08">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2390,23 +2367,22 @@
     abandoned non-terminally before, but only once for each abandonment reason.
     &quot;This is logged after non-terminal abandonment of pages which were
     {BackgroundSuffix} and {HiddenSuffix}&quot; {NonSRPSuffix} is added if the
-    navigation involves a non-SRP URL but then redirected to SRP URL, and
-    {IncognitoSuffix}. The milestone recorded will be the latest milestone (if
-    there are multiple milestones reached before the abandonment). The metric is
-    emitted when the navigation gets abandoned.
+    navigation involves a non-SRP URL but then redirected to SRP URL. The
+    milestone recorded will be the latest milestone (if there are multiple
+    milestones reached before the abandonment). The metric is emitted when the
+    navigation gets abandoned.
   </summary>
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
+  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="NavigationMilestone" variants="NavigationMilestone"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
-  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
 <histogram
-    name="PageLoad.Clients{ObservedNavigation}.Leakage2.{NavigationMilestone}ToAbandon{NavigationAbandonReason}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{IncognitoSuffix}{RTTBucketSuffix}"
+    name="PageLoad.Clients{ObservedNavigation}.Leakage2.{NavigationMilestone}ToAbandon{NavigationAbandonReason}{BackgroundSuffix}{HiddenSuffix}{ResponseFromCacheSuffix}{NonSRPSuffix}{RTTBucketSuffix}"
     units="ms" expires_after="2025-02-10">
   <owner>rakina@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
@@ -2420,19 +2396,18 @@
     once for each abandonment reason. Metrics logged after non-terminal
     abandonment will be marked with the suffixes {BackgroundSuffix} and/or
     {HiddenSuffix}, and if the navigation involves a non-SRP URL but then
-    redirected to SRP URL, the logged metric will be marked with {NonSRPSuffix},
-    and {IncognitoSuffix}. The milestone recorded will be the latest milestone
-    (if there are multiple milestones reached before the abandonment). The
-    metric is emitted when the navigation gets abandoned.
+    redirected to SRP URL, the logged metric will be marked with {NonSRPSuffix}.
+    The milestone recorded will be the latest milestone (if there are multiple
+    milestones reached before the abandonment). The metric is emitted when the
+    navigation gets abandoned.
   </summary>
   <token key="BackgroundSuffix" variants="BackgroundSuffix"/>
   <token key="HiddenSuffix" variants="HiddenSuffix"/>
-  <token key="IncognitoSuffix" variants="IncognitoSuffix"/>
+  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="NavigationAbandonReason" variants="NavigationAbandonReason"/>
   <token key="NavigationMilestone" variants="NavigationMilestone"/>
   <token key="NonSRPSuffix" variants="NonSRPSuffix"/>
   <token key="ObservedNavigation" variants="ObservedNavigation"/>
-  <token key="ResponseFromCacheSuffix" variants="ResponseFromCacheSuffix"/>
   <token key="RTTBucketSuffix" variants="RTTBucketSuffix"/>
 </histogram>
 
@@ -2965,6 +2940,17 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.FrameCounts.AdFrames.PerFrame.DeferredForTagging"
+    enum="Boolean" expires_after="2025-02-05">
+  <owner>jdh@chromium.org</owner>
+  <owner>src/chrome/browser/tpcd/OWNERS</owner>
+  <summary>
+    Records whether the start of a child frame navigation was deferred to allow
+    ad tagging to be completed first or not. Recorded only when the
+    TPCDAdHeuristicSubframeRequestTagging feature is enabled.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.FrameCounts.AdFrames.PerFrame.OriginStatus"
     enum="CrossOriginAdStatus" expires_after="2025-07-10">
   <owner>johnidel@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/printing/histograms.xml b/tools/metrics/histograms/metadata/printing/histograms.xml
index a6c1402..6b481f2 100644
--- a/tools/metrics/histograms/metadata/printing/histograms.xml
+++ b/tools/metrics/histograms/metadata/printing/histograms.xml
@@ -407,7 +407,7 @@
 </histogram>
 
 <histogram name="Printing.CUPS.SavedPrintersCount" units="printers"
-    expires_after="2024-10-06">
+    expires_after="2025-10-06">
   <owner>gavinwill@chromium.org</owner>
   <owner>cros-peripherals@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/tab/enums.xml b/tools/metrics/histograms/metadata/tab/enums.xml
index 51f6bed78..d5f2c337 100644
--- a/tools/metrics/histograms/metadata/tab/enums.xml
+++ b/tools/metrics/histograms/metadata/tab/enums.xml
@@ -204,17 +204,6 @@
 
 <!-- LINT.ThenChange(//components/saved_tab_groups/types.h:TabGroupEvent) -->
 
-<enum name="TabManagerTabRankerResult">
-  <int value="0" label="Success">Tab score was calculated successfully.</int>
-  <int value="1" label="Preprocessor initialization failed">
-    The ExamplePreprocessorConfig could not be loaded or parsed.
-  </int>
-  <int value="2" label="Preprocessor other error">
-    The ExamplePreprocessor returned an error other than, or in addition to, the
-    kNoFeatureIndexFound error.
-  </int>
-</enum>
-
 <enum name="TabOrganizationTriggerOutcome">
   <int value="0" label="Accepted">User clicked through the nudge UI.</int>
   <int value="1" label="Dismissed">User explicitly dismissed the nudge UI.</int>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index 5f8b593..61e983f 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -1430,18 +1430,6 @@
   </summary>
 </histogram>
 
-<histogram name="TabManager.TabRanker.Result" enum="TabManagerTabRankerResult"
-    expires_after="M85">
-  <owner>michaelpg@chromium.org</owner>
-  <owner>charleszhao@chromium.org</owner>
-  <summary>
-    Logged when calculating a tab reactivation score for a background tab. Any
-    value other than &quot;none&quot; may indicate a bug in the inference code,
-    a problem with the preprocessor configuration shipped with the model, or a
-    bug in the code that populates the RankerExample for a tab.
-  </summary>
-</histogram>
-
 <histogram name="TabRestore.{RestoreType}.TimeBetweenClosedAndRestored"
     units="ms" expires_after="2025-01-05">
   <owner>sreejakshetty@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 5043e669..0f41980 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -21455,144 +21455,6 @@
   </metric>
 </event>
 
-<event name="TabManager.TabMetrics">
-  <owner>michaelpg@chromium.org</owner>
-  <summary>
-    Collects tab information for a tab after navigations, activations and close
-    events.
-  </summary>
-  <metric name="HasBeforeUnloadHandler">
-    <summary>
-      Boolean value indicating whether the page has a beforeunload JavaScript
-      event handler.
-    </summary>
-  </metric>
-  <metric name="HasFormEntry">
-    <summary>
-      Boolean value indicating whether the page has any user-input text.
-    </summary>
-  </metric>
-  <metric name="IsPinned">
-    <summary>
-      Boolean value indicating whether the tab is pinned in the tabstrip.
-    </summary>
-  </metric>
-  <metric name="KeyEventCount">
-    <summary>
-      Number of key events that were sent to the page.
-    </summary>
-  </metric>
-  <metric name="LabelId">
-    <summary>
-      An int64 random number generated at logging time. The same number will
-      also be logged to the TabManager.Background.ForegroundedOrClosed event, so
-      that feature label can be paired.
-    </summary>
-  </metric>
-  <metric name="MouseEventCount">
-    <summary>
-      Number of mouse events that were sent to the page.
-    </summary>
-  </metric>
-  <metric name="MRUIndex">
-    <summary>
-      Index of the tab in most-recently-used order. A value of N means there are
-      N tabs more recently used than the one that is being foregrounded or
-      closed.
-    </summary>
-  </metric>
-  <metric name="NavigationEntryCount">
-    <summary>
-      Number of navigation entries in the tab's NavigationController.
-      Corresponds to the size of the tab's back/forward list.
-    </summary>
-  </metric>
-  <metric name="NumReactivationBefore">
-    <summary>
-      Number of reactivations that this tab had till now.
-    </summary>
-  </metric>
-  <metric name="PageTransitionCoreType">
-    <summary>
-      Type of the page transition for this navigation. Uses the core values from
-      ui::PageTransition.
-    </summary>
-  </metric>
-  <metric name="PageTransitionFromAddressBar">
-    <summary>
-      True if the page transition came from interacting with the address bar,
-      such as by typing a URL or performing a search.
-    </summary>
-  </metric>
-  <metric name="PageTransitionIsRedirect">
-    <summary>
-      True if the page transition type is a redirect, in which case the
-      PageTransition type may not be accurate.
-    </summary>
-  </metric>
-  <metric name="QueryId">
-    <summary>
-      An int64 random number generated at query time of
-      TabManager::GetSortedLifecycleUnitsFromTabRanker. Tabs with the same
-      QueryId will be later on combined in one full list for further analysis.
-    </summary>
-  </metric>
-  <metric name="SiteEngagementScore">
-    <summary>
-      Site engagement score in the range [0, 100], rounded down to a multiple of
-      10 to limit granularity.
-    </summary>
-  </metric>
-  <metric name="TimeFromBackgrounded">
-    <summary>
-      Duration in MS from when the tab is backgrounded to when it is brought to
-      foreground or closed.
-    </summary>
-  </metric>
-  <metric name="TotalTabCount">
-    <summary>
-      Total number of tabs open across all non-incognito browser windows. Helps
-      contextualize the MRUIndex value.
-    </summary>
-  </metric>
-  <metric name="TouchEventCount">
-    <summary>
-      Number of touch events that were sent to the page.
-    </summary>
-  </metric>
-  <metric name="WasRecentlyAudible">
-    <summary>
-      Boolean value indicating whether the tab has played audio within the last
-      two seconds.
-    </summary>
-  </metric>
-  <metric name="WindowIsActive">
-    <summary>
-      Boolean value indicating whether the window is the active (frontmost)
-      window.
-    </summary>
-  </metric>
-  <metric name="WindowShowState">
-    <summary>
-      Enumeration of the window show state, such as fullscreen or minimized.
-      Values are enumerated in metrics::WindowMetricsEvent::ShowState.
-    </summary>
-  </metric>
-  <metric name="WindowTabCount">
-    <summary>
-      Number of tabs in the tab strip. Rounded down to the nearest exponential
-      bucket (with a bucket spacing factor of 1.5). Will be 1 for windows with
-      only one top-level WebContents, such as app windows.
-    </summary>
-  </metric>
-  <metric name="WindowType">
-    <summary>
-      Enumeration for the type of the window. Values are enumerated in
-      metrics::WindowMetricsEvent::Type.
-    </summary>
-  </metric>
-</event>
-
 <event name="TabManager.WindowMetrics">
   <owner>michaelpg@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 7f85dd4f..ba09fef 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,28 +1,28 @@
 {
     "trace_processor_shell": {
         "linux_arm64": {
-            "hash": "bb4e52b14323b733f66118e9f1bc146e2b2ad811",
-            "full_remote_path": "perfetto-luci-artifacts/v47.0/linux-arm64/trace_processor_shell"
+            "hash": "a9b776323ad6989d25e0d6c3dff2f829a27e0550",
+            "full_remote_path": "perfetto-luci-artifacts/baf3dcdc408c406ec523e3fde052e2672a3c37d2/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "9d21cb3253fcbe678fb323553fe7001268a9ed80",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/ecfdfaf092dc10cf75ba4e819eef4caab48e7c96/trace_processor_shell.exe"
+            "hash": "2a3e07f6278fd5d874171dcd84968f193ae65fc6",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/180231fef057dc2e575e58bdf13be8fd88ecad6e/trace_processor_shell.exe"
         },
         "linux_arm": {
-            "hash": "b5e5fcaf0e8ae5af509255c50c116d2ad6308221",
-            "full_remote_path": "perfetto-luci-artifacts/v47.0/linux-arm/trace_processor_shell"
+            "hash": "53f993fc3201982cd949c5b8de884682bb56de83",
+            "full_remote_path": "perfetto-luci-artifacts/baf3dcdc408c406ec523e3fde052e2672a3c37d2/linux-arm/trace_processor_shell"
         },
         "mac": {
             "hash": "f5d83eca972747f7c3db9f35c07ed57902418e8c",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/881ad50c05049ca13d4b34e4f92f4167de5ac52a/trace_processor_shell"
         },
         "mac_arm64": {
-            "hash": "7f99f145d5e23e95081b93ec3cef9eecf27679e1",
-            "full_remote_path": "perfetto-luci-artifacts/v47.0/mac-arm64/trace_processor_shell"
+            "hash": "2febae949dab5fcd582ef79bf82b90faecc9fead",
+            "full_remote_path": "perfetto-luci-artifacts/baf3dcdc408c406ec523e3fde052e2672a3c37d2/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "3b1a17b6e2b1d0246050895116f788a312d59475",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/ecfdfaf092dc10cf75ba4e819eef4caab48e7c96/trace_processor_shell"
+            "hash": "e55fb237f68c9dff2fcaca25a9ca96d4ce6528a4",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/180231fef057dc2e575e58bdf13be8fd88ecad6e/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/traffic_annotation/safe_list.txt b/tools/traffic_annotation/safe_list.txt
index 89f4aad7..690e53f 100644
--- a/tools/traffic_annotation/safe_list.txt
+++ b/tools/traffic_annotation/safe_list.txt
@@ -184,7 +184,6 @@
 missing_new_fields,components/captive_portal/content/captive_portal_service.cc
 missing_new_fields,components/commerce/core/account_checker.cc
 missing_new_fields,components/commerce/core/subscriptions/subscriptions_server_proxy.cc
-missing_new_fields,components/content_relationship_verification/digital_asset_links_handler.cc
 missing_new_fields,components/dom_distiller/core/distiller_url_fetcher.cc
 missing_new_fields,components/domain_reliability/uploader.cc
 missing_new_fields,components/download/internal/common/download_item_impl.cc
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index fb60c18..50c1b3b0 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -56,7 +56,7 @@
  <item id="devtools_network_resource" added_in_milestone="62" content_hash_code="06958290" os_list="linux,windows,chromeos" file_path="chrome/browser/devtools/devtools_ui_bindings.cc" />
  <item id="devtools_proxy_config" added_in_milestone="85" content_hash_code="01e83c36" os_list="linux,windows,chromeos,android" file_path="content/browser/devtools/protocol/target_handler.cc" />
  <item id="dial_url_fetcher" added_in_milestone="67" content_hash_code="07bd0650" os_list="linux,windows,chromeos" file_path="chrome/browser/media/router/discovery/dial/dial_url_fetcher.cc" />
- <item id="digital_asset_links" added_in_milestone="90" content_hash_code="00ced49e" os_list="linux,windows,chromeos,android" file_path="components/content_relationship_verification/digital_asset_links_handler.cc" />
+ <item id="digital_asset_links" added_in_milestone="90" content_hash_code="05caa66d" os_list="linux,windows,chromeos,android" file_path="components/content_relationship_verification/digital_asset_links_handler.cc" />
  <item id="direct_sockets" added_in_milestone="88" content_hash_code="03dc0aad" os_list="linux,windows,chromeos" file_path="content/browser/direct_sockets/direct_sockets_service_impl.cc" />
  <item id="dns_over_https" added_in_milestone="66" content_hash_code="02b087b6" os_list="linux,windows,chromeos,android" file_path="net/dns/dns_transaction.cc" />
  <item id="dns_transaction" added_in_milestone="65" content_hash_code="07e14f9f" os_list="linux,windows,chromeos,android" file_path="net/dns/dns_transaction.cc" />
diff --git a/tools/ubsan/ignorelist.txt b/tools/ubsan/ignorelist.txt
index f705667..877225f 100644
--- a/tools/ubsan/ignorelist.txt
+++ b/tools/ubsan/ignorelist.txt
@@ -22,7 +22,7 @@
 # https://crbug.com/40943968
 [signed-integer-overflow]
 fun:*OT*Layout*propagate_attachment_offsets*
-fun:*_hb_ot_shape_fallback_mark_position*
+src:*/hb-ot-shape-fallback.cc
 
 # https://crbug.com/363189664
 [null]
diff --git a/tools/win/DebugVisualizers/blink.natvis b/tools/win/DebugVisualizers/blink.natvis
index 847cd18..199ce33 100644
--- a/tools/win/DebugVisualizers/blink.natvis
+++ b/tools/win/DebugVisualizers/blink.natvis
@@ -121,10 +121,10 @@
       <Item Name="Ptr">ptr_</Item>
     </Expand>
   </Type>
-  <Type Name="blink::LayoutUnit">
-    <DisplayString>{(float)value_ / 64}</DisplayString>
+  <Type Name="blink::FixedPoint&lt;*&gt;">
+    <DisplayString>{(float)value_ / kFixedPointDenominator}</DisplayString>
     <Expand>
-      <Item Name="FloatVal">(float)value_ / 64</Item>
+      <Item Name="FloatVal">(float)value_ / kFixedPointDenominator</Item>
       <Item Name="RawVal">value_</Item>
     </Expand>
   </Type>
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index f1ab4e7..1129909 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -46,7 +46,7 @@
 
 BASE_FEATURE(kImageDescriptionsAlternateRouting,
              "ImageDescriptionsAlternateRouting",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 bool IsImageDescriptionsAlternateRoutingEnabled() {
   return base::FeatureList::IsEnabled(
       ::features::kImageDescriptionsAlternateRouting);
@@ -340,19 +340,20 @@
 
 BASE_FEATURE(kReadAnythingReadAloud,
              "ReadAnythingReadAloud",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-bool IsReadAnythingReadAloudEnabled() {
-  return base::FeatureList::IsEnabled(::features::kReadAnythingReadAloud);
-}
-
-BASE_FEATURE(kReadAloudAutoVoiceSwitching,
-             "ReadAloudAutoVoiceSwitching",
 #if BUILDFLAG(IS_CHROMEOS_ASH)
              base::FEATURE_ENABLED_BY_DEFAULT
 #else
              base::FEATURE_DISABLED_BY_DEFAULT
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 );
+
+bool IsReadAnythingReadAloudEnabled() {
+  return base::FeatureList::IsEnabled(::features::kReadAnythingReadAloud);
+}
+
+BASE_FEATURE(kReadAloudAutoVoiceSwitching,
+             "ReadAloudAutoVoiceSwitching",
+             base::FEATURE_ENABLED_BY_DEFAULT);
 bool IsReadAloudAutoVoiceSwitchingEnabled() {
   return IsReadAnythingReadAloudEnabled() &&
          base::FeatureList::IsEnabled(::features::kReadAloudAutoVoiceSwitching);
@@ -360,12 +361,7 @@
 
 BASE_FEATURE(kReadAloudLanguagePackDownloading,
              "ReadAloudLanguagePackDownloading",
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-             base::FEATURE_ENABLED_BY_DEFAULT
-#else
-             base::FEATURE_DISABLED_BY_DEFAULT
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 bool IsReadAloudLanguagePackDownloadingEnabled() {
   return IsReadAnythingReadAloudEnabled() &&
          base::FeatureList::IsEnabled(
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 1711f299..24ffa10 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -942,15 +942,6 @@
   return delegate_->GetTextContentUTF16();
 }
 
-// https://crbug.com/40889544 - to be removed once we gather some info on
-// the reason for the macOS exception being thrown.
-std::u16string AXPlatformNodeBase::GetTextContentUTF16WithInvisibles() const {
-  if (!delegate_) {
-    return std::u16string();
-  }
-  return delegate_->GetTextContentUTF16WithInvisibles();
-}
-
 std::u16string
 AXPlatformNodeBase::GetRoleDescriptionFromImageAnnotationStatusOrFromAttribute()
     const {
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 87a85ee..894eb62 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -345,10 +345,6 @@
   // e.g. aria-label and HTML title, is not returned.
   std::u16string GetTextContentUTF16() const;
 
-  // https://crbug.com/40889544 - to be removed once we gather some info on
-  // the reason for the macOS exception being thrown.
-  std::u16string GetTextContentUTF16WithInvisibles() const;
-
   // Returns the value of a control such as a text field, a slider, a <select>
   // element, a date picker or an ARIA combo box. In order to minimize
   // cross-process communication between the renderer and the browser, may
diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm
index 4d85272b..f5c231e 100644
--- a/ui/accessibility/platform/ax_platform_node_cocoa.mm
+++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm
@@ -48,10 +48,6 @@
 
 namespace {
 
-// https://crbug.com/40889544 - to be removed once we gather some info on
-// the reason for the macOS exception being thrown.
-size_t lengthWithInvisibles = 0;
-
 // Same length as web content/WebKit.
 int kLiveRegionDebounceMillis = 20;
 
@@ -788,10 +784,6 @@
   int anchorStartOffset = 0;
   std::map<ui::AXNodeID, std::set<ax::mojom::Role>> ancestor_roles;
 
-  // https://crbug.com/40889544 - to be removed once we gather some info on
-  // the reason for the macOS exception being thrown.
-  NSUInteger leafTextIndex = 0;
-
   [attributedString beginEditing];
   for (const AXRange& leafTextRange : *axRange) {
     DCHECK(!leafTextRange.IsNull());
@@ -837,39 +829,6 @@
               attributedString.length);
     NSRange leafRange = NSMakeRange(anchorStartOffset, leafTextLength);
 
-    // https://crbug.com/40889544 - to be removed once we gather some info on
-    // the reason for the macOS exception being thrown.
-    // Capture info about the suspected cause of
-    // "NSRangeException: NSMutableRLEArray objectAtIndex:effectiveRange:: Out
-    // of bounds", which is thrown if the range provided to
-    // addAttribute:value:range: is out of bounds.
-    leafTextIndex++;
-    if (NSMaxRange(leafRange) > attributedString.length) {
-      // Capture:
-      //   * Current leaf text index and total number of leaves
-      //   * Current leaf text's range
-      //   * The attributed string's length if we had created it by concating
-      //     the GetText()s of the individual leaves, instead of using
-      //     _node->GetTextContentUTF16() in -AXAttributedStringForRange:
-      //   * The attributed string's length if _node->GetTextContentUTF16()
-      //     included invisible elements.
-      NSUInteger numberOfLeaves = 0;
-      NSUInteger lengthFromGetTextsOfLeafRanges = 0;
-      for (const AXRange& nextRange : *axRange) {
-        numberOfLeaves++;
-        lengthFromGetTextsOfLeafRanges += nextRange.GetText().length();
-      }
-
-      NSString* info = [NSString
-          stringWithFormat:@"%lu of %lu %lu,%lu %lu %lu", leafTextIndex,
-                           numberOfLeaves, leafRange.location, leafRange.length,
-                           lengthFromGetTextsOfLeafRanges,
-                           lengthWithInvisibles];
-      SCOPED_CRASH_KEY_STRING256("AXPlatformNodeCocoa", "addTextAnnotations",
-                                 base::SysNSStringToUTF8(info));
-      base::debug::DumpWithoutCrashing();
-    }
-
     CollectAncestorRoles(*anchor, ancestor_roles);
 
     if (ancestor_roles[anchor->id()].contains(ax::mojom::Role::kMark)) {
@@ -2084,7 +2043,6 @@
   std::u16string textContent = _node->GetTextContentUTF16();
   if (NSMaxRange(range) > textContent.length())
     return nil;
-  lengthWithInvisibles = _node->GetTextContentUTF16WithInvisibles().length();
 
   // We potentially need to add text attributes to the whole text content
   // because a spelling mistake might start or end outside the given range.
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.cc b/ui/accessibility/platform/ax_platform_node_delegate.cc
index 52021e2..e88cf3f 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate.cc
@@ -90,55 +90,6 @@
   return text_content;
 }
 
-// https://crbug.com/40889544 - to be removed once we gather some info on
-// the reason for the macOS exception being thrown.
-std::u16string AXPlatformNodeDelegate::GetTextContentUTF16WithInvisibles()
-    const {
-  if (node_) {
-    return node_->GetTextContentUTF16();
-  }
-
-  // Unlike in web content the "kValue" attribute always takes precedence,
-  // because we assume that users of the base impl, such as Views controls,
-  // are carefully crafted by hand, in contrast to HTML pages, where any content
-  // that might be present in the shadow DOM (AKA in the internal accessibility
-  // tree) is actually used by the renderer when assigning the "kValue"
-  // attribute, including any redundant white space.
-  std::u16string value =
-      GetString16Attribute(ax::mojom::StringAttribute::kValue);
-  if (!value.empty()) {
-    return value;
-  }
-
-  // The name of a leaf node in Views is displayed inside the View, i.e.
-  // `GetNameFrom` == `ax::mojom::NameFrom::kContents`, except in text fields,
-  // where the name attribute is the field's label and the value attribute is
-  // the field's text contents. For maximum compatibility with the Web code, we
-  // compute the text of a non-leaf text field from the text contents of its
-  // children, even though we currently know of no such text field in Views.
-  //
-  // TODO(crbug.com/40662009): The check for `IsInvisibleOrIgnored()`
-  // should not be needed. `ChildAtIndex()` and `GetChildCount()` are already
-  // supposed to skip over nodes that are invisible or ignored, but
-  // `ViewAXPlatformNodeDelegate` does not currently implement this behavior.
-  //  if (IsLeaf() && !GetData().IsTextField() && !IsInvisibleOrIgnored()) {
-  //    return GetString16Attribute(ax::mojom::StringAttribute::kName);
-  //  }
-
-  std::u16string text_content;
-  for (size_t i = 0; i < GetChildCount(); ++i) {
-    // TODO(nektar): Add const to all tree traversal methods and remove
-    // const_cast.
-    const AXPlatformNode* child = AXPlatformNode::FromNativeViewAccessible(
-        const_cast<AXPlatformNodeDelegate*>(this)->ChildAtIndex(i));
-    if (!child || !child->GetDelegate()) {
-      continue;
-    }
-    text_content += child->GetDelegate()->GetTextContentUTF16WithInvisibles();
-  }
-  return text_content;
-}
-
 int AXPlatformNodeDelegate::GetTextContentLengthUTF16() const {
   // TODO(accessibility): Simplify once ViewsAX is complete.
   if (node_) {
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index ad9206f..564a66b 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -185,7 +185,6 @@
   // attributes that is either not displayed on screen, or outside this node,
   // e.g. aria-label and HTML title, is not returned.
   virtual std::u16string GetTextContentUTF16() const;
-  std::u16string GetTextContentUTF16WithInvisibles() const;
   virtual int GetTextContentLengthUTF16() const;
 
   // Returns the value of a control such as a text field, a slider, a <select>
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
index 61edeaf5b..a4bf8f7 100644
--- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
+++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -70,6 +70,7 @@
     private static final String VIDEO_TYPE = "video";
     private static final String AUDIO_TYPE = "audio";
     private static final String ALL_TYPES = "*/*";
+    private static final String GENERIC_TYPE = "application/octet-stream";
 
     // Duration before temporary camera file is cleaned up, in milliseconds.
     private static final long DURATION_BEFORE_FILE_CLEAN_UP_IN_MILLIS = TimeUnit.HOURS.toMillis(1);
@@ -251,7 +252,10 @@
 
     private long mNativeSelectFileDialog;
     private String mIntentAction;
+    // File types may contain both file extensions and MIME types.
     private List<String> mFileTypes;
+    // Converted from `mFileTypes`, only contains deduped MIME types.
+    private List<String> mMimeTypes;
     private boolean mCapture;
     private boolean mAllowMultiple;
     private Uri mCameraOutputUri;
@@ -306,6 +310,7 @@
         List<String> oldValue = mFileTypes;
         mFileTypes = fileTypes;
         ResettersForTesting.register(() -> mFileTypes = oldValue);
+        mMimeTypes = convertToSupportedMimeTypes(mFileTypes);
     }
 
     /**
@@ -329,6 +334,7 @@
                         ? intentAction
                         : Intent.ACTION_GET_CONTENT;
         mFileTypes = new ArrayList<String>(Arrays.asList(fileTypes));
+        mMimeTypes = convertToSupportedMimeTypes(mFileTypes);
         mCapture = capture;
         mAllowMultiple = multiple;
         mWindowAndroid = (sWindowAndroidForTesting == null) ? window : sWindowAndroidForTesting;
@@ -516,14 +522,13 @@
         }
 
         // Use the new photo picker, if available.
-        List<String> imageMimeTypes = convertToSupportedPhotoPickerTypes(mFileTypes);
         if (shouldUsePhotoPicker()
                 && showPhotoPicker(
                         mWindowAndroid,
                         /* intentCallback= */ this,
                         /* listener= */ this,
                         mAllowMultiple,
-                        imageMimeTypes)) {
+                        mMimeTypes)) {
             mMediaPickerWasUsed = true;
             return;
         } else {
@@ -560,8 +565,12 @@
             getContentIntent.setType(ALL_TYPES);
         }
 
-        List<String> types = new ArrayList<>(mFileTypes);
-        if (types.size() > 0) {
+        if (mMimeTypes.size() > 0) {
+            // If some of the extensions are generic, just let user selectall files.
+            List<String> types =
+                    mMimeTypes.contains(GENERIC_TYPE)
+                            ? new ArrayList<>()
+                            : new ArrayList<>(mMimeTypes);
             // Calls to ACTION_GET_CONTENT can result in the MediaPicker hijacking the call and
             // showing itself instead of the Files app, when only images or videos are provided.
             // This flow is not only confusing for the user (a MediaPicker on top of a MediaPicker?)
@@ -571,7 +580,10 @@
             if (shouldShowImageTypes() || shouldShowVideoTypes()) {
                 types.add("type/nonexistent");
             }
-            getContentIntent.putExtra(Intent.EXTRA_MIME_TYPES, types.toArray(new String[0]));
+
+            if (!types.isEmpty()) {
+                getContentIntent.putExtra(Intent.EXTRA_MIME_TYPES, types.toArray(new String[0]));
+            }
         }
 
         ArrayList<Intent> extraIntents = new ArrayList<Intent>();
@@ -618,7 +630,12 @@
 
         ArrayList<Intent> extraIntents = new ArrayList<Intent>();
         if (acceptsSingleType()) {
-            List<String> types = mFileTypes;
+            // Attention: We should change the variable below to `mMimeTypes`. Using of `mFileTypes`
+            // is discouraged because it may include both file and MIME types. We keep the current
+            // variable just in case something goes wrong with the newly introduced `mMimeTypes` so
+            // that we can switch back to the old implementation. Remove this method once the new
+            // implementation is proven to work properly.
+            List<String> types = new ArrayList<>(mFileTypes);
             // Calls to ACTION_GET_CONTENT can result in the MediaPicker hijacking the call and
             // showing itself instead of the Files app, when only images or videos are provided.
             // This flow is not only confusing for the user (a MediaPicker on top of a MediaPicker?)
@@ -667,64 +684,84 @@
     }
 
     /**
-     * Determines whether the photo picker should be used for this select file request.  To be
+     * Determines whether the photo picker should be used for this select file request. To be
      * applicable for the photo picker, the following must be true:
-     *   1.) Only media types were requested in the file request
-     *   2.) The file request did not explicitly ask to capture camera directly.
-     *   3.) The photo picker is supported by the embedder (i.e. Chrome).
-     *   4.) There is a valid Android Activity associated with the file request.
+     * 1.) Only media types were requested in the file request
+     * 2.) The file request did not explicitly ask to capture camera directly.
+     * 3.) The photo picker is supported by the embedder (i.e. Chrome).
+     * 4.) There is a valid Android Activity associated with the file request.
      */
     private boolean shouldUsePhotoPicker() {
-        List<String> mediaMimeTypes = convertToSupportedPhotoPickerTypes(mFileTypes);
         return !captureImage()
-                && mediaMimeTypes != null
+                && isSupportedPhotoPickerTypes(mMimeTypes)
                 && shouldShowPhotoPicker()
                 && mWindowAndroid.getActivity().get() != null;
     }
 
     /**
-     * Converts a list of extensions and Mime types to a list of de-duped Mime types supported by
-     * the photo picker only. If the input list contains a unsupported type, then null is returned.
-     * @param fileTypes the list of filetypes (extensions and Mime types) to convert.
-     * @return A de-duped list of supported types only, or null if one or more unsupported types
-     *         were given as input.
+     * Returns whether a list of MIME types are supported by photo picker.
+     *
+     * @param mimeTypes the list of MIME types to check.
+     * @return true if all MIME types are supported by photo picker, or false otherwise.
      */
     @VisibleForTesting
-    public static List<String> convertToSupportedPhotoPickerTypes(List<String> fileTypes) {
-        if (fileTypes.size() == 0) return null;
-        List<String> mimeTypes = new ArrayList<>();
-        for (String type : fileTypes) {
-            String mimeType = ensureMimeType(type);
-            if (!mimeType.startsWith("image/")) {
-                if (!photoPickerSupportsVideo() || !mimeType.startsWith("video/")) {
-                    return null;
+    public static boolean isSupportedPhotoPickerTypes(List<String> mimeTypes) {
+        if (mimeTypes.size() == 0) return false;
+        for (String type : mimeTypes) {
+            if (!type.startsWith("image/")) {
+                if (!photoPickerSupportsVideo() || !type.startsWith("video/")) {
+                    return false;
                 }
             }
-            if (!mimeTypes.contains(mimeType)) mimeTypes.add(mimeType);
+        }
+        return true;
+    }
+
+    /**
+     * Converts a list of extensions and MIME types to a list of de-duped MIME types. If the input
+     * list contains a unsupported extension, "application/octet-stream" is returned as the MIME
+     * tye.
+     *
+     * @param fileTypes the list of filetypes (extensions and Mime types) to convert.
+     * @return A de-duped list of supported types only.
+     */
+    @VisibleForTesting
+    public static List<String> convertToSupportedMimeTypes(List<String> fileTypes) {
+        List<String> mimeTypes = new ArrayList<>();
+        if (fileTypes.size() == 0) return mimeTypes;
+        for (String type : fileTypes) {
+            String mimeType = ensureMimeType(type);
+            if (!mimeType.isEmpty() && !mimeTypes.contains(mimeType)) {
+                mimeTypes.add(mimeType);
+            }
         }
         return mimeTypes;
     }
 
     /**
      * Convert |type| to MIME type (known types only).
+     *
      * @param type The type to convert. Can be either a MIME type or an extension (should include
-     *             the leading dot). If an extension is passed in, it is converted to the
-     *             corresponding MIME type (via {@link MimeTypeMap}), or "application/octet-stream"
-     *             if the MIME type is not known.
-     * @return The MIME type, if known, or "application/octet-stream" otherwise (or blank if input
-     *         is blank).
+     *     the leading dot). If an extension is passed in, it is converted to the corresponding MIME
+     *     type (via {@link MimeTypeMap}), or "application/octet-stream" if the MIME type is not
+     *     known.
+     * @return The MIME type, if known, or "application/octet-stream" otherwise (or blank if
+     *     extension is blank).
      */
     @VisibleForTesting
     public static String ensureMimeType(String type) {
         if (type.length() == 0) return "";
 
-        String extension = MimeTypeMap.getFileExtensionFromUrl(type);
-        if (extension.length() > 0) {
-            String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
-            if (mimeType != null) return mimeType;
-            return "application/octet-stream";
+        if (isMimeType(type)) {
+            return type;
         }
-        return type;
+
+        String extension = MimeTypeMap.getFileExtensionFromUrl(type);
+        if (extension.isEmpty()) return "";
+
+        String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+        if (mimeType != null) return mimeType;
+        return GENERIC_TYPE;
     }
 
     @Override
@@ -1001,14 +1038,17 @@
     // now we want to distinguish between generic, photo and visual media pickers.
     @VisibleForTesting
     int determineSelectFileDialogScope() {
-        if (mFileTypes.size() == 0) return SELECT_FILE_DIALOG_SCOPE_GENERIC;
+        if (mMimeTypes.size() == 0) return SELECT_FILE_DIALOG_SCOPE_GENERIC;
 
         // Capture the MIME types:
         int acceptsImages = countAcceptTypesFor(IMAGE_TYPE);
         int acceptsVideos = countAcceptTypesFor(VIDEO_TYPE);
 
         // Capture the most common image and video extensions:
-        if (mFileTypes.size() > acceptsImages + acceptsVideos) {
+        // TODO(b/365299139): This code below is probably wrong because mFileTypes may
+        // contain MIME types instead of file extensions. Need to figure out the
+        // right logic to count different types.
+        if (mMimeTypes.size() > acceptsImages + acceptsVideos) {
             for (String left : mFileTypes) {
                 boolean found = false;
                 for (String right : POPULAR_IMAGE_EXTENSIONS) {
@@ -1042,34 +1082,33 @@
     }
 
     /**
-     * Whether any of the mime-types in mFileTypes accepts the given type.
-     * If mFileTypes contains ALL_TYPES or is empty every type is accepted so always return true.
-     * @param superType The superType to look for, such as 'image' or 'video'.
-     *                  Note: This is string-matched on the prefix, so using generics as
-     *                  'image/*' or '*' will not work.
+     * Whether any of the types in `mMimeTypes` accepts the given type. If `mMimeTypes` contains
+     * ALL_TYPES or is empty every type is accepted so always return true.
+     *
+     * @param superType The superType to look for, such as 'image' or 'video'. Note: This is
+     *     string-matched on the prefix, so using generics as 'image/*' or '*' will not work.
      */
     private boolean acceptsType(String superType) {
-        if (mFileTypes.isEmpty() || mFileTypes.contains(ALL_TYPES)) return true;
+        if (mMimeTypes.isEmpty() || mMimeTypes.contains(ALL_TYPES)) return true;
         return countAcceptTypesFor(superType) > 0;
     }
 
     /**
-     * Whether all mime-types in mFileTypes accepts the given type.
-     * @param superType The superType to look for, such as 'image' or 'video'.
-     *                  Note: This is string-matched on the prefix, so using generics as
-     *                  'image/*' or '*' will not work.
+     * Whether all types in `mMimeTypes` accepts the given type.
+     *
+     * @param superType The superType to look for, such as 'image' or 'video'. Note: This is
+     *     string-matched on the prefix, so using generics as 'image/*' or '*' will not work.
      */
     private boolean acceptsOnlyType(String superType) {
-        return countAcceptTypesFor(superType) == mFileTypes.size();
+        return countAcceptTypesFor(superType) == mMimeTypes.size();
     }
 
     /**
-     * Checks whether the list of accepted types effectively describes only a single
-     * type, which might be wildcard. For example:
+     * Checks whether the list of accepted types effectively describes only a single type, which
+     * might be wildcard. For example:
      *
-     * [image/jpeg]            -> true: Only one type is specified.
-     * [image/jpeg, image/gif] -> false: Contains two distinct types.
-     * [image/*, image/gif]    -> true: image/gif already part of image/*.
+     * <p>[image/jpeg] -> true: Only one type is specified. [image/jpeg, image/gif] -> false:
+     * Contains two distinct types. [image/*, image/gif] -> true: image/gif already part of image/*.
      */
     @VisibleForTesting
     boolean acceptsSingleType() {
@@ -1077,13 +1116,13 @@
         // which means we can only give it a single type. If there are multiple accept types
         // specified, we will fallback to a generic chooser (unless a capture parameter has been
         // specified, in which case we'll try to satisfy that first.
-        if (mFileTypes.size() == 1) return !mFileTypes.contains(ALL_TYPES);
+        if (mMimeTypes.size() == 1) return !mMimeTypes.contains(ALL_TYPES);
         // Also return true when a generic subtype "type/*" and one or more specific subtypes
         // "type/subtype" are listed but all still have the same supertype.
         // Ie. treat ["image/png", "image/*"] as if it said just ["image/*"].
         String superTypeFound = null;
         boolean foundGenericSubtype = false;
-        for (String fileType : mFileTypes) {
+        for (String fileType : mMimeTypes) {
             int slash = fileType.indexOf('/');
             if (slash == -1) return false;
             String superType = fileType.substring(0, slash);
@@ -1143,7 +1182,7 @@
     private int countAcceptTypesFor(String superType) {
         assert superType.indexOf('/') == -1;
         int count = 0;
-        for (String type : mFileTypes) {
+        for (String type : mMimeTypes) {
             if (type.startsWith(superType)) {
                 count++;
             }
@@ -1311,10 +1350,6 @@
                 });
     }
 
-    private boolean eligibleForPhotoPicker() {
-        return convertToSupportedPhotoPickerTypes(mFileTypes) != null;
-    }
-
     protected void onFileSelected(
             long nativeSelectFileDialogImpl, String filePath, String displayName) {
         recordImageCountHistograms(new String[] {filePath});
@@ -1350,7 +1385,7 @@
     }
 
     private void recordImageCountHistograms(String[] filesSelected) {
-        if (eligibleForPhotoPicker()) {
+        if (isSupportedPhotoPickerTypes(mMimeTypes)) {
             // Record the total number of images selected via the Chrome Media Picker.
             RecordHistogram.recordCount100Histogram(
                     "Android.SelectFileDialogImgCount", filesSelected.length);
@@ -1688,6 +1723,15 @@
         return true;
     }
 
+    // Returns whether a string is a MIME type.
+    private static boolean isMimeType(String type) {
+        if (TextUtils.isEmpty(type) && type.length() < 3) {
+            return false;
+        }
+        int index = type.indexOf('/');
+        return index > 0 && index < type.length() - 1;
+    }
+
     @CalledByNative
     private void nativeDestroyed() {
         mNativeSelectFileDialog = 0;
diff --git a/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java b/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java
index dc7294d..9f7975d05 100644
--- a/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java
+++ b/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java
@@ -258,6 +258,11 @@
     }
 
     @Test
+    public void testExternalPickerWithFileExtensions() throws Exception {
+        verifyExternalPickerWithFileExtensions(Intent.ACTION_GET_CONTENT);
+    }
+
+    @Test
     @EnableFeatures({UiAndroidFeatures.SELECT_FILE_OPEN_DOCUMENT})
     public void testMimeTypesWithExternalPickerOpenDocument() throws Exception {
         testMimeTypesWithExternalPicker(Intent.ACTION_OPEN_DOCUMENT);
@@ -305,6 +310,149 @@
         selectFileDialog.resetFileSelectionAttempts();
     }
 
+    public void verifyExternalPickerWithFileExtensions(String intentAction) throws Exception {
+        ShadowMimeTypeMap shadowMimeTypeMap = Shadows.shadowOf(MimeTypeMap.getSingleton());
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("jpg", "image/jpeg");
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("gif", "image/gif");
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("pdf", "application/pdf");
+
+        TestSelectFileDialog selectFileDialog = new TestSelectFileDialog(0);
+        WindowAndroid windowAndroid = Mockito.mock(WindowAndroid.class);
+
+        // Select simple file extensions without setting up successful intent handling, to
+        // simulate the pipeline aborting because showIntent fails.
+        int callCount = mOnActionCallback.getCallCount();
+        selectFileDialog.selectFile(
+                intentAction,
+                new String[] {".pdf", ".jpg"},
+                /* capture= */ false,
+                /* multiple= */ false,
+                windowAndroid);
+        mOnActionCallback.waitForCallback(callCount, 1);
+        assertEquals(0, selectFileDialog.mFileSelectionSuccess);
+        assertEquals(1, selectFileDialog.mFileSelectionAborted);
+        selectFileDialog.resetFileSelectionAttempts();
+
+        // Now setup WindowAndroid#showIntent to succeed for our next run.
+        IntentArgumentMatcher chooserIntentArgumentMatcher =
+                new IntentArgumentMatcher(new Intent(Intent.ACTION_CHOOSER));
+        Mockito.doAnswer(
+                        (invocation) -> {
+                            // When showIntent is called, we use the opportunity to check on the
+                            // values we expect to see within the Intent data.
+                            Intent chooserIntent = (Intent) invocation.getArguments()[0];
+                            Intent getContentIntent =
+                                    (Intent) chooserIntent.getExtra(Intent.EXTRA_INTENT);
+                            assertEquals(
+                                    null, getContentIntent.getExtra(Intent.EXTRA_ALLOW_MULTIPLE));
+                            assertEquals("*/*", getContentIntent.getType());
+                            String[] mimeTypes =
+                                    (String[]) getContentIntent.getExtra(Intent.EXTRA_MIME_TYPES);
+                            assertArrayEquals(
+                                    new String[] {
+                                        "application/pdf",
+                                        "image/jpeg",
+                                        "image/gif",
+                                        "type/nonexistent"
+                                    },
+                                    mimeTypes);
+                            assertEquals(
+                                    null, getContentIntent.getExtra(Intent.EXTRA_INITIAL_INTENTS));
+                            assertTrue(getContentIntent.hasCategory(Intent.CATEGORY_OPENABLE));
+                            return true;
+                        })
+                .when(windowAndroid)
+                .showIntent(
+                        ArgumentMatchers.argThat(chooserIntentArgumentMatcher),
+                        (WindowAndroid.IntentCallback) any(),
+                        anyInt());
+
+        // Simulate showing the dialog, allowing a PDF and some images to be uploaded and watch the
+        // pipeline remain open.
+        callCount = mOnActionCallback.getCallCount();
+        selectFileDialog.selectFile(
+                intentAction,
+                new String[] {".pdf", ".jpg", "image/gif"},
+                /* capture= */ false,
+                /* multiple= */ false,
+                windowAndroid);
+        assertEquals(0, selectFileDialog.mFileSelectionSuccess);
+        assertEquals(0, selectFileDialog.mFileSelectionAborted);
+        selectFileDialog.resetFileSelectionAttempts();
+
+        // Setup showIntent to check for invalid file extensions.
+        Mockito.doAnswer(
+                        (invocation) -> {
+                            Intent chooserIntent = (Intent) invocation.getArguments()[0];
+                            Intent getContentIntent =
+                                    (Intent) chooserIntent.getExtra(Intent.EXTRA_INTENT);
+                            assertEquals(
+                                    true, getContentIntent.getExtra(Intent.EXTRA_ALLOW_MULTIPLE));
+                            assertEquals("*/*", getContentIntent.getType());
+                            String[] mimeTypes =
+                                    (String[]) getContentIntent.getExtra(Intent.EXTRA_MIME_TYPES);
+                            assertArrayEquals(new String[] {"type/nonexistent"}, mimeTypes);
+                            assertEquals(
+                                    null, getContentIntent.getExtra(Intent.EXTRA_INITIAL_INTENTS));
+                            assertTrue(getContentIntent.hasCategory(Intent.CATEGORY_OPENABLE));
+                            return true;
+                        })
+                .when(windowAndroid)
+                .showIntent(
+                        ArgumentMatchers.argThat(chooserIntentArgumentMatcher),
+                        (WindowAndroid.IntentCallback) any(),
+                        anyInt());
+
+        // Add a media file to the mix and allow multiple files.
+        callCount = mOnActionCallback.getCallCount();
+        selectFileDialog.selectFile(
+                intentAction,
+                new String[] {".xyz", "image/gif"},
+                /* capture= */ false,
+                /* multiple= */ true,
+                windowAndroid);
+        assertEquals(0, selectFileDialog.mFileSelectionSuccess);
+        assertEquals(0, selectFileDialog.mFileSelectionAborted);
+        selectFileDialog.resetFileSelectionAttempts();
+
+        // Setup showIntent to check for an empty file extensions, which will be
+        // ignored.
+        Mockito.doAnswer(
+                        (invocation) -> {
+                            Intent chooserIntent = (Intent) invocation.getArguments()[0];
+                            Intent getContentIntent =
+                                    (Intent) chooserIntent.getExtra(Intent.EXTRA_INTENT);
+                            assertEquals(
+                                    true, getContentIntent.getExtra(Intent.EXTRA_ALLOW_MULTIPLE));
+                            assertEquals("*/*", getContentIntent.getType());
+                            String[] mimeTypes =
+                                    (String[]) getContentIntent.getExtra(Intent.EXTRA_MIME_TYPES);
+                            assertArrayEquals(
+                                    new String[] {"image/gif", "type/nonexistent"}, mimeTypes);
+                            assertEquals(
+                                    null, getContentIntent.getExtra(Intent.EXTRA_INITIAL_INTENTS));
+                            assertTrue(getContentIntent.hasCategory(Intent.CATEGORY_OPENABLE));
+                            return true;
+                        })
+                .when(windowAndroid)
+                .showIntent(
+                        ArgumentMatchers.argThat(chooserIntentArgumentMatcher),
+                        (WindowAndroid.IntentCallback) any(),
+                        anyInt());
+
+        // Empty file extension is ignored.
+        callCount = mOnActionCallback.getCallCount();
+        selectFileDialog.selectFile(
+                intentAction,
+                new String[] {".", "image/gif"},
+                /* capture= */ false,
+                /* multiple= */ true,
+                windowAndroid);
+        assertEquals(0, selectFileDialog.mFileSelectionSuccess);
+        assertEquals(0, selectFileDialog.mFileSelectionAborted);
+        selectFileDialog.resetFileSelectionAttempts();
+    }
+
     @Test
     public void testFileSelectionUserActions() throws Exception {
         TestSelectFileDialog selectFileDialog = new TestSelectFileDialog(0);
@@ -590,42 +738,35 @@
         // Unknown extension, expect default response:
         assertEquals("application/octet-stream", SelectFileDialog.ensureMimeType(".flv"));
 
-        assertEquals(null, SelectFileDialog.convertToSupportedPhotoPickerTypes(new ArrayList<>()));
-        assertEquals(null, SelectFileDialog.convertToSupportedPhotoPickerTypes(Arrays.asList("")));
-        assertEquals(
-                null,
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(Arrays.asList("foo/bar")));
-        assertEquals(
-                Arrays.asList("image/jpeg"),
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(Arrays.asList(".jpg")));
-        assertEquals(
-                Arrays.asList("image/jpeg"),
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(Arrays.asList("image/jpeg")));
-        assertEquals(
-                Arrays.asList("image/jpeg"),
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(
-                        Arrays.asList(".jpg", "image/jpeg")));
-        assertEquals(
-                Arrays.asList("image/gif", "image/jpeg"),
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(
-                        Arrays.asList(".gif", "image/jpeg")));
+        assertFalse(SelectFileDialog.isSupportedPhotoPickerTypes(new ArrayList<>()));
+        assertFalse(SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList("")));
+        assertFalse(SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList("foo/bar")));
+        // ".jpg" is not a valid MIME type.
+        assertFalse(SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList(".jpg")));
+        assertTrue(SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList("image/jpeg")));
+        // If one of the file type is not a valid MIME type, the method should return false.
+        assertFalse(
+                SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList(".jpg", "image/jpeg")));
+        assertFalse(
+                SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList(".gif", "image/jpeg")));
+        assertTrue(
+                SelectFileDialog.isSupportedPhotoPickerTypes(
+                        Arrays.asList("image/gif", "image/jpeg")));
 
         // Video and mixed video/images support. This feature is supported, but off by default, so
         // expect failure until it is turned on by default.
-        assertEquals(
-                null, SelectFileDialog.convertToSupportedPhotoPickerTypes(Arrays.asList(".mpg")));
-        assertEquals(
-                null,
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(Arrays.asList("video/mpeg")));
-        assertEquals(
-                null,
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(
+        assertFalse(SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList(".mpg")));
+        assertFalse(SelectFileDialog.isSupportedPhotoPickerTypes(Arrays.asList("video/mpeg")));
+        assertFalse(
+                SelectFileDialog.isSupportedPhotoPickerTypes(
+                        Arrays.asList("image/jpeg", "video/mpeg")));
+        assertFalse(
+                SelectFileDialog.isSupportedPhotoPickerTypes(
                         Arrays.asList(".jpg", "image/jpeg", ".mpg")));
 
         // Returns null because generic picker is required (due to addition of .txt file).
-        assertEquals(
-                null,
-                SelectFileDialog.convertToSupportedPhotoPickerTypes(
+        assertFalse(
+                SelectFileDialog.isSupportedPhotoPickerTypes(
                         Arrays.asList(".txt", ".jpg", "image/jpeg")));
     }
 
@@ -719,6 +860,11 @@
 
     @Test
     public void testShowTypes() {
+        ShadowMimeTypeMap shadowMimeTypeMap = Shadows.shadowOf(MimeTypeMap.getSingleton());
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("jpg", "image/jpeg");
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("gif", "image/gif");
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("pdf", "application/pdf");
+
         SelectFileDialog selectFileDialog = new SelectFileDialog(0);
 
         selectFileDialog.setFileTypesForTests(Arrays.asList("image/jpeg"));
@@ -790,23 +936,83 @@
         assertTrue(selectFileDialog.shouldShowVideoTypes());
         assertTrue(selectFileDialog.shouldShowAudioTypes());
 
+        // Only the first one is considered valid MIME type.
         selectFileDialog.setFileTypesForTests(Arrays.asList("image//png", "image/", "image"));
-        assertFalse(selectFileDialog.acceptsSingleType());
+        assertTrue(selectFileDialog.acceptsSingleType());
         assertTrue(selectFileDialog.shouldShowImageTypes());
         assertFalse(selectFileDialog.shouldShowVideoTypes());
         assertFalse(selectFileDialog.shouldShowAudioTypes());
 
+        // Both are invalid MIME types
         selectFileDialog.setFileTypesForTests(Arrays.asList("/image", "/"));
         assertFalse(selectFileDialog.acceptsSingleType());
+        assertTrue(selectFileDialog.shouldShowImageTypes());
+        assertTrue(selectFileDialog.shouldShowVideoTypes());
+        assertTrue(selectFileDialog.shouldShowAudioTypes());
+
+        // Same, both are invalid MIME types
+        selectFileDialog.setFileTypesForTests(Arrays.asList("/", ""));
+        assertFalse(selectFileDialog.acceptsSingleType());
+        assertTrue(selectFileDialog.shouldShowImageTypes());
+        assertTrue(selectFileDialog.shouldShowVideoTypes());
+        assertTrue(selectFileDialog.shouldShowAudioTypes());
+
+        // Invalid extension
+        selectFileDialog.setFileTypesForTests(Arrays.asList(".xyz"));
+        assertTrue(selectFileDialog.acceptsSingleType());
+        assertFalse(selectFileDialog.shouldShowImageTypes());
+        assertFalse(selectFileDialog.shouldShowVideoTypes());
+        assertFalse(selectFileDialog.shouldShowAudioTypes());
+
+        // Both are converted to the same MIME type
+        selectFileDialog.setFileTypesForTests(Arrays.asList("application/octet-stream", ".xyz"));
+        assertTrue(selectFileDialog.acceptsSingleType());
+        assertFalse(selectFileDialog.shouldShowImageTypes());
+        assertFalse(selectFileDialog.shouldShowVideoTypes());
+        assertFalse(selectFileDialog.shouldShowAudioTypes());
+
+        selectFileDialog.setFileTypesForTests(Arrays.asList(".pdf", ".xyz"));
+        assertFalse(selectFileDialog.acceptsSingleType());
         assertFalse(selectFileDialog.shouldShowImageTypes());
         assertFalse(selectFileDialog.shouldShowVideoTypes());
         assertFalse(selectFileDialog.shouldShowAudioTypes());
 
-        selectFileDialog.setFileTypesForTests(Arrays.asList("/", ""));
-        assertFalse(selectFileDialog.acceptsSingleType());
-        assertFalse(selectFileDialog.shouldShowImageTypes());
+        selectFileDialog.setFileTypesForTests(Arrays.asList(".gif", "image/gif"));
+        assertTrue(selectFileDialog.acceptsSingleType());
+        assertTrue(selectFileDialog.shouldShowImageTypes());
         assertFalse(selectFileDialog.shouldShowVideoTypes());
         assertFalse(selectFileDialog.shouldShowAudioTypes());
+
+        selectFileDialog.setFileTypesForTests(Arrays.asList(".gif", ".jpg"));
+        assertFalse(selectFileDialog.acceptsSingleType());
+        assertTrue(selectFileDialog.shouldShowImageTypes());
+        assertFalse(selectFileDialog.shouldShowVideoTypes());
+        assertFalse(selectFileDialog.shouldShowAudioTypes());
+    }
+
+    @Test
+    public void testConvertToSupportedMimeTypes() {
+        ShadowMimeTypeMap shadowMimeTypeMap = Shadows.shadowOf(MimeTypeMap.getSingleton());
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("jpg", "image/jpeg");
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("gif", "image/gif");
+        shadowMimeTypeMap.addExtensionMimeTypeMapping("pdf", "application/pdf");
+
+        assertEquals(
+                SelectFileDialog.convertToSupportedMimeTypes(Arrays.asList("image/jpeg", ".jpg")),
+                Arrays.asList("image/jpeg"));
+
+        assertEquals(
+                SelectFileDialog.convertToSupportedMimeTypes(Arrays.asList("image/gif", "jpg")),
+                Arrays.asList("image/gif"));
+
+        assertEquals(
+                SelectFileDialog.convertToSupportedMimeTypes(Arrays.asList("image/gif", ".xyz")),
+                Arrays.asList("image/gif", "application/octet-stream"));
+
+        // Empty extensions are omitted.
+        assertEquals(
+                SelectFileDialog.convertToSupportedMimeTypes(Arrays.asList("image/gif", ".", "")),
+                Arrays.asList("image/gif"));
     }
 
     ContentResolver getMockContentResolver(String mimeType) {
diff --git a/ui/android/ui_android_features.cc b/ui/android/ui_android_features.cc
index 4dfb361..24b76e98 100644
--- a/ui/android/ui_android_features.cc
+++ b/ui/android/ui_android_features.cc
@@ -15,7 +15,7 @@
 
 BASE_FEATURE(kDeprecatedExternalPickerFunction,
              "DeprecatedExternalPickerFunction",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 BASE_FEATURE(kMirrorBackForwardGesturesInRTL,
              "MirrorBackForwardGesturesInRTL",
diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn
index 333424e5..84afacf 100644
--- a/ui/display/BUILD.gn
+++ b/ui/display/BUILD.gn
@@ -301,7 +301,7 @@
     public_deps += [ "//ui/display:managed_display_info" ]
   }
 
-  if (!is_mac && !is_win &&
+  if (!is_mac && !is_win && !is_chromeos_ash &&
       !(is_linux && ozone_platform_x11 && enable_remoting)) {
     sources += [
       # Virtual display util stub for unimplemented platforms.
diff --git a/ui/display/linux/test/DEPS b/ui/display/linux/test/DEPS
index 6276d0f..2094421 100644
--- a/ui/display/linux/test/DEPS
+++ b/ui/display/linux/test/DEPS
@@ -1,5 +1,3 @@
 include_rules = [
   "+ui/aura/screen_ozone.h",
-  "+remoting/host/x11_desktop_resizer.h",
-  "+remoting/host/desktop_geometry.h"
 ]
diff --git a/ui/display/linux/test/virtual_display_util_linux.cc b/ui/display/linux/test/virtual_display_util_linux.cc
index 2f7df67..7da85c5 100644
--- a/ui/display/linux/test/virtual_display_util_linux.cc
+++ b/ui/display/linux/test/virtual_display_util_linux.cc
@@ -10,36 +10,37 @@
 
 #include "base/environment.h"
 #include "base/nix/xdg_util.h"
-#include "remoting/host/desktop_geometry.h"
-#include "remoting/host/x11_desktop_resizer.h"
 #include "ui/display/display.h"
 #include "ui/display/display_list.h"
 #include "ui/display/screen.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/x/connection.h"
 #include "ui/gfx/x/randr.h"
+#include "ui/gfx/x/randr_output_manager.h"
 
 namespace {
 
-// Appends a new screen with `resolution` to the specified desktop
+// Appends a new screen with `resolution` and `dpi` to the specified desktop
 // `layout`. Arranges horizontally left to right.
-void AppendScreen(remoting::DesktopLayoutSet& layout,
-                  const remoting::DesktopResolution& resolution) {
+void AppendScreen(x11::RandRMonitorLayout& layout,
+                  const gfx::Size& resolution,
+                  const gfx::Vector2d& dpi) {
   // Find the rightmost screen layout.
-  const remoting::DesktopLayout* rightmost_layout = nullptr;
-  for (const auto& screen : layout.layouts) {
+  const x11::RandRMonitorConfig* rightmost_layout = nullptr;
+  for (const auto& screen : layout.configs) {
     if (rightmost_layout == nullptr ||
         screen.rect().right() > rightmost_layout->rect().right()) {
       rightmost_layout = &screen;
     }
   }
-  layout.layouts.emplace_back(
+  layout.configs.emplace_back(
       std::nullopt,
       gfx::Rect(rightmost_layout->rect().right() + 1,
-                rightmost_layout->position_y(), resolution.dimensions().width(),
-                resolution.dimensions().height()),
-      resolution.dpi());
+                rightmost_layout->rect().y(), resolution.width(),
+                resolution.height()),
+      dpi);
 }
 }  // namespace
 
@@ -47,8 +48,9 @@
 
 VirtualDisplayUtilLinux::VirtualDisplayUtilLinux(Screen* screen)
     : screen_(screen),
-      desktop_resizer_(std::make_unique<remoting::X11DesktopResizer>()),
-      initial_layout_(desktop_resizer_->GetLayout()),
+      randr_output_manager_(std::make_unique<x11::RandROutputManager>(
+          /*output_name_prefix=*/"VDU_")),
+      initial_layout_(randr_output_manager_->GetLayout()),
       current_layout_(initial_layout_) {
   CHECK(screen_);
   screen_->AddObserver(this);
@@ -60,7 +62,7 @@
 
 // static
 bool VirtualDisplayUtilLinux::IsAPIAvailable() {
-  // Check if XRandR is running with a sufficient number of connected outputs.
+  // Check if XRandR is available with a sufficient number of connected outputs.
   // Skip base::nix::GetSessionType(...), which may return kTty instead of kX11
   // in SSH sessions with virtualized X11 environments.
 
@@ -107,18 +109,17 @@
                << " already exists or requested.";
     return kInvalidDisplayId;
   }
-  if (current_layout_.layouts.size() - initial_layout_.layouts.size() >
+  if (current_layout_.configs.size() - initial_layout_.configs.size() >
       kMaxDisplays) {
     LOG(ERROR) << "Cannot exceed " << kMaxDisplays << " virtual displays.";
     return kInvalidDisplayId;
   }
-  CHECK(!current_layout_.layouts.empty());
+  CHECK(!current_layout_.configs.empty());
   last_requested_layout_ = current_layout_;
-  AppendScreen(last_requested_layout_,
-               remoting::DesktopResolution(display_params.resolution,
-                                           display_params.dpi));
+  AppendScreen(last_requested_layout_, display_params.resolution,
+               display_params.dpi);
   requested_ids_.push_back(id);
-  desktop_resizer_->SetVideoLayout(last_requested_layout_);
+  randr_output_manager_->SetLayout(last_requested_layout_);
   detected_added_display_ids_.clear();
   StartWaiting();
   CHECK_EQ(detected_added_display_ids_.size(), 1u)
@@ -126,40 +127,43 @@
   // Reconcile the added resizer display ID to the detected display::Display id.
   int64_t new_display_id = detected_added_display_ids_.front();
   detected_added_display_ids_.pop_front();
-  remoting::DesktopLayoutSet prev_layout = current_layout_;
-  current_layout_ = desktop_resizer_->GetLayout();
-  for (const auto& layout : current_layout_.layouts) {
+  x11::RandRMonitorLayout prev_layout = current_layout_;
+  current_layout_ = randr_output_manager_->GetLayout();
+  for (const auto& layout : current_layout_.configs) {
     auto was_added =
-        std::find_if(prev_layout.layouts.begin(), prev_layout.layouts.end(),
-                     [&](const remoting::DesktopLayout& prev) {
+        std::find_if(prev_layout.configs.begin(), prev_layout.configs.end(),
+                     [&](const x11::RandRMonitorConfig& prev) {
                        return prev.rect() == layout.rect();
                      });
-    if (was_added == prev_layout.layouts.end()) {
-      display_id_to_resizer_id_[new_display_id] = *layout.screen_id();
+    if (was_added == prev_layout.configs.end()) {
+      display_id_to_randr_id_[new_display_id] = *layout.id();
     }
   }
   return new_display_id;
 }
+
 void VirtualDisplayUtilLinux::RemoveDisplay(int64_t display_id) {
-  if (!display_id_to_resizer_id_.contains(display_id)) {
+  if (!display_id_to_randr_id_.contains(display_id)) {
     LOG(ERROR) << "Invalid display_id. Missing mapping for " << display_id
                << " to resizer ID.";
     return;
   }
   last_requested_layout_ = current_layout_;
-  std::erase_if(last_requested_layout_.layouts,
-                [&](const remoting::DesktopLayout& layout) {
-                  return layout.screen_id() ==
-                         display_id_to_resizer_id_[display_id];
+  x11::RandRMonitorConfig::ScreenId randr_id =
+      display_id_to_randr_id_[display_id];
+  std::erase_if(last_requested_layout_.configs,
+                [&](const x11::RandRMonitorConfig& layout) {
+                  return layout.id() == randr_id;
                 });
-  desktop_resizer_->SetVideoLayout(last_requested_layout_);
+  randr_output_manager_->SetLayout(last_requested_layout_);
   StartWaiting();
 }
+
 void VirtualDisplayUtilLinux::ResetDisplays() {
   last_requested_layout_ = initial_layout_;
-  desktop_resizer_->SetVideoLayout(last_requested_layout_);
+  randr_output_manager_->SetLayout(last_requested_layout_);
   StartWaiting();
-  current_layout_ = desktop_resizer_->GetLayout();
+  current_layout_ = randr_output_manager_->GetLayout();
 }
 
 void VirtualDisplayUtilLinux::OnDisplayAdded(
@@ -184,10 +188,11 @@
                   [&](std::pair<uint8_t, int64_t>& pair) {
                     return pair.second == display.id();
                   });
-    base::EraseIf(display_id_to_resizer_id_,
-                  [&](std::pair<DisplayId, ResizerDisplayId>& pair) {
-                    return pair.first == display.id();
-                  });
+    base::EraseIf(
+        display_id_to_randr_id_,
+        [&](std::pair<DisplayId, x11::RandRMonitorConfig::ScreenId>& pair) {
+          return pair.first == display.id();
+        });
     base::EraseIf(detected_added_display_ids_,
                   [&](DisplayId& id) { return id == display.id(); });
     OnDisplayAddedOrRemoved(display.id());
@@ -204,8 +209,8 @@
 bool VirtualDisplayUtilLinux::RequestedLayoutIsSet() {
   // Checks that the number of virtual displays (delta of last requested layout
   // minus initial layout) is equal to the number of requested displays.
-  return last_requested_layout_.layouts.size() -
-             initial_layout_.layouts.size() ==
+  return last_requested_layout_.configs.size() -
+             initial_layout_.configs.size() ==
          requested_ids_to_display_ids_.size();
 }
 
diff --git a/ui/display/linux/test/virtual_display_util_linux.h b/ui/display/linux/test/virtual_display_util_linux.h
index e35f817..ee9df63 100644
--- a/ui/display/linux/test/virtual_display_util_linux.h
+++ b/ui/display/linux/test/virtual_display_util_linux.h
@@ -8,9 +8,9 @@
 #include "base/containers/circular_deque.h"
 #include "base/containers/flat_map.h"
 #include "base/run_loop.h"
-#include "remoting/host/x11_desktop_resizer.h"
 #include "ui/display/display_observer.h"
 #include "ui/display/test/virtual_display_util.h"
+#include "ui/gfx/x/randr_output_manager.h"
 
 namespace display {
 class Display;
@@ -58,26 +58,26 @@
 
   std::unique_ptr<base::RunLoop> run_loop_;
   raw_ptr<Screen> screen_;
-  std::unique_ptr<remoting::X11DesktopResizer> desktop_resizer_;
+  std::unique_ptr<x11::RandROutputManager> randr_output_manager_;
   // Initial layout when this class was instantiated that should be restored.
-  remoting::DesktopLayoutSet initial_layout_;
-  // Current layout calculated by `desktop_resizer_` after an operation.
-  remoting::DesktopLayoutSet current_layout_;
-  // Last layout request sent to `desktop_resizer_`.
-  remoting::DesktopLayoutSet last_requested_layout_;
+  x11::RandRMonitorLayout initial_layout_;
+  // Current layout calculated by `randr_output_manager_` after an operation.
+  x11::RandRMonitorLayout current_layout_;
+  // Last layout request sent to `randr_output_manager_`.
+  x11::RandRMonitorLayout last_requested_layout_;
 
   // There are lots of IDS to track here:
   //  1. The user-requested ID set in AddDisplay().
-  //  2. The resizer (xrandr) display ID
+  //  2. The xrandr display ID
   //  3. The display ID detected by the display::Screen implementation.
   using RequestedId = uint8_t;
-  using ResizerDisplayId = int64_t;
   using DisplayId = int64_t;
 
   // Queue of displays added via OnDisplayAdded. Removed as they are reconciled
-  // and moved to `display_id_to_resizer_id_`.
+  // and moved to `display_id_to_randr_id_`.
   base::circular_deque<DisplayId> detected_added_display_ids_;
-  base::flat_map<DisplayId, ResizerDisplayId> display_id_to_resizer_id_;
+  base::flat_map<DisplayId, x11::RandRMonitorConfig::ScreenId>
+      display_id_to_randr_id_;
 
   // Tracks display IDs requested in AddDisplay(). The IDs don't do anything in
   // this implementation, but they are tracked to prevent the user from
diff --git a/ui/display/test/display_manager_test_api.cc b/ui/display/test/display_manager_test_api.cc
index 8e0d90e3..85be3fe 100644
--- a/ui/display/test/display_manager_test_api.cc
+++ b/ui/display/test/display_manager_test_api.cc
@@ -5,6 +5,7 @@
 #include "ui/display/test/display_manager_test_api.h"
 
 #include <cstdarg>
+#include <iterator>
 #include <vector>
 
 #include "base/logging.h"
@@ -18,6 +19,8 @@
 #include "ui/display/screen.h"
 #include "ui/display/test/display_test_util.h"
 #include "ui/display/util/display_util.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace display {
 namespace test {
@@ -67,12 +70,74 @@
   DCHECK(display_manager);
 }
 
-DisplayManagerTestApi::~DisplayManagerTestApi() {}
+DisplayManagerTestApi::~DisplayManagerTestApi() = default;
 
 void DisplayManagerTestApi::ResetMaximumDisplay() {
   maximum_support_display_ = kDefaultMaxSupportDisplayTest;
 }
 
+int64_t DisplayManagerTestApi::AddDisplay(uint8_t id,
+                                          const DisplayParams& display_params) {
+  const Displays& current_displays = display_manager_->active_display_list();
+  if (current_displays.size() >= maximum_support_display_) {
+    LOG(ERROR) << "Display limit exceeded.";
+    return kInvalidDisplayId;
+  }
+  int64_t new_display_id = GetASynthesizedDisplayId();
+  std::vector<ManagedDisplayInfo> current_display_infos;
+  for (const Display& display : current_displays) {
+    if (display_id_to_add_display_id_[display.id()] == id) {
+      LOG(ERROR) << "Display with ID " << id << " already exists.";
+      return kInvalidDisplayId;
+    }
+    ManagedDisplayInfo display_info =
+        GetInternalManagedDisplayInfo(display.id());
+    gfx::Rect bounds = display_info.bounds_in_native();
+    // Reset the bounds so that UpdateDisplayWithDisplayInfoList automatically
+    // arranges them.
+    bounds.set_origin(gfx::Point());
+    display_info.SetBounds(bounds);
+    current_display_infos.push_back(display_info);
+  }
+  ManagedDisplayInfo new_display;
+  new_display.set_display_id(new_display_id);
+  new_display.SetBounds(gfx::Rect(display_params.resolution));
+  ManagedDisplayInfo::ManagedDisplayModeList display_modes;
+  display_modes.emplace_back(display_params.resolution, /*refresh_rate=*/60,
+                             /*is_interlaced=*/false, /*native=*/true,
+                             /*device_scale_factor=*/1);
+  new_display.SetManagedDisplayModes(display_modes);
+  current_display_infos.push_back(new_display);
+  UpdateDisplayWithDisplayInfoList(current_display_infos,
+                                   /*from_native_platform=*/false);
+  display_id_to_add_display_id_[new_display.id()] = id;
+  return new_display.id();
+}
+
+void DisplayManagerTestApi::RemoveDisplay(int64_t display_id) {
+  const Displays& active_displays = display_manager_->active_display_list();
+  std::vector<ManagedDisplayInfo> desired_display_infos;
+  for (const Display& display : active_displays) {
+    if (display.id() == display_id) {
+      display_id_to_add_display_id_.erase(display_id);
+      continue;
+    }
+    desired_display_infos.push_back(
+        GetInternalManagedDisplayInfo(display.id()));
+  }
+  if (desired_display_infos.size() == active_displays.size()) {
+    LOG(ERROR) << "Display with ID " << display_id << " not found.";
+    return;
+  }
+
+  UpdateDisplayWithDisplayInfoList(desired_display_infos,
+                                   /*from_native_platform=*/false);
+}
+
+void DisplayManagerTestApi::ResetDisplays() {
+  display_manager_->InitDefaultDisplay();
+}
+
 void DisplayManagerTestApi::UpdateDisplay(const std::string& display_specs,
                                           bool from_native_platform,
                                           bool generate_new_ids) {
diff --git a/ui/display/test/display_manager_test_api.h b/ui/display/test/display_manager_test_api.h
index 8d6cc3d..0196673 100644
--- a/ui/display/test/display_manager_test_api.h
+++ b/ui/display/test/display_manager_test_api.h
@@ -11,11 +11,13 @@
 #include <string>
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/memory/raw_ptr.h"
 #include "ui/display/display.h"
 #include "ui/display/display_export.h"
 #include "ui/display/display_layout.h"
 #include "ui/display/manager/util/display_manager_util.h"
+#include "ui/display/test/virtual_display_util.h"
 #include "ui/display/types/display_constants.h"
 
 namespace gfx {
@@ -28,14 +30,18 @@
 
 namespace test {
 
-class DISPLAY_EXPORT DisplayManagerTestApi {
+class DISPLAY_EXPORT DisplayManagerTestApi : public VirtualDisplayUtil {
  public:
   explicit DisplayManagerTestApi(DisplayManager* display_manager);
-
   DisplayManagerTestApi(const DisplayManagerTestApi&) = delete;
   DisplayManagerTestApi& operator=(const DisplayManagerTestApi&) = delete;
 
-  virtual ~DisplayManagerTestApi();
+  ~DisplayManagerTestApi() override;
+
+  // VirtualDisplayUtil:
+  int64_t AddDisplay(uint8_t id, const DisplayParams& display_params) override;
+  void RemoveDisplay(int64_t display_id) override;
+  void ResetDisplays() override;
 
   void set_maximum_display(size_t maximum_display_num) {
     maximum_support_display_ = maximum_display_num;
@@ -87,6 +93,9 @@
   static size_t maximum_support_display_;
 
   raw_ptr<DisplayManager> display_manager_;  // not owned
+
+  // TODO(crbug.com/40271794): Remove this once AddDisplay id is removed.
+  base::flat_map<uint64_t, uint8_t> display_id_to_add_display_id_;
 };
 
 class DISPLAY_EXPORT ScopedSetInternalDisplayId {
diff --git a/ui/gfx/x/BUILD.gn b/ui/gfx/x/BUILD.gn
index 19a858a8..802404b 100644
--- a/ui/gfx/x/BUILD.gn
+++ b/ui/gfx/x/BUILD.gn
@@ -171,6 +171,8 @@
     "keyboard_state.h",
     "property_cache.cc",
     "property_cache.h",
+    "randr_output_manager.cc",
+    "randr_output_manager.h",
     "ref_counted_fd.cc",
     "ref_counted_fd.h",
     "visual_manager.cc",
@@ -183,6 +185,8 @@
     "window_event_manager.h",
     "wm_sync.cc",
     "wm_sync.h",
+    "x11_crtc_resizer.cc",
+    "x11_crtc_resizer.h",
     "x11_path.cc",
     "x11_path.h",
     "xlib_support.cc",
@@ -217,8 +221,10 @@
     "connection_unittest.cc",
     "geometry_cache_unittest.cc",
     "property_cache_unittest.cc",
+    "randr_output_manager_unittest.cc",
     "window_cache_unittest.cc",
     "wm_sync_unittest.cc",
+    "x11_crtc_resizer_unittest.cc",
   ]
   deps = [
     "//base",
diff --git a/ui/gfx/x/connection.cc b/ui/gfx/x/connection.cc
index a3f9a89..1bbe75e 100644
--- a/ui/gfx/x/connection.cc
+++ b/ui/gfx/x/connection.cc
@@ -970,4 +970,14 @@
   synced_with_wm_ = true;
 }
 
+ScopedXGrabServer::ScopedXGrabServer(x11::Connection* connection)
+    : connection_(connection) {
+  connection_->GrabServer();
+}
+
+ScopedXGrabServer::~ScopedXGrabServer() {
+  connection_->UngrabServer();
+  connection_->Flush();
+}
+
 }  // namespace x11
diff --git a/ui/gfx/x/connection.h b/ui/gfx/x/connection.h
index aee149e..4f496a79 100644
--- a/ui/gfx/x/connection.h
+++ b/ui/gfx/x/connection.h
@@ -603,6 +603,21 @@
   std::unique_ptr<PropertyCache> wm_props_;
 };
 
+// Grab/release the X server connection within a scope. This can help avoid race
+// conditions that would otherwise lead to X errors.
+class COMPONENT_EXPORT(X11) ScopedXGrabServer {
+ public:
+  explicit ScopedXGrabServer(x11::Connection* connection);
+
+  ScopedXGrabServer(const ScopedXGrabServer&) = delete;
+  ScopedXGrabServer& operator=(const ScopedXGrabServer&) = delete;
+
+  ~ScopedXGrabServer();
+
+ private:
+  raw_ptr<x11::Connection> connection_;
+};
+
 }  // namespace x11
 
 namespace base {
diff --git a/ui/gfx/x/randr_output_manager.cc b/ui/gfx/x/randr_output_manager.cc
new file mode 100644
index 0000000..0f45816
--- /dev/null
+++ b/ui/gfx/x/randr_output_manager.cc
@@ -0,0 +1,561 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/x/randr_output_manager.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <type_traits>
+
+#include "base/containers/contains.h"
+#include "base/containers/span.h"
+#include "base/logging.h"
+#include "base/numerics/byte_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/system/sys_info.h"
+#include "base/types/cxx23_to_underlying.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/x11_crtc_resizer.h"
+
+// Xrandr has a number of restrictions that make exact resize more complex:
+//
+//   1. It's not possible to change the resolution of an existing mode. Instead,
+//      the mode must be deleted and recreated.
+//   2. It's not possible to delete a mode that's in use.
+//   3. Errors are communicated via Xlib's spectacularly unhelpful mechanism
+//      of terminating the process unless you install an error handler.
+//   4. The root window size must always enclose any enabled Outputs (that is,
+//      any output which is attached to a CRTC).
+//   5. An Output cannot be given properties (xy-offsets, mode) which would
+//      extend its rectangle beyond the root window size.
+//
+// Since we want the current mode name to be consistent (for each Output), the
+// approach is as follows:
+//
+//   1. Fetch information about all the active (enabled) CRTCs.
+//   2. Disable the RANDR Output being resized.
+//   3. Delete the CRD mode, if it exists.
+//   4. Create the CRD mode at the new resolution, and add it to the Output's
+//      list of modes.
+//   5. Adjust the properties (in memory) of any CRTCs to be modified:
+//      * Width/height (mode) of the CRTC being resized.
+//      * xy-offsets to avoid overlapping CRTCs.
+//   6. Disable any CRTCs that might prevent changing the root window size.
+//   7. Compute the bounding rectangle of all CRTCs (after adjustment), and set
+//      it as the new root window size.
+//   8. Apply all adjusted CRTC properties to the CRTCs. This will set the
+//      Output being resized to the new CRD mode (which re-enables it), and it
+//      will re-enable any other CRTCs that were disabled.
+
+namespace {
+
+constexpr auto kInvalidMode = static_cast<x11::RandR::Mode>(0);
+constexpr auto kDisabledCrtc = static_cast<x11::RandR::Crtc>(0);
+constexpr int kDefaultScreenDpi = 96;
+constexpr double kMillimetersPerInch = 25.4;
+
+int CalculateDpi(uint16_t length_in_pixels, uint32_t length_in_mm) {
+  if (length_in_mm == 0) {
+    return kDefaultScreenDpi;
+  }
+  double pixels_per_mm = static_cast<double>(length_in_pixels) / length_in_mm;
+  double pixels_per_inch = pixels_per_mm * kMillimetersPerInch;
+  return base::ClampRound(pixels_per_inch);
+}
+
+gfx::Vector2d GetMonitorDpi(const x11::RandR::MonitorInfo& monitor) {
+  return gfx::Vector2d(
+      CalculateDpi(monitor.width, monitor.width_in_millimeters),
+      CalculateDpi(monitor.height, monitor.height_in_millimeters));
+}
+
+x11::RandRMonitorConfig ToRandRMonitorConfig(
+    const x11::RandR::MonitorInfo& monitor) {
+  return x11::RandRMonitorConfig(
+      static_cast<intptr_t>(monitor.name),
+      gfx::Rect(monitor.x, monitor.y, monitor.width, monitor.height),
+      GetMonitorDpi(monitor));
+}
+
+// Gets current layout with context information from a list of monitors.
+std::vector<x11::RandRMonitorConfigWithContext> GetLayoutWithContext(
+    std::vector<x11::RandR::MonitorInfo>& monitors) {
+  std::vector<x11::RandRMonitorConfigWithContext> current_displays;
+  for (auto& monitor : monitors) {
+    // This implementation only supports resizing synthesized Monitors which
+    // automatically track their Outputs.
+    // TODO(crbug.com/40225767): Maybe support resizing manually-created
+    // monitors?
+    if (monitor.automatic) {
+      current_displays.emplace_back(ToRandRMonitorConfig(monitor), &monitor);
+    }
+  }
+  return current_displays;
+}
+
+x11::RandR::Output GetOutputFromContext(void* context) {
+  return reinterpret_cast<x11::RandR::MonitorInfo*>(context)->outputs[0];
+}
+
+int PixelsToMillimeters(int pixels, int dpi) {
+  DCHECK(dpi != 0);
+
+  // (pixels / dpi) is the length in inches. Multiplying by
+  // kMillimetersPerInch converts to mm. Multiplication is done first to
+  // avoid integer division.
+  return static_cast<int>(kMillimetersPerInch * pixels / dpi);
+}
+
+// Returns a physical size in mm that will work well with GNOME's
+// automatic scale-selection algorithm.
+gfx::Size CalculateSizeInMmForGnome(const gfx::Size& dimensions,
+                                    const gfx::Vector2d& dpi) {
+  int width_mm = PixelsToMillimeters(dimensions.width(), dpi.x());
+  int height_mm = PixelsToMillimeters(dimensions.height(), dpi.y());
+
+  // GNOME will, by default, choose an automatic scaling-factor based on the
+  // monitor's physical size (mm) and resolution (pixels). Some versions of
+  // GNOME have a problem when the computed DPI is close to 192. GNOME
+  // calculates the DPI using:
+  // dpi = size_pixels / (size_mm / 25.4)
+  // This is the reverse of PixelsToMillimeters() which should result in
+  // the same values as resolution.dpi() except for any floating-point
+  // truncation errors. GNOME will choose 2x scaling only if both the width and
+  // height DPIs are strictly greater than 192. The problem is that a user might
+  // connect from a 192dpi device and then GNOME's choice of scaling is randomly
+  // subject to rounding errors. If the calculation worked out at exactly
+  // 192dpi, the inequality test would fail and GNOME would choose 1x scaling.
+  // To address this, width_mm/height_mm are decreased slightly (increasing the
+  // calculated DPI) to favor 2x over 1x scaling for 192dpi devices.
+  width_mm--;
+  height_mm--;
+
+  // GNOME treats some pairs of width/height values as untrustworthy and will
+  // always choose 1x scaling for them. These values come from
+  // meta_monitor_has_aspect_as_size() in
+  // https://gitlab.gnome.org/GNOME/mutter/-/blob/main/src/backends/meta-monitor-manager.c
+  constexpr std::pair<int, int> kBadSizes[] = {
+      {16, 9}, {16, 10}, {160, 90}, {160, 100}, {1600, 900}, {1600, 1000}};
+  if (base::Contains(kBadSizes, std::pair(width_mm, height_mm))) {
+    width_mm--;
+  }
+  return {width_mm, height_mm};
+}
+
+x11::Atom GetX11Atom(x11::Connection* connection, const std::string& name) {
+  auto reply = connection->InternAtom({false, name}).Sync();
+  if (!reply) {
+    LOG(ERROR) << "Failed to intern atom " << name;
+    return x11::Atom::None;
+  }
+  return reply->atom;
+}
+
+void SetOutputPhysicalSizeInMM(x11::Connection* connection,
+                               x11::RandR::Output output,
+                               int width,
+                               int height) {
+  static const x11::Atom width_mm_atom = GetX11Atom(connection, "WIDTH_MM");
+  static const x11::Atom height_mm_atom = GetX11Atom(connection, "HEIGHT_MM");
+  if (width_mm_atom == x11::Atom::None || height_mm_atom == x11::Atom::None) {
+    return;
+  }
+
+  auto width_32 = static_cast<uint32_t>(width);
+  auto height_32 = static_cast<uint32_t>(height);
+
+  x11::RandR::ChangeOutputPropertyRequest request = {
+      .output = output,
+      .property = width_mm_atom,
+      .type = x11::Atom::INTEGER,
+      .format = 32,
+      .mode = x11::PropMode::Replace,
+      .num_units = 1,
+      .data = base::MakeRefCounted<base::RefCountedStaticMemory>(
+          base::U32ToNativeEndian(width_32)),
+  };
+  connection->randr().ChangeOutputProperty(request).Sync();
+
+  request.property = height_mm_atom;
+  request.data = base::MakeRefCounted<base::RefCountedStaticMemory>(
+      base::U32ToNativeEndian(height_32));
+  connection->randr().ChangeOutputProperty(request).Sync();
+}
+
+}  // namespace
+
+namespace x11 {
+
+DisplayLayoutDiff::DisplayLayoutDiff() = default;
+DisplayLayoutDiff::DisplayLayoutDiff(
+    x11::RandRMonitorLayout new_displays,
+    std::vector<RandRMonitorConfigWithContext> updated_displays,
+    std::vector<RandRMonitorConfigWithContext> removed_displays)
+    : new_displays(new_displays),
+      updated_displays(updated_displays),
+      removed_displays(removed_displays) {}
+DisplayLayoutDiff::~DisplayLayoutDiff() = default;
+DisplayLayoutDiff::DisplayLayoutDiff(const DisplayLayoutDiff&) = default;
+
+DisplayLayoutDiff CalculateDisplayLayoutDiff(
+    const std::vector<RandRMonitorConfigWithContext>& current_displays,
+    const x11::RandRMonitorLayout& new_layout) {
+  DisplayLayoutDiff diff;
+
+  // A list where the index is the index of |current_displays| and the value
+  // denotes whether the display is found in the new layout. Used to detect
+  // deletion of displays.
+  std::vector<bool> current_display_found(current_displays.size(), false);
+
+  for (const x11::RandRMonitorConfig& new_config : new_layout.configs) {
+    if (!new_config.id().has_value()) {
+      diff.new_displays.configs.push_back(new_config);
+      continue;
+    }
+    auto current_display_it = base::ranges::find(
+        current_displays, new_config.id(),
+        [](const auto& display) { return display.config.id(); });
+    if (current_display_it == current_displays.end()) {
+      LOG(ERROR) << "Ignoring unknown screen_id " << *new_config.id();
+      continue;
+    }
+    current_display_found[current_display_it - current_displays.begin()] = true;
+    if (new_config.rect() != current_display_it->config.rect() ||
+        new_config.dpi() != current_display_it->config.dpi()) {
+      VLOG(1) << "Video layout for screen id " << *new_config.id()
+              << " has been changed.";
+      diff.updated_displays.emplace_back(new_config,
+                                         current_display_it->context);
+    } else {
+      VLOG(1) << "Video layout for screen id " << *new_config.id()
+              << " has not been changed.";
+    }
+  }
+
+  for (size_t i = 0u; i < current_display_found.size(); i++) {
+    if (!current_display_found[i]) {
+      diff.removed_displays.push_back(current_displays[i]);
+    }
+  }
+  return diff;
+}
+
+ScreenResources::ScreenResources() = default;
+
+ScreenResources::~ScreenResources() = default;
+
+bool ScreenResources::Refresh(x11::RandR* randr, x11::Window window) {
+  resources_ = nullptr;
+  if (auto response = randr->GetScreenResourcesCurrent({window}).Sync()) {
+    resources_ = std::move(response.reply);
+  }
+  return resources_ != nullptr;
+}
+
+x11::RandR::Mode ScreenResources::GetIdForMode(const std::string& name) {
+  CHECK(resources_);
+  base::span<const char> names =
+      base::as_chars(base::span<uint8_t>(resources_->names));
+  uint16_t idx = 0;
+  for (const auto& mode_info : resources_->modes) {
+    std::string mode_name(names.subspan(idx, mode_info.name_len).data(),
+                          mode_info.name_len);
+    idx += mode_info.name_len;
+    if (name == mode_name) {
+      return static_cast<x11::RandR::Mode>(mode_info.id);
+    }
+  }
+  return kInvalidMode;
+}
+
+x11::RandR::GetScreenResourcesCurrentReply* ScreenResources::get() {
+  return resources_.get();
+}
+
+RandRMonitorConfig::RandRMonitorConfig(std::optional<ScreenId> id,
+                                       gfx::Rect rect,
+                                       gfx::Vector2d dpi)
+    : id_(id), rect_(rect), dpi_(dpi) {}
+bool RandRMonitorConfig::operator==(const RandRMonitorConfig& rhs) const =
+    default;
+RandRMonitorConfig::RandRMonitorConfig(const RandRMonitorConfig& other) =
+    default;
+RandRMonitorConfig& RandRMonitorConfig::operator=(
+    const RandRMonitorConfig& other) = default;
+
+RandRMonitorLayout::RandRMonitorLayout() = default;
+RandRMonitorLayout::RandRMonitorLayout(const RandRMonitorLayout&) = default;
+RandRMonitorLayout::RandRMonitorLayout(
+    const std::vector<RandRMonitorConfig> configs)
+    : configs(configs) {}
+RandRMonitorLayout& RandRMonitorLayout::operator=(const RandRMonitorLayout&) =
+    default;
+RandRMonitorLayout::~RandRMonitorLayout() = default;
+bool RandRMonitorLayout::operator==(const RandRMonitorLayout& rhs) const =
+    default;
+
+RandROutputManager::RandROutputManager(std::string output_name_prefix,
+                                       uint32_t default_mode_dot_clock)
+    : connection_(x11::Connection::Get()),
+      randr_(&connection_->randr()),
+      root_(connection_->default_screen().root),
+      output_name_prefix_(output_name_prefix),
+      default_mode_dot_clock_(default_mode_dot_clock) {
+  has_randr_ = randr_->present();
+}
+RandROutputManager::~RandROutputManager() = default;
+
+bool RandROutputManager::TryGetCurrentMonitors(
+    std::vector<x11::RandR::MonitorInfo>& list) {
+  if (!has_randr_) {
+    return false;
+  }
+
+  if (!resources_.Refresh(randr_, root_)) {
+    return false;
+  }
+
+  auto reply = randr_->GetMonitors({root_}).Sync();
+  if (!reply) {
+    return false;
+  }
+  std::copy(reply->monitors.begin(), reply->monitors.end(),
+            std::back_inserter(list));
+  return true;
+}
+
+RandRMonitorLayout RandROutputManager::GetLayout() {
+  RandRMonitorLayout result;
+  std::vector<x11::RandR::MonitorInfo> monitors;
+  if (!TryGetCurrentMonitors(monitors)) {
+    return RandRMonitorLayout();
+  }
+  for (const auto& config_context : GetLayoutWithContext(monitors)) {
+    result.configs.emplace_back(config_context.config);
+  }
+  return result;
+}
+
+void RandROutputManager::SetLayout(const RandRMonitorLayout& layout) {
+  if (!has_randr_) {
+    return;
+  }
+  // Grab the X server while we're changing the display resolution. This ensures
+  // that the display configuration doesn't change under our feet.
+  ScopedXGrabServer grabber(connection_);
+
+  std::vector<x11::RandR::MonitorInfo> monitors;
+  if (!TryGetCurrentMonitors(monitors)) {
+    return;
+  }
+  std::vector<RandRMonitorConfigWithContext> current_displays =
+      GetLayoutWithContext(monitors);
+
+  // TODO(yuweih): Verify that the layout is valid, e.g. no overlaps or gaps
+  // between displays.
+  DisplayLayoutDiff diff = CalculateDisplayLayoutDiff(current_displays, layout);
+
+  X11CrtcResizer resizer(resources_.get(), connection_);
+  resizer.FetchActiveCrtcs();
+
+  const std::vector<RandRMonitorConfig>& new_layouts =
+      diff.new_displays.configs;
+  // Add displays
+  if (!new_layouts.empty()) {
+    auto outputs = GetDisabledOutputs();
+    size_t i = 0u;
+    for (; i < outputs.size() && i < new_layouts.size(); i++) {
+      auto& output_pair = outputs[i];
+      auto output = output_pair.first;
+      auto& output_info = output_pair.second;
+      // For the video-dummy driver, the size of |crtcs| is exactly 1 and is
+      // different for each Output. In general, this is not true for other
+      // video-drivers, and the lists can overlap.
+      // TODO(yuweih): Consider making CRTC allocation smarter so it works with
+      // non-video-dummy drivers.
+      if (output_info.crtcs.empty()) {
+        LOG(ERROR) << "No available CRTC found associated with "
+                   << reinterpret_cast<char*>(output_info.name.data());
+        continue;
+      }
+      auto crtc = output_info.crtcs.front();
+      auto new_layout = new_layouts[i];
+      // Note that this has a weird behavior in GNOME, such that, if |output| is
+      // "disconnected", creating the mode somehow resizes all existing displays
+      // to 1024x768. Once the output is successfully enabled, it will remain
+      // "connected" and will no longer have the problem. The problem doesn't
+      // occur on XFCE or Cinnamon.
+      // TODO(yuweih): See if this is fixable, or at least implement some
+      // workaround, such as re-applying the layout.
+      auto mode = UpdateMode(output, new_layout.rect().width(),
+                             new_layout.rect().height());
+      if (mode == kInvalidMode) {
+        LOG(ERROR) << "Failed to create new mode.";
+        continue;
+      }
+      resizer.AddActiveCrtc(crtc, mode, {output}, new_layout.rect());
+      VLOG(0) << "Added display with crtc: " << base::to_underlying(crtc)
+              << ", output: " << base::to_underlying(output);
+    }
+    if (i < diff.new_displays.configs.size()) {
+      LOG(WARNING) << "Failed to create "
+                   << (diff.new_displays.configs.size() - i)
+                   << " display(s) due to insufficient resources.";
+    }
+  }
+
+  // Update displays
+  for (const auto& updated_display : diff.updated_displays) {
+    auto updated_layout = updated_display.config;
+    auto output = GetOutputFromContext(updated_display.context);
+    auto crtc = resizer.GetCrtcForOutput(output);
+    if (crtc == kDisabledCrtc) {
+      // This is not expected to happen. Disabled Outputs are not expected to
+      // have any Monitor, but |output| was found in the RRGetMonitors response,
+      // so it should have a CRTC attached.
+      LOG(ERROR) << "No CRTC found for output: " << base::to_underlying(output);
+      continue;
+    }
+    resizer.DisableCrtc(crtc);
+    auto mode = UpdateMode(output, updated_layout.rect().width(),
+                           updated_layout.rect().height());
+    if (mode == kInvalidMode) {
+      LOG(ERROR) << "Failed to create new mode.";
+      continue;
+    }
+    resizer.UpdateActiveCrtc(crtc, mode, updated_layout.rect());
+    VLOG(0) << "Updated display with screen ID: "
+            << updated_display.config.id().value_or(-1);
+  }
+
+  // Remove displays
+  for (const auto& removed_display : diff.removed_displays) {
+    auto output = GetOutputFromContext(removed_display.context);
+    auto crtc = resizer.GetCrtcForOutput(output);
+    if (crtc == kDisabledCrtc) {
+      LOG(ERROR) << "No CRTC found for output: " << base::to_underlying(output);
+      continue;
+    }
+    resizer.DisableCrtc(crtc);
+    resizer.RemoveActiveCrtc(crtc);
+    DeleteMode(output, GetModeNameForOutput(output));
+    VLOG(0) << "Removed display with screen ID: "
+            << removed_display.config.id().value_or(-1);
+  }
+
+  resizer.NormalizeCrtcs();
+  resizer.UpdateRootWindow(root_);
+}
+
+x11::RandR::Mode RandROutputManager::UpdateMode(x11::RandR::Output output,
+                                                int width,
+                                                int height) {
+  std::string mode_name = GetModeNameForOutput(output);
+  DeleteMode(output, mode_name);
+
+  // Set some clock values so that the computed refresh-rate is a realistic
+  // number:
+  // 60Hz = dot_clock / (htotal * vtotal).
+  // This allows GNOME's Display Settings tool to apply new settings for
+  // resolution/scaling - see crbug.com/1374488.
+  x11::RandR::ModeInfo mode;
+  mode.width = width;
+  mode.height = height;
+  mode.dot_clock = default_mode_dot_clock_;
+  mode.htotal = 1000;
+  mode.vtotal = 1000;
+  mode.name_len = mode_name.size();
+  if (auto reply =
+          randr_->CreateMode({root_, mode, mode_name.c_str()}).Sync()) {
+    randr_->AddOutputMode({
+        output,
+        reply->mode,
+    });
+    return reply->mode;
+  }
+  return kInvalidMode;
+}
+
+void RandROutputManager::DeleteMode(x11::RandR::Output output,
+                                    const std::string& name) {
+  x11::RandR::Mode mode_id = resources_.GetIdForMode(name);
+  if (mode_id != kInvalidMode) {
+    randr_->DeleteOutputMode({output, mode_id});
+    randr_->DestroyMode({mode_id});
+    resources_.Refresh(randr_, root_);
+  }
+}
+
+void RandROutputManager::SetResolutionForOutput(x11::RandR::Output output,
+                                                const gfx::Size& dimensions,
+                                                const gfx::Vector2d& dpi) {
+  if (!resources_.Refresh(randr_, root_)) {
+    LOG(ERROR) << "Failed to Refresh RandR resources.";
+  }
+  x11::X11CrtcResizer resizer(resources_.get(), connection_);
+
+  resizer.FetchActiveCrtcs();
+  auto crtc = resizer.GetCrtcForOutput(output);
+
+  if (crtc == kDisabledCrtc) {
+    // This is not expected to happen. Disabled Outputs are not expected to
+    // have any Monitor, but |output| was found in the RRGetMonitors response,
+    // so it should have a CRTC attached.
+    LOG(ERROR) << "No CRTC found for output: " << base::to_underlying(output);
+    return;
+  }
+
+  // Disable the output now, so that the old mode can be deleted and the new
+  // mode created and added to the output's available modes. The previous size
+  // and offsets will be stored in |resizer|.
+  resizer.DisableCrtc(crtc);
+
+  auto mode = UpdateMode(output, dimensions.width(), dimensions.height());
+  if (mode == kInvalidMode) {
+    // The CRTC is disabled, but there's no easy way to recover it here
+    // (the mode it was attached to has gone).
+    LOG(ERROR) << "Failed to create new mode.";
+    return;
+  }
+
+  // Update |active_crtcs_| with new sizes and offsets.
+  resizer.UpdateActiveCrtcs(crtc, mode, dimensions);
+  resizer.UpdateRootWindow(root_);
+
+  gfx::Size size_mm = CalculateSizeInMmForGnome(dimensions, dpi);
+  int width_mm = size_mm.width();
+  int height_mm = size_mm.height();
+  VLOG(0) << "Setting physical size in mm: " << width_mm << "x" << height_mm;
+  SetOutputPhysicalSizeInMM(connection_, output, width_mm, height_mm);
+}
+
+RandROutputManager::OutputInfoList RandROutputManager::GetDisabledOutputs() {
+  OutputInfoList disabled_outputs;
+  for (x11::RandR::Output output : resources_.get()->outputs) {
+    auto reply = randr_
+                     ->GetOutputInfo({.output = output,
+                                      .config_timestamp =
+                                          resources_.get()->config_timestamp})
+                     .Sync();
+    if (!reply) {
+      continue;
+    }
+    if (reply->crtc == kDisabledCrtc) {
+      disabled_outputs.emplace_back(output, std::move(*reply.reply));
+    }
+  }
+  return disabled_outputs;
+}
+
+std::string RandROutputManager::GetModeNameForOutput(
+    x11::RandR::Output output) {
+  // The name of the mode representing the current client view resolution. This
+  // must be unique per Output, so that Outputs can be resized independently.
+  return base::StringPrintf("%s%i", output_name_prefix_.c_str(),
+                            base::to_underlying(output));
+}
+
+}  // namespace x11
diff --git a/ui/gfx/x/randr_output_manager.h b/ui/gfx/x/randr_output_manager.h
new file mode 100644
index 0000000..0ac2647
--- /dev/null
+++ b/ui/gfx/x/randr_output_manager.h
@@ -0,0 +1,156 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_X_RANDR_OUTPUT_MANAGER_H_
+#define UI_GFX_X_RANDR_OUTPUT_MANAGER_H_
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/component_export.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/x/randr.h"
+
+namespace x11 {
+
+// Wrapper class for the XRRScreenResources struct.
+class COMPONENT_EXPORT(X11) ScreenResources {
+ public:
+  ScreenResources();
+  ~ScreenResources();
+
+  bool Refresh(x11::RandR* randr, x11::Window window);
+
+  x11::RandR::Mode GetIdForMode(const std::string& name);
+
+  x11::RandR::GetScreenResourcesCurrentReply* get();
+
+ private:
+  std::unique_ptr<x11::RandR::GetScreenResourcesCurrentReply> resources_;
+};
+
+// Encapsulates basic configuration properties for a single RandR monitor.
+class COMPONENT_EXPORT(X11) RandRMonitorConfig {
+ public:
+  using ScreenId = int64_t;
+  RandRMonitorConfig(std::optional<ScreenId> id,
+                     gfx::Rect rect,
+                     gfx::Vector2d dpi);
+  RandRMonitorConfig(const RandRMonitorConfig& other);
+  RandRMonitorConfig& operator=(const RandRMonitorConfig& other);
+  bool operator==(const RandRMonitorConfig& rhs) const;
+
+  std::optional<ScreenId> id() const { return id_; }
+
+  const gfx::Rect& rect() const { return rect_; }
+  const gfx::Vector2d& dpi() const { return dpi_; }
+
+ private:
+  // An opaque ID used to identify this monitor. Unset when the ID is unknown,
+  // for example, when a caller is setting a new layout and the screen ID
+  // does not exist yet.
+  std::optional<ScreenId> id_;
+  gfx::Rect rect_;
+  gfx::Vector2d dpi_;
+};
+
+// Encapsulates a set of monitors to represent an entire screen layout.
+struct COMPONENT_EXPORT(X11) RandRMonitorLayout {
+  RandRMonitorLayout();
+  RandRMonitorLayout(const RandRMonitorLayout&);
+  explicit RandRMonitorLayout(const std::vector<RandRMonitorConfig> configs);
+  RandRMonitorLayout& operator=(const RandRMonitorLayout&);
+  ~RandRMonitorLayout();
+  bool operator==(const RandRMonitorLayout& rhs) const;
+
+  std::vector<RandRMonitorConfig> configs;
+  std::optional<int64_t> primary_screen_id;
+};
+
+// Attaches an arbitrary pointer to a monitor config for internal tracking
+// purposes.
+struct COMPONENT_EXPORT(X11) RandRMonitorConfigWithContext {
+  x11::RandRMonitorConfig config;
+  raw_ptr<void> context;
+};
+
+// Structure to hold data which describes changes between two layouts.
+struct COMPONENT_EXPORT(X11) DisplayLayoutDiff {
+  DisplayLayoutDiff();
+  DisplayLayoutDiff(
+      x11::RandRMonitorLayout new_displays,
+      std::vector<RandRMonitorConfigWithContext> updated_displays,
+      std::vector<RandRMonitorConfigWithContext> removed_displays);
+  DisplayLayoutDiff(const DisplayLayoutDiff&);
+  ~DisplayLayoutDiff();
+  x11::RandRMonitorLayout new_displays;
+  std::vector<RandRMonitorConfigWithContext> updated_displays;
+  std::vector<RandRMonitorConfigWithContext> removed_displays;
+};
+
+// Calculates the difference between the current display layout and the new
+// display layout. Displays are matched using the screen ID.
+COMPONENT_EXPORT(X11)
+DisplayLayoutDiff CalculateDisplayLayoutDiff(
+    const std::vector<RandRMonitorConfigWithContext>& current_displays,
+    const x11::RandRMonitorLayout& new_layout);
+
+// Manages modes and layout of RandR outputs.
+class COMPONENT_EXPORT(X11) RandROutputManager final {
+ public:
+  // `output_name_prefix` is used when creating new RandR outputs. Optionally
+  // override the default mode dot clock with `default_mode_dot_clock`.
+  explicit RandROutputManager(
+      std::string output_name_prefix,
+      uint32_t default_mode_dot_clock = 60 * 1e6 /* Realistic default */);
+  ~RandROutputManager();
+
+  // Attempts to get the current list of XRandR monitors from the current
+  // connection. Returns true on success in which case `list` is populated with
+  // the monitors. Returns false otherwise.
+  bool TryGetCurrentMonitors(std::vector<x11::RandR::MonitorInfo>& list);
+
+  // Obtains the current RandR layout.
+  RandRMonitorLayout GetLayout();
+  // Adjusts outputs to match the specified layout.
+  void SetLayout(const RandRMonitorLayout& layout);
+
+  // Removes the existing mode from the output and replaces it with the new
+  // size. Returns the new mode ID, or None (0) on failure.
+  x11::RandR::Mode UpdateMode(x11::RandR::Output output, int width, int height);
+  // Remove the specified mode from the output, and delete it. If the mode is in
+  // use, it is not deleted.
+  // |name| should be set to GetModeNameForOutput(output). The parameter is to
+  // avoid creating the mode name twice.
+  void DeleteMode(x11::RandR::Output output, const std::string& name);
+
+  // Add a mode matching the specified resolution and switch to it.
+  void SetResolutionForOutput(x11::RandR::Output output,
+                              const gfx::Size& dimensions,
+                              const gfx::Vector2d& dpi);
+
+ private:
+  using OutputInfoList = std::vector<
+      std::pair<x11::RandR::Output, x11::RandR::GetOutputInfoReply>>;
+
+  OutputInfoList GetDisabledOutputs();
+
+  std::string GetModeNameForOutput(x11::RandR::Output output);
+
+  raw_ptr<x11::Connection> connection_ = nullptr;
+  const raw_ptr<x11::RandR> randr_ = nullptr;
+  x11::Window root_;
+  ScreenResources resources_;
+  bool has_randr_;
+  std::string output_name_prefix_;
+  const uint32_t default_mode_dot_clock_;
+};
+
+}  // namespace x11
+
+#endif  // UI_GFX_X_RANDR_OUTPUT_MANAGER_H_
diff --git a/ui/gfx/x/randr_output_manager_unittest.cc b/ui/gfx/x/randr_output_manager_unittest.cc
new file mode 100644
index 0000000..f89f9c9a
--- /dev/null
+++ b/ui/gfx/x/randr_output_manager_unittest.cc
@@ -0,0 +1,79 @@
+#include "ui/gfx/x/randr_output_manager.h"
+
+#include <optional>
+#include <vector>
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+namespace {
+
+void* ContextOf(int i) {
+  return reinterpret_cast<void*>(i);
+}
+
+}  // namespace
+
+namespace x11 {
+
+std::ostream& operator<<(std::ostream& os, const RandRMonitorConfig& layout) {
+  if (layout.id().has_value()) {
+    os << *layout.id() << ": ";
+  } else {
+    os << "(no screen id): ";
+  }
+  return os << layout.rect().ToString() << " @ " << layout.dpi().x() << "x"
+            << layout.dpi().y();
+}
+
+std::ostream& operator<<(
+    std::ostream& os,
+    const RandRMonitorConfigWithContext& layout_with_context) {
+  return os << "{config=" << layout_with_context.config
+            << ", context=" << layout_with_context.context << "}";
+}
+
+bool operator==(const RandRMonitorConfigWithContext& a,
+                const RandRMonitorConfigWithContext& b) {
+  return a.config == b.config && a.context == b.context;
+}
+
+TEST(RandrOutputManagerTest, CalculateDisplayLayoutDiff) {
+  std::vector<RandRMonitorConfigWithContext> current_displays = {
+      {{123, gfx::Rect(0, 0, 1230, 1230), gfx::Vector2d(96, 96)}, ContextOf(1)},
+      {{234, gfx::Rect(1230, 0, 2340, 2340), gfx::Vector2d(192, 192)},
+       ContextOf(2)},
+      {{345, gfx::Rect(0, 1230, 3450, 3450), gfx::Vector2d(96, 96)},
+       ContextOf(3)}};
+  x11::RandRMonitorLayout new_layout(
+      {// Updated.
+       {234, gfx::Rect(3450, 1230, 2340, 2000), gfx::Vector2d(100, 96)},
+       // Unchanged.
+       {345, gfx::Rect(0, 1230, 3450, 3450), gfx::Vector2d(96, 96)},
+       // New.
+       {{}, gfx::Rect(3450, 3450, 4560, 4560), gfx::Vector2d(192, 192)}});
+  auto diff = CalculateDisplayLayoutDiff(current_displays, new_layout);
+
+  x11::RandRMonitorLayout expected_new_displays;
+  expected_new_displays.configs.push_back(RandRMonitorConfig(
+      {}, gfx::Rect(3450, 3450, 4560, 4560), gfx::Vector2d(192, 192)));
+  EXPECT_EQ(diff.new_displays, expected_new_displays);
+
+  std::vector<RandRMonitorConfigWithContext> expected_updated_displays = {
+      RandRMonitorConfigWithContext(
+          RandRMonitorConfig(234, gfx::Rect(3450, 1230, 2340, 2000),
+                             gfx::Vector2d(100, 96)),
+          ContextOf(2))};
+  EXPECT_EQ(diff.updated_displays, expected_updated_displays);
+
+  std::vector<RandRMonitorConfigWithContext> expected_removed_displays = {
+      RandRMonitorConfigWithContext(
+          RandRMonitorConfig(123, gfx::Rect(0, 0, 1230, 1230),
+                             gfx::Vector2d(96, 96)),
+          ContextOf(1))};
+  EXPECT_EQ(diff.removed_displays, expected_removed_displays);
+}
+
+}  // namespace x11
diff --git a/remoting/host/x11_crtc_resizer.cc b/ui/gfx/x/x11_crtc_resizer.cc
similarity index 89%
rename from remoting/host/x11_crtc_resizer.cc
rename to ui/gfx/x/x11_crtc_resizer.cc
index 309691dcb..af7dfbb4 100644
--- a/remoting/host/x11_crtc_resizer.cc
+++ b/ui/gfx/x/x11_crtc_resizer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "remoting/host/x11_crtc_resizer.h"
+#include "ui/gfx/x/x11_crtc_resizer.h"
 
 #include <iterator>
 #include <utility>
@@ -14,8 +14,8 @@
 #include "base/logging.h"
 #include "base/ranges/algorithm.h"
 #include "base/stl_util.h"
-#include "ui/base/x/x11_util.h"
 #include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/x/connection.h"
 #include "ui/gfx/x/future.h"
 
 namespace {
@@ -23,9 +23,23 @@
 constexpr auto kInvalidMode = static_cast<x11::RandR::Mode>(0);
 constexpr auto kDisabledCrtc = static_cast<x11::RandR::Crtc>(0);
 
+// TODO(jamiewalch): Use the correct DPI for the mode: http://crbug.com/172405.
+const int kDefaultDPI = 96;
+
+int PixelsToMillimeters(int pixels, int dpi) {
+  DCHECK(dpi != 0);
+
+  const double kMillimetersPerInch = 25.4;
+
+  // (pixels / dpi) is the length in inches. Multiplying by
+  // kMillimetersPerInch converts to mm. Multiplication is done first to
+  // avoid integer division.
+  return static_cast<int>(kMillimetersPerInch * pixels / dpi);
+}
+
 }  // namespace
 
-namespace remoting {
+namespace x11 {
 
 X11CrtcResizer::CrtcInfo::CrtcInfo() = default;
 X11CrtcResizer::CrtcInfo::CrtcInfo(
@@ -300,6 +314,33 @@
   updated_crtcs_.clear();
 }
 
+void X11CrtcResizer::UpdateRootWindow(x11::Window root) {
+  // Disable any CRTCs that have been changed, so that the root window can be
+  // safely resized to the bounding-box of the new CRTCs.
+  // This is non-optimal: the only CRTCs that need disabling are those whose
+  // original rectangles don't fit into the new root window - they are the ones
+  // that would prevent resizing the root window. But figuring these out would
+  // involve keeping track of all the original rectangles as well as the new
+  // ones. So, to keep the implementation simple (and working for any arbitrary
+  // layout algorithm), all changed CRTCs are disabled here.
+  DisableChangedCrtcs();
+
+  // Get the dimensions to resize the root window to.
+  auto dimensions = GetBoundingBox();
+
+  // TODO(lambroslambrou): Use the DPI from client size information.
+  uint32_t width_mm = PixelsToMillimeters(dimensions.width(), kDefaultDPI);
+  uint32_t height_mm = PixelsToMillimeters(dimensions.height(), kDefaultDPI);
+  randr_->SetScreenSize({root, static_cast<uint16_t>(dimensions.width()),
+                         static_cast<uint16_t>(dimensions.height()), width_mm,
+                         height_mm});
+
+  MoveApplicationWindows();
+
+  // Apply the new CRTCs, which will re-enable any that were disabled.
+  ApplyActiveCrtcs();
+}
+
 void X11CrtcResizer::SetCrtcsForTest(
     std::vector<x11::RandR::GetCrtcInfoReply> crtcs) {
   int id = 1;
@@ -509,4 +550,4 @@
   return x11::Window::None;
 }
 
-}  // namespace remoting
+}  // namespace x11
diff --git a/remoting/host/x11_crtc_resizer.h b/ui/gfx/x/x11_crtc_resizer.h
similarity index 96%
rename from remoting/host/x11_crtc_resizer.h
rename to ui/gfx/x/x11_crtc_resizer.h
index 5069948..2ea38b6 100644
--- a/remoting/host/x11_crtc_resizer.h
+++ b/ui/gfx/x/x11_crtc_resizer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef REMOTING_HOST_X11_CRTC_RESIZER_H_
-#define REMOTING_HOST_X11_CRTC_RESIZER_H_
+#ifndef UI_GFX_X_X11_CRTC_RESIZER_H_
+#define UI_GFX_X_X11_CRTC_RESIZER_H_
 
 #include <vector>
 
@@ -13,11 +13,11 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/x/randr.h"
 
-namespace remoting {
+namespace x11 {
 
 // Helper class for DesktopResizerX11 which handles much of the logic
 // for arranging and resizing a set of active CRTCs.
-class X11CrtcResizer {
+class COMPONENT_EXPORT(X11) X11CrtcResizer {
  public:
   X11CrtcResizer(x11::RandR::GetScreenResourcesCurrentReply* resources,
                  x11::Connection* connection);
@@ -96,6 +96,10 @@
   // outputs/CRTCs that were disabled.
   void ApplyActiveCrtcs();
 
+  // Updates the root window using the bounding box of the CRTCs, then
+  // re-activate all CRTCs.
+  void UpdateRootWindow(x11::Window root);
+
   // Initializes the active CRTCs from a list of fake X11 replies. As the
   // replies don't include the CRTC IDs, these will be created sequentially
   // as 1, 2, ...
@@ -217,6 +221,6 @@
   x11::Atom wm_state_atom_;
 };
 
-}  // namespace remoting
+}  // namespace x11
 
-#endif  // REMOTING_HOST_X11_CRTC_RESIZER_H_
+#endif  // UI_GFX_X_X11_CRTC_RESIZER_H_
diff --git a/remoting/host/x11_crtc_resizer_unittest.cc b/ui/gfx/x/x11_crtc_resizer_unittest.cc
similarity index 96%
rename from remoting/host/x11_crtc_resizer_unittest.cc
rename to ui/gfx/x/x11_crtc_resizer_unittest.cc
index 5398e90d..7e42774 100644
--- a/remoting/host/x11_crtc_resizer_unittest.cc
+++ b/ui/gfx/x/x11_crtc_resizer_unittest.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "remoting/host/x11_crtc_resizer.h"
+#include "ui/gfx/x/x11_crtc_resizer.h"
 
-#include "inttypes.h"
+#include <inttypes.h>
 
 #include <string>
 
@@ -31,7 +31,7 @@
 
 }  // namespace
 
-namespace remoting {
+namespace x11 {
 
 TEST(X11CrtcResizerTest, ShiftToMakeRoomHorizontally) {
   X11CrtcResizer resizer(nullptr, nullptr);
@@ -121,4 +121,4 @@
   ExpectEqual(result[1], gfx::Rect(150, 100, 100, 100));
 }
 
-}  // namespace remoting
+}  // namespace x11
diff --git a/ui/latency/latency_info.cc b/ui/latency/latency_info.cc
index 14717f6f..c9f11e6 100644
--- a/ui/latency/latency_info.cc
+++ b/ui/latency/latency_info.cc
@@ -15,22 +15,22 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/trace_event/trace_event.h"
+#include "base/tracing/protos/chrome_track_event.pbzero.h"
 #include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
 #include "services/tracing/public/cpp/perfetto/macros.h"
-#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_latency_info.pbzero.h"
 
 namespace {
 
-using perfetto::protos::pbzero::ChromeLatencyInfo;
 using perfetto::protos::pbzero::TrackEvent;
 
 const size_t kMaxLatencyInfoNumber = 100;
 
-ChromeLatencyInfo::LatencyComponentType GetComponentProtoEnum(
-    ui::LatencyComponentType type) {
-#define CASE_TYPE(t)      \
-  case ui::t##_COMPONENT: \
-    return ChromeLatencyInfo::COMPONENT_##t
+perfetto::protos::pbzero::ChromeLatencyInfo2::LatencyComponentType
+GetComponentProtoEnum(ui::LatencyComponentType type) {
+#define CASE_TYPE(t)                                      \
+  case ui::t##_COMPONENT:                                 \
+    return perfetto::protos::pbzero::ChromeLatencyInfo2:: \
+        LatencyComponentType::COMPONENT_##t
   switch (type) {
     CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_RWH);
     CASE_TYPE(INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL);
@@ -46,7 +46,8 @@
     CASE_TYPE(INPUT_EVENT_LATENCY_FRAME_SWAP);
     default:
       NOTREACHED_IN_MIGRATION() << "Unhandled LatencyComponentType: " << type;
-      return ChromeLatencyInfo::COMPONENT_UNSPECIFIED;
+      return perfetto::protos::pbzero::ChromeLatencyInfo2::
+          LatencyComponentType::COMPONENT_UNSPECIFIED;
   }
 #undef CASE_TYPE
 }
@@ -109,8 +110,11 @@
     TRACE_EVENT(
         "input,benchmark,latencyInfo", "LatencyInfo.Flow",
         [&latency, &step](perfetto::EventContext ctx) {
-          ChromeLatencyInfo* info = ctx.event()->set_chrome_latency_info();
-          info->set_step(step);
+          auto* info = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                           ->set_chrome_latency_info();
+          info->set_step(
+              (perfetto::protos::pbzero::
+                   perfetto_pbzero_enum_ChromeLatencyInfo2::Step)step);
           info->set_trace_id(latency.trace_id());
           tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_INOUT,
                                  latency.trace_id());
@@ -118,6 +122,17 @@
   }
 }
 
+void LatencyInfo::FillTraceEvent(const LatencyInfo& latency,
+                                 const perfetto::EventContext& ctx) {
+  perfetto::protos::pbzero::ChromeLatencyInfo* info =
+      ctx.event()->set_chrome_latency_info();
+  info->set_trace_id(latency.trace_id());
+
+  tracing::FillFlowEvent(
+      ctx, perfetto::protos::pbzero::TrackEvent::LegacyEvent::FLOW_OUT,
+      latency.trace_id());
+}
+
 void LatencyInfo::AddNewLatencyFrom(const LatencyInfo& other) {
   // Don't clobber an existing trace_id_.
   if (trace_id_ == -1) {
@@ -191,11 +206,12 @@
 
     TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
                 [this](perfetto::EventContext ctx) {
-                  ChromeLatencyInfo* info =
-                      ctx.event()->set_chrome_latency_info();
+                  auto* info =
+                      ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                          ->set_chrome_latency_info();
                   info->set_trace_id(trace_id_);
-                  tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_OUT,
-                                         trace_id_);
+                  tracing::FillFlowEvent(
+                      ctx, TrackEvent::LegacyEvent::FLOW_INOUT, trace_id_);
                 });
   }
 
@@ -224,10 +240,10 @@
     TRACE_EVENT_END(
         kTraceCategoriesForAsyncEvents, perfetto::Track::Global(trace_id_),
         gpu_swap_end_timestamp, [this](perfetto::EventContext ctx) {
-          ChromeLatencyInfo* info = ctx.event()->set_chrome_latency_info();
+          auto* info = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                           ->set_chrome_latency_info();
           for (const auto& lc : latency_components_) {
-            ChromeLatencyInfo::ComponentInfo* component =
-                info->add_component_info();
+            auto* component = info->add_component_info();
 
             component->set_component_type(GetComponentProtoEnum(lc.first));
             component->set_time_us(lc.second.since_origin().InMicroseconds());
@@ -247,8 +263,9 @@
 
   TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
               [this](perfetto::EventContext ctx) {
-                ChromeLatencyInfo* info =
-                    ctx.event()->set_chrome_latency_info();
+                auto* info =
+                    ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
+                        ->set_chrome_latency_info();
                 info->set_trace_id(trace_id_);
                 tracing::FillFlowEvent(ctx, TrackEvent::LegacyEvent::FLOW_IN,
                                        trace_id_);
diff --git a/ui/latency/latency_info.h b/ui/latency/latency_info.h
index 3ba180c3..31c5d51 100644
--- a/ui/latency/latency_info.h
+++ b/ui/latency/latency_info.h
@@ -11,6 +11,7 @@
 #include "base/time/time.h"
 #include "build/blink_buildflags.h"
 #include "build/build_config.h"
+#include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
 #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_latency_info.pbzero.h"
 
 #if BUILDFLAG(USE_BLINK)
@@ -103,6 +104,11 @@
       const std::vector<LatencyInfo>& latency_info,
       perfetto::protos::pbzero::ChromeLatencyInfo::Step step);
 
+  // Populates fields for a `LatencyInfo.Flow` event with `ctx`
+  // from `latency`.
+  static void FillTraceEvent(const LatencyInfo& latency,
+                             const perfetto::EventContext& ctx);
+
   // Add timestamps for components that are in |other| but not in |this|.
   void AddNewLatencyFrom(const LatencyInfo& other);
 
diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc
index 3c51f14..6bd202d 100644
--- a/ui/views/controls/native/native_view_host.cc
+++ b/ui/views/controls/native/native_view_host.cc
@@ -4,7 +4,6 @@
 
 #include "ui/views/controls/native/native_view_host.h"
 
-#include <memory>
 #include <utility>
 
 #include "base/check.h"
@@ -74,11 +73,6 @@
   return native_wrapper_->SetCornerRadii(corner_radii);
 }
 
-bool NativeViewHost::SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) {
-  DCHECK(native_wrapper_);
-  return native_wrapper_->SetCustomMask(std::move(mask));
-}
-
 void NativeViewHost::SetHitTestTopInset(int top_inset) {
   native_wrapper_->SetHitTestTopInset(top_inset);
 }
diff --git a/ui/views/controls/native/native_view_host.h b/ui/views/controls/native/native_view_host.h
index 08b4014..172639d 100644
--- a/ui/views/controls/native/native_view_host.h
+++ b/ui/views/controls/native/native_view_host.h
@@ -63,13 +63,6 @@
   // SetCustomMask internally.
   bool SetCornerRadii(const gfx::RoundedCornersF& corner_radii);
 
-  // Sets the custom layer mask for clipping gfx::NativeView. Returns true on
-  // success or false if the platform doesn't support the operation.
-  // NB: This does not interact nicely with fast_resize.
-  // TODO(tluk): This is currently only being used to apply rounded corners in
-  // ash code. Migrate existing use to SetCornerRadii().
-  bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask);
-
   // Sets the height of the top region where the gfx::NativeView shouldn't be
   // targeted. This will be used when another view is covering there
   // temporarily, like the immersive fullscreen mode of ChromeOS.
diff --git a/ui/views/controls/native/native_view_host_aura.cc b/ui/views/controls/native/native_view_host_aura.cc
index 477f5666..9fed2509 100644
--- a/ui/views/controls/native/native_view_host_aura.cc
+++ b/ui/views/controls/native/native_view_host_aura.cc
@@ -103,7 +103,6 @@
   original_transform_ = host_->native_view()->transform();
   original_transform_changed_ = false;
   AddClippingWindow();
-  InstallMask();
   ApplyRoundedCorners();
 }
 
@@ -179,15 +178,6 @@
   return true;
 }
 
-bool NativeViewHostAura::SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) {
-  UninstallMask();
-  mask_ = std::move(mask);
-  if (mask_)
-    mask_->layer()->SetFillsBoundsOpaquely(false);
-  InstallMask();
-  return true;
-}
-
 void NativeViewHostAura::SetHitTestTopInset(int top_inset) {
   if (top_inset_ == top_inset)
     return;
@@ -278,15 +268,6 @@
     host_->native_view()->Show();
 }
 
-void NativeViewHostAura::OnWindowBoundsChanged(
-    aura::Window* window,
-    const gfx::Rect& old_bounds,
-    const gfx::Rect& new_bounds,
-    ui::PropertyChangeReason reason) {
-  if (mask_)
-    mask_->layer()->SetBounds(gfx::Rect(host_->native_view()->bounds().size()));
-}
-
 void NativeViewHostAura::OnWindowDestroying(aura::Window* window) {
   DCHECK(window == host_->native_view());
   clipping_window_delegate_->set_native_view(nullptr);
@@ -357,23 +338,6 @@
   }
 }
 
-void NativeViewHostAura::InstallMask() {
-  if (!mask_)
-    return;
-  if (host_->native_view()) {
-    mask_->layer()->SetBounds(gfx::Rect(host_->native_view()->bounds().size()));
-    host_->native_view()->layer()->SetMaskLayer(mask_->layer());
-  }
-}
-
-void NativeViewHostAura::UninstallMask() {
-  if (!host_->native_view() || !mask_)
-    return;
-
-  host_->native_view()->layer()->SetMaskLayer(nullptr);
-  mask_.reset();
-}
-
 void NativeViewHostAura::UpdateInsets() {
   if (!clipping_window_)
     return;
diff --git a/ui/views/controls/native/native_view_host_aura.h b/ui/views/controls/native/native_view_host_aura.h
index 5ce1be2..cab80a7 100644
--- a/ui/views/controls/native/native_view_host_aura.h
+++ b/ui/views/controls/native/native_view_host_aura.h
@@ -9,7 +9,6 @@
 
 #include "base/memory/raw_ptr.h"
 #include "ui/aura/window_observer.h"
-#include "ui/compositor/layer_owner.h"
 #include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/geometry/transform.h"
 #include "ui/views/controls/native/native_view_host_wrapper.h"
@@ -17,7 +16,7 @@
 
 namespace aura {
 class Window;
-}
+}  // namespace aura
 
 namespace views {
 
@@ -40,7 +39,6 @@
   void AddedToWidget() override;
   void RemovedFromWidget() override;
   bool SetCornerRadii(const gfx::RoundedCornersF& corner_radii) override;
-  bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) override;
   void SetHitTestTopInset(int top_inset) override;
   int GetHitTestTopInset() const override;
   void InstallClip(int x, int y, int w, int h) override;
@@ -65,10 +63,6 @@
   // Overridden from aura::WindowObserver:
   void OnWindowDestroying(aura::Window* window) override;
   void OnWindowDestroyed(aura::Window* window) override;
-  void OnWindowBoundsChanged(aura::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds,
-                             ui::PropertyChangeReason reason) override;
 
   void CreateClippingWindow();
 
@@ -83,12 +77,6 @@
   // Sets or updates the |corner_radii_| on the native view's layer.
   void ApplyRoundedCorners();
 
-  // Sets or updates the mask layer on the native view's layer.
-  void InstallMask();
-
-  // Unsets the mask layer on the native view's layer.
-  void UninstallMask();
-
   // Updates the top insets of |clipping_window_|.
   void UpdateInsets();
 
@@ -103,9 +91,6 @@
   std::unique_ptr<aura::Window> clipping_window_;
   std::unique_ptr<gfx::Rect> clip_rect_;
 
-  // This mask exists for the sake of SetCornerRadius().
-  std::unique_ptr<ui::LayerOwner> mask_;
-
   // Holds the corner_radii to be applied.
   gfx::RoundedCornersF corner_radii_;
 
diff --git a/ui/views/controls/native/native_view_host_mac.h b/ui/views/controls/native/native_view_host_mac.h
index a07865a..02c45e8 100644
--- a/ui/views/controls/native/native_view_host_mac.h
+++ b/ui/views/controls/native/native_view_host_mac.h
@@ -5,15 +5,12 @@
 #ifndef UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_MAC_H_
 #define UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_MAC_H_
 
-#include <memory>
-
 #include "base/memory/raw_ptr.h"
 #include "ui/base/cocoa/views_hostable.h"
 #include "ui/views/controls/native/native_view_host_wrapper.h"
 #include "ui/views/views_export.h"
 
 namespace ui {
-class LayerOwner;
 class ViewsHostableView;
 }  // namespace ui
 
@@ -49,7 +46,6 @@
   void AddedToWidget() override;
   void RemovedFromWidget() override;
   bool SetCornerRadii(const gfx::RoundedCornersF& corner_radii) override;
-  bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) override;
   void SetHitTestTopInset(int top_inset) override;
   int GetHitTestTopInset() const override;
   void InstallClip(int x, int y, int w, int h) override;
diff --git a/ui/views/controls/native/native_view_host_mac.mm b/ui/views/controls/native/native_view_host_mac.mm
index c381a9a2..6b692fc 100644
--- a/ui/views/controls/native/native_view_host_mac.mm
+++ b/ui/views/controls/native/native_view_host_mac.mm
@@ -222,11 +222,6 @@
   return true;
 }
 
-bool NativeViewHostMac::SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 void NativeViewHostMac::SetHitTestTopInset(int top_inset) {
   NOTIMPLEMENTED();
 }
diff --git a/ui/views/controls/native/native_view_host_wrapper.h b/ui/views/controls/native/native_view_host_wrapper.h
index 142c3cf4..2b3752a1e 100644
--- a/ui/views/controls/native/native_view_host_wrapper.h
+++ b/ui/views/controls/native/native_view_host_wrapper.h
@@ -5,20 +5,17 @@
 #ifndef UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WRAPPER_H_
 #define UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WRAPPER_H_
 
-#include <memory>
-
 #include "ui/base/cursor/cursor.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/views_export.h"
 
 namespace gfx {
 class RoundedCornersF;
-}
+}  // namespace gfx
 
 namespace ui {
 class Layer;
-class LayerOwner;
-}
+}  // namespace ui
 
 namespace views {
 
@@ -50,15 +47,11 @@
   // rooted at a valid Widget.
   virtual void RemovedFromWidget() = 0;
 
-  // Clips the corners of the gfx::NativeView to the |corner_radii| specififed.
+  // Clips the corners of the gfx::NativeView to the `corner_radii` specified.
   // Returns true on success or false if the platform doesn't support the
   // operation.
   virtual bool SetCornerRadii(const gfx::RoundedCornersF& corner_radii) = 0;
 
-  // Sets the custom mask for clipping gfx::NativeView. Returns true on
-  // success or false if the platform doesn't support the operation.
-  virtual bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) = 0;
-
   // Sets the height of the top region where gfx::NativeView shouldn't be
   // targeted.
   virtual void SetHitTestTopInset(int top_inset) = 0;
diff --git a/v8 b/v8
index 6c7cf27a..9927247 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 6c7cf27a322aa220c36e60faa79370cfbdcbcf5d
+Subproject commit 9927247d821b1fefa9d225acee0d67f2cbdbfd0f