diff --git a/.gitmodules b/.gitmodules
index 4c42655..55266c1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -9,10 +9,6 @@
 	path = chrome/installer/mac/third_party/xz/xz
 	url = https://chromium.googlesource.com/chromium/deps/xz
 	gclient-condition = checkout_mac
-[submodule "chrome/release_scripts"]
-	path = chrome/release_scripts
-	url = https://chrome-internal.googlesource.com/chrome/tools/release/scripts
-	gclient-condition = checkout_chrome_release_scripts
 [submodule "third_party/compiler-rt/src"]
 	path = third_party/compiler-rt/src
 	url = https://chromium.googlesource.com/external/github.com/llvm/llvm-project/compiler-rt
diff --git a/BUILD.gn b/BUILD.gn
index c0a9639..e32e315 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -114,7 +114,6 @@
       "//third_party/angle/src/tests:angle_end2end_tests",
       "//third_party/angle/src/tests:angle_unittests",
       "//third_party/angle/src/tests:angle_white_box_tests",
-      "//third_party/distributed_point_functions/shim:distributed_point_functions_shim_unittests",
       "//third_party/flatbuffers:flatbuffers_unittests",
       "//third_party/highway:highway_tests",
       "//third_party/liburlpattern:liburlpattern_unittests",
diff --git a/DEPS b/DEPS
index 0dab28ee..0e2d1e8 100644
--- a/DEPS
+++ b/DEPS
@@ -135,10 +135,6 @@
   # acts upon.
   'checkout_src_internal_infra' : False,
 
-  # Condition used by a subset of official Chrome release builders.
-  # By default, do not check out release_scripts.
-  'checkout_chrome_release_scripts': False,
-
   # Checkout legacy src_internal. This variable is ignored if
   # checkout_src_internal is set as false.
   'checkout_legacy_src_internal': True,
@@ -299,19 +295,19 @@
   # 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': '2feff4bc46c95c907d7d0ab9836fa5d735eb7c96',
+  'src_internal_revision': '23319755d0789a1e63cc4c1dfb6f38403c9bfa63',
   # 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': '750c73b5f3d518c1bdbefaab7b55dd56aef83c1c',
+  'skia_revision': '32591be9cd3bea8c9e1ad39c64bc8230a4c4d499',
   # 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': 'b7e55339f42eb610415fae3fb16b5a56b3304ffb',
+  'v8_revision': '8b2e5e57af618aadee7b3b9f967348c87da61591',
   # 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': 'f5e2a67a3136b51586f4e2009551cf5b3116b3c7',
+  'angle_revision': '1c7fa5f847f236cc758f58838a9f5f958c1de0de',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -319,7 +315,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '1eb36c32e79a499ab0612b6be6006c563037bb3d',
+  'pdfium_revision': 'e265bde6fee233a96f87ca46464dd662531e0f90',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -375,11 +371,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '417522f6185fde0e4e0812bce00bca1277f286a5',
+  'catapult_revision': '4a839855c5e79d91689784e2c7284f3f6288123b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
-  'crossbench_revision': '3b45a2197a4e242d626f8479c045d89c7062a8f3',
+  'crossbench_revision': '6f0c3181a39f6fdfbaea35689d8126e0361da071',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -395,7 +391,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': '553792fb66b5711ebf46e2de1e5c74f6e553313b',
+  'devtools_frontend_revision': '682af1f84e33247088b8ca38e189f734ff9923ef',
   # 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.
@@ -419,7 +415,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': 'c315409a56fe4ecce7f3ee49b7f7075a298d4e03',
+  'dawn_revision': '0f24b334d63efffa544d1c2fc6d779576a3aa5e9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -527,7 +523,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'compiler_rt_revision': '6558e6a3eacafd269527cf2595e0e722f117c1e6',
+  'compiler_rt_revision': 'cff6ae8a80960ceca4d83cf6efa271222d2e7d85',
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
@@ -1151,11 +1147,6 @@
       'condition': 'checkout_mac',
   },
 
-  'src/chrome/release_scripts': {
-      'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + '088710b5c1f11a40e005e1b4a09cd6bb3a754fe6',
-      'condition': 'checkout_chrome_release_scripts',
-  },
-
   'src/third_party/compiler-rt/src':
     Var('chromium_git') +
     '/external/github.com/llvm/llvm-project/compiler-rt.git' + '@' +
@@ -1495,7 +1486,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '611586675d71250b8b9ffca165e159f05acbb3d5',
+    'a85f502de34463769977268999f0dbce0321efa6',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1654,7 +1645,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'k1zV9FUHrRghPTZBejg81vzwei2vVTdjpM7GhDEXyxQC',
+          'version': 'maUv18JmcvP3nwKYXghGhozFkEce3pFDH6JtbSR0SqQC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -1957,7 +1948,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7ee6e840b449896c4bb271f1232b792eac10905c',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '73e7b77d6878e58c3d26d5fe0d5877cf9ac44597',
       'condition': 'checkout_chromeos',
   },
 
@@ -2535,7 +2526,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'fc9aac573945f2da6d05bf1904d500e6d5cdf18d',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'f4cde1b052fd591a5c50fe11dbcda61c51c4cccf',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -3036,7 +3027,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'WfiGsSWIbN_UapKdDa6SYzPvbRtiVAj95HbKah5XjhMC',
+        'version': 'EaqAC4qcuy5Hq-7VdbO8W5ruTjiF684Mwn0dHuKfXmUC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3047,7 +3038,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'vRkmV5KdXMevk9OUAREFdc08OSZtPZVrUgAnOFQXaNAC',
+        'version': 'f-zzVreu26KWGyDpux6WAgj31DoLpwAdHVhSl2LBEDQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3107,7 +3098,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/autorolled',
-              'version': 'nb19wuIgamdmcgMY_6xHCGH3ph_tLVHkHYH33tKbup4C',
+              'version': 'TZHdcfZjA4uMdOqeaQ-7MG_Pi3P1vgW-fN5TrDzqfVsC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -4529,7 +4520,7 @@
   # grepping.
   'src/chrome/installer/mac/internal': {
       'url': Var('chrome_git') + '/chrome/installer/mac/internal.git' + '@' +
-        'e5018549ab93c778b4d89049c662cf9b35645f97',
+        '6460c6c38734ceabe0bb49c02640b6c2040b1e63',
       'condition': 'checkout_src_internal',
   },
 
@@ -4623,7 +4614,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        '425f25c52e48f3cf6a80dd192a880bdb3106e99c',
+        'd9be8fda5a8b047287677a35f2b3a6111f5883be',
       'condition': 'checkout_src_internal',
   },
 
@@ -4689,7 +4680,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'f52bf9510b206c97e50249032c3e9b3b461f8694',
+        '56c2b01d07aad9c323ad655a8cb07b849923ac99',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/OWNERS b/OWNERS
index 2c55624..c1fa20ca 100644
--- a/OWNERS
+++ b/OWNERS
@@ -47,7 +47,6 @@
 per-file chromeos/assistant/internal=*
 per-file clank=*
 per-file content/test/data/plugin=*
-per-file chrome/release_scripts=*
 per-file docs/website=*
 per-file google_apis/internal=*
 per-file internal=*
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 35d3e025..574fe38a 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1236,7 +1236,7 @@
     ),
     BanRule(
         # Ban everything except specifically allowlisted constructs.
-        pattern=r'/std::ranges::(?!' + '|'.join((
+        pattern=r'/std::ranges::(?!(?:' + '|'.join((
             # From https://en.cppreference.com/w/cpp/ranges:
             # Range access
             'begin',
@@ -1419,7 +1419,11 @@
             'distance',
             'next',
             'prev',
-        )) + r')\w+',
+            # Require a word boundary at the end of negative lookahead
+            # assertion, e.g. to ensure that even though `view` is allowed (and
+            # should not match this regex), `views` is still treated as
+            # disallowed (and matches the regex).
+        )) + r')\b)\w+',
         explanation=(
             'Use of range views and associated helpers is banned in Chrome. '
             'If you need this functionality, please contact cxx@chromium.org.',
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index e82fda5..a2ff946 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -3029,23 +3029,35 @@
             MockFile('some/cpp/problematic/file4.cc', [
                 'Browser* browser = chrome::FindBrowserWithTab(web_contents)'
             ]),
-            MockFile('allowed_ranges_usage.cc', ['std::ranges::begin(vec)']),
-            MockFile('banned_ranges_usage.cc',
-                     ['std::ranges::subrange(first, last)']),
+            MockFile(
+                'allowed_ranges_usage.cc',
+                [
+                    'std::ranges::begin(vec);',
+                    # std::ranges::view is a concept and allowed, but the views
+                    # library itself is not (see below)
+                    'static_assert(std::ranges::view<SomeType>);'
+                ]),
+            MockFile(
+                'banned_ranges_usage.cc',
+                [
+                    'std::ranges::subrange(first, last);',
+                    # Edge case: make sure std::ranges::views is disallowed,
+                    # even though std::ranges::view is allowed.
+                    'std::ranges::views::take(first, count);'
+                ]),
             MockFile('views_usage.cc', ['std::views::all(vec)']),
-            MockFile('content/desktop_android.cc',
-                     [
-                         '// some first line',
-                         '#if BUILDFLAG(IS_DESKTOP_ANDROID)',
-                         '// some third line',
-                     ]),
+            MockFile('content/desktop_android.cc', [
+                '// some first line',
+                '#if BUILDFLAG(IS_DESKTOP_ANDROID)',
+                '// some third line',
+            ]),
         ]
 
         results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
 
         # Each entry in results corresponds to a BanRule with a violation, in
         # the order they were encountered.
-        self.assertEqual(8, len(results))
+        self.assertEqual(9, len(results))
         self.assertTrue('some/cpp/problematic/file.cc' in results[0].message)
         self.assertTrue(
             'third_party/blink/problematic/file.cc' in results[1].message)
@@ -3057,13 +3069,15 @@
         self.assertTrue(all('some/cpp/comment/file.cc' not in r.message for r in results))
         self.assertTrue(all('allowed_ranges_usage.cc' not in r.message for r in results))
         self.assertTrue('banned_ranges_usage.cc' in results[5].message)
-        self.assertTrue('views_usage.cc' in results[6].message)
-        self.assertTrue('content/desktop_android.cc' in results[7].message)
+        self.assertTrue('banned_ranges_usage.cc' in results[6].message)
+        self.assertTrue('views_usage.cc' in results[7].message)
+        self.assertTrue('content/desktop_android.cc' in results[8].message)
 
         # Check ResultLocation data. Line nums start at 1.
-        self.assertEqual(results[7].locations[0].file_path, 'content/desktop_android.cc')
-        self.assertEqual(results[7].locations[0].start_line, 2)
-        self.assertEqual(results[7].locations[0].end_line, 2)
+        self.assertEqual(results[8].locations[0].file_path,
+                         'content/desktop_android.cc')
+        self.assertEqual(results[8].locations[0].start_line, 2)
+        self.assertEqual(results[8].locations[0].end_line, 2)
 
     def testBannedCppRandomFunctions(self):
         banned_rngs = [
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc
index 071f28c2..cc104ae 100644
--- a/android_webview/browser/aw_contents_io_thread_client.cc
+++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -497,9 +497,12 @@
   TRACE_EVENT0("android_webview", "RunShouldInterceptRequest");
   // The app may perform blocking calls as part of synchronous
   // shouldInterceptRequest, so mark the rest of this scope as possibly
-  // blocking.
+  // blocking. This will ensure that the thread pool is expanded to avoid it
+  // being exhausted if all the threads end up waiting at the same time.
+  // See https://crbug.com/404563944 for an example of this happening.
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
+
   JNIEnv* env = AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> obj = ref.get(env);
   if (!obj) {
diff --git a/android_webview/browser/network_service/aw_url_loader_throttle.cc b/android_webview/browser/network_service/aw_url_loader_throttle.cc
index 3546f36..a1a6cf3 100644
--- a/android_webview/browser/network_service/aw_url_loader_throttle.cc
+++ b/android_webview/browser/network_service/aw_url_loader_throttle.cc
@@ -5,8 +5,6 @@
 #include "android_webview/browser/network_service/aw_url_loader_throttle.h"
 
 #include "android_webview/browser/aw_browser_context.h"
-#include "android_webview/common/aw_features.h"
-#include "base/feature_list.h"
 #include "base/strings/string_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_request_headers.h"
@@ -35,17 +33,12 @@
     std::vector<std::string>* to_be_removed_request_headers,
     net::HttpRequestHeaders* modified_request_headers,
     net::HttpRequestHeaders* modified_cors_exempt_request_headers) {
-  bool same_origin_only = base::FeatureList::IsEnabled(
-      features::kWebViewExtraHeadersSameOriginOnly);
-
   if (!added_headers_.empty()) {
-    bool is_same_origin =
-        original_origin_.CanBeDerivedFrom(redirect_info->new_url);
     bool is_same_domain = net::registry_controlled_domains::SameDomainOrHost(
         redirect_info->new_url, original_origin_,
         net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
 
-    if ((same_origin_only && !is_same_origin) || !is_same_domain) {
+    if (!is_same_domain) {
       // The headers we added must be removed.
       to_be_removed_request_headers->insert(
           to_be_removed_request_headers->end(),
diff --git a/android_webview/common/aw_features.cc b/android_webview/common/aw_features.cc
index 20199c2..fb4f26ef 100644
--- a/android_webview/common/aw_features.cc
+++ b/android_webview/common/aw_features.cc
@@ -89,12 +89,6 @@
              "WebViewMuteAudio",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Only allow extra headers added via loadUrl() to be sent to the original
-// origin; strip them from the request if a cross-origin redirect occurs.
-BASE_FEATURE(kWebViewExtraHeadersSameOriginOnly,
-             "WebViewExtraHeadersSameOriginOnly",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Whether to record size of the embedding app's data directory to the UMA
 // histogram Android.WebView.AppDataDirectorySize.
 BASE_FEATURE(kWebViewRecordAppDataDirectorySize,
diff --git a/android_webview/common/aw_features.h b/android_webview/common/aw_features.h
index eebd6e03d..3ff03d2 100644
--- a/android_webview/common/aw_features.h
+++ b/android_webview/common/aw_features.h
@@ -20,7 +20,6 @@
 BASE_DECLARE_FEATURE(kWebViewDigitalAssetLinksLoadIncludes);
 BASE_DECLARE_FEATURE(kWebViewDisableCHIPS);
 BASE_DECLARE_FEATURE(kWebViewDisableSharpeningAndMSAA);
-BASE_DECLARE_FEATURE(kWebViewExtraHeadersSameOriginOnly);
 BASE_DECLARE_FEATURE(kWebViewFileSystemAccess);
 BASE_DECLARE_FEATURE(kWebViewInvokeZoomPickerOnGSU);
 // Feature parameter for `network::features::kMaskedDomainList` which is
diff --git a/android_webview/glue/BUILD.gn b/android_webview/glue/BUILD.gn
index 06d65d4..5695620 100644
--- a/android_webview/glue/BUILD.gn
+++ b/android_webview/glue/BUILD.gn
@@ -77,6 +77,7 @@
     "java/src/com/android/webview/chromium/WebResourceErrorAdapter.java",
     "java/src/com/android/webview/chromium/WebResourceRequestAdapter.java",
     "java/src/com/android/webview/chromium/WebStorageAdapter.java",
+    "java/src/com/android/webview/chromium/WebViewCachedFlags.java",
     "java/src/com/android/webview/chromium/WebViewChromium.java",
     "java/src/com/android/webview/chromium/WebViewChromiumAwInit.java",
     "java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java",
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewCachedFlags.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewCachedFlags.java
new file mode 100644
index 0000000..f3d5818
--- /dev/null
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewCachedFlags.java
@@ -0,0 +1,197 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package com.android.webview.chromium;
+
+import static java.lang.annotation.ElementType.TYPE_USE;
+
+import android.content.SharedPreferences;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.android_webview.AwFeatureMap;
+import org.chromium.android_webview.common.AwFeatures;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This class provides a mechanism for accessing flags before native initialization. It uses
+ * SharedPreferences to cache two Sets of feature flag names. Once they're read from disk at
+ * startup, the disk caches are deleted immediately so that if a crash happens, we don't use the
+ * same flag configuration on the next startup. Once startup is completed, we write new values for
+ * each flag to disk by querying finch.
+ *
+ * <p>To use this class, add your feature to the Map in init. You can then query your feature's
+ * value in code using {@code WebViewCachedFlags.get().isCachedFeatureEnabled(FEATURE_NAME);}. Note:
+ * if you use a feature through the cached mechanism you must not query its value through finch as
+ * the two may differ in their values.
+ */
+@NullMarked
+public class WebViewCachedFlags {
+    private static final String CACHED_ENABLED_FLAGS_PREF = "CachedFlagsEnabled";
+    private static final String CACHED_DISABLED_FLAGS_PREF = "CachedFlagsDisabled";
+    private static final String MIGRATION_HISTOGRAM_NAME = "Android.WebView.CachedFlagMigration";
+
+    @IntDef({DefaultState.DISABLED, DefaultState.ENABLED})
+    @Retention(RetentionPolicy.SOURCE)
+    @Target(TYPE_USE)
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    public @interface DefaultState {
+        int DISABLED = 0;
+        int ENABLED = 1;
+    }
+
+    private static @Nullable WebViewCachedFlags sInstance;
+    private static final Object sLock = new Object();
+
+    private final Map<String, @DefaultState Integer> mDefaults;
+    private final Set<String> mOverrideEnabled;
+    private final Set<String> mOverrideDisabled;
+
+    /**
+     * Initializes the singleton instance and reads the cached values from prefs. This method must
+     * be called before get().
+     *
+     * @param prefs the SharedPreferences from which to initialize the caches.
+     */
+    public static void init(SharedPreferences prefs) {
+        synchronized (sLock) {
+            if (sInstance != null) {
+                throw new IllegalStateException(
+                        "Cannot call WebViewCachedFlags.init more than once.");
+            }
+            sInstance =
+                    new WebViewCachedFlags(
+                            prefs,
+                            Map.of(
+                                    // Add new CachedFlags here along with their default state.
+                                    AwFeatures.WEBVIEW_SEPARATE_RESOURCE_CONTEXT,
+                                            DefaultState.DISABLED,
+                                    AwFeatures.WEBVIEW_DISABLE_CHIPS, DefaultState.DISABLED,
+                                    AwFeatures.WEBVIEW_USE_STARTUP_TASKS_LOGIC,
+                                            DefaultState.DISABLED));
+        }
+    }
+
+    /**
+     * @return the singleton instance of this class.
+     */
+    public static WebViewCachedFlags get() {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                throw new IllegalStateException(
+                        "Can't get WebViewCachedFlags instance before init is called");
+            }
+            return sInstance;
+        }
+    }
+
+    /**
+     * @param feature the name of the feature to query.
+     * @return true if feature is enabled in the cache, false if it is disabled and the default
+     *     value from mDefaults otherwise. Throws IllegalArgumentException if the flag is not
+     *     registered in mDefaults or one of the caches.
+     */
+    public boolean isCachedFeatureEnabled(String feature) {
+        if (mOverrideEnabled.contains(feature)) {
+            return true;
+        } else if (mOverrideDisabled.contains(feature)) {
+            return false;
+        } else if (mDefaults.containsKey(feature)) {
+            return mDefaults.get(feature) == DefaultState.ENABLED;
+        }
+        throw new IllegalArgumentException("Cached feature not registered");
+    }
+
+    /**
+     * Writes new finch values to prefs. This method should be called from a background thread.
+     *
+     * @param prefs the SharedPreferences to write new feature values to.
+     */
+    public void onStartupCompleted(SharedPreferences prefs) {
+        Set<String> newEnabledSet = new HashSet<>();
+        Set<String> newDisabledSet = new HashSet<>();
+        mDefaults.forEach(
+                (String feature, @DefaultState Integer value) -> {
+                    if (AwFeatureMap.isEnabled(feature)) {
+                        newEnabledSet.add(feature);
+                    } else {
+                        newDisabledSet.add(feature);
+                    }
+                });
+        prefs.edit()
+                .putStringSet(CACHED_ENABLED_FLAGS_PREF, newEnabledSet)
+                .putStringSet(CACHED_DISABLED_FLAGS_PREF, newDisabledSet)
+                .apply();
+    }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    public WebViewCachedFlags(
+            SharedPreferences prefs, Map<String, @DefaultState Integer> defaults) {
+        // TODO(crbug.com/414342590): Remove the call to HashSet constructor once the migration code
+        // is removed.
+        mOverrideEnabled =
+                new HashSet<>(
+                        prefs.getStringSet(CACHED_ENABLED_FLAGS_PREF, Collections.emptySet()));
+        mOverrideDisabled =
+                new HashSet<>(
+                        prefs.getStringSet(CACHED_DISABLED_FLAGS_PREF, Collections.emptySet()));
+        SharedPreferences.Editor editor = prefs.edit();
+        cleanUpOldManualExperiments(prefs, editor);
+        editor.remove(CACHED_ENABLED_FLAGS_PREF).remove(CACHED_DISABLED_FLAGS_PREF).apply();
+        mDefaults = defaults;
+    }
+
+    /**
+     * Before this generic mechanism was written, a number of early startup experiments used
+     * individual prefs to read experiment state. By migrating to the generic mechanism, we may
+     * leave many clients with old preferences on their devices. This method cleans up any old
+     * preferences from the manual experiments. It also uses the state of the old preference to
+     * carry forward the client's experiment state so that we don't revert them to the default
+     * behavior for a single startup.
+     *
+     * @param prefs the SharedPreferences object used to initialize this class.
+     * @param editor SharedPreferences.Editor used to make modifications to prefs.
+     */
+    // TODO(crbug.com/414342590): Remove this method once migrations are near 0.
+    private void cleanUpOldManualExperiments(
+            SharedPreferences prefs, SharedPreferences.Editor editor) {
+        boolean didMigration = false;
+        if (prefs.contains("useWebViewResourceContext")) {
+            // If this pref is present, we should enable the WEBVIEW_SEPARATE_RESOURCE_CONTEXT flag
+            // for this run of WebView.
+            editor.remove("useWebViewResourceContext");
+            mOverrideDisabled.remove(AwFeatures.WEBVIEW_SEPARATE_RESOURCE_CONTEXT);
+            mOverrideEnabled.add(AwFeatures.WEBVIEW_SEPARATE_RESOURCE_CONTEXT);
+            didMigration = true;
+        }
+        if (prefs.contains("defaultWebViewPartitionedCookiesState")) {
+            // If this pref is present, we want to default to not using CHIPS so enable the
+            // WEBVIEW_DISABLE_CHIPS flag.
+            editor.remove("defaultWebViewPartitionedCookiesState");
+            mOverrideDisabled.remove(AwFeatures.WEBVIEW_DISABLE_CHIPS);
+            mOverrideEnabled.add(AwFeatures.WEBVIEW_DISABLE_CHIPS);
+            didMigration = true;
+        }
+        if (prefs.contains("webViewUseStartupTasksLogic")) {
+            // If this pref is present, we should enable the WEBVIEW_USE_STARTUP_TASKS_LOGIC flag
+            // for this run of WebView.
+            editor.remove("webViewUseStartupTasksLogic");
+            mOverrideDisabled.remove(AwFeatures.WEBVIEW_USE_STARTUP_TASKS_LOGIC);
+            mOverrideEnabled.add(AwFeatures.WEBVIEW_USE_STARTUP_TASKS_LOGIC);
+            didMigration = true;
+        }
+        RecordHistogram.recordBooleanHistogram(MIGRATION_HISTOGRAM_NAME, didMigration);
+    }
+}
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 9b7cfa1..b72a7ac 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
@@ -460,14 +460,8 @@
                     PostTask.postTask(
                             TaskTraits.BEST_EFFORT,
                             () -> {
-                                mFactory.setWebViewContextExperimentValue(
-                                        AwFeatureMap.isEnabled(
-                                                AwFeatures.WEBVIEW_SEPARATE_RESOURCE_CONTEXT));
-                                mFactory.setWebViewDisableCHIPSExperimentValue(
-                                        AwFeatureMap.isEnabled(AwFeatures.WEBVIEW_DISABLE_CHIPS));
-                                mFactory.setWebViewUseStartupTasksExperimentValue(
-                                        AwFeatureMap.isEnabled(
-                                                AwFeatures.WEBVIEW_USE_STARTUP_TASKS_LOGIC));
+                                WebViewCachedFlags.get()
+                                        .onStartupCompleted(mFactory.getWebViewPrefs());
                             });
 
                     if (AwFeatureMap.isEnabled(AwFeatures.WEBVIEW_PREFETCH_NATIVE_LIBRARY)
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 186f78e..8f21027a 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
@@ -124,11 +124,6 @@
 
     private static final String CHROMIUM_PREFS_NAME = "WebViewChromiumPrefs";
     private static final String VERSION_CODE_PREF = "lastVersionCodeUsed";
-    private static final String WEBVIEW_CONTEXT_EXPERIMENT_PREF = "useWebViewResourceContext";
-    private static final String WEBVIEW_PARTITIONED_COOKIES_DEFAULT_STATE_PREF =
-            "defaultWebViewPartitionedCookiesState";
-    private static final String WEBVIEW_USE_STARTUP_TASKS_LOGIC_PREF =
-            "webViewUseStartupTasksLogic";
 
     private static final String SUPPORT_LIB_GLUE_AND_BOUNDARY_INTERFACE_PREFIX =
             "org.chromium.support_lib_";
@@ -140,20 +135,6 @@
     // WebLayerImpl.java for more info.
     private static final int SHARED_LIBRARY_MAX_ID = 36;
 
-    // Stores the value of the cached SharedPref denoting whether we should use WebView's own
-    // Context for querying resources.
-    private static boolean sUseWebViewContext;
-
-    // Stores the value of the cached SharedPref denoting what the default enablement state of
-    // partitioned cookies is.
-    private static boolean sPartitionedCookiesDefaultState;
-
-    // Stores the value of the cached SharedPref denoting whether we should run chromium startup
-    // using the startup tasks logic which runs the startup tasks asynchronously if startup is
-    // triggered from a background thread. Otherwise runs startup synchronously. Also caches any
-    // chromium startup exception and rethrows it if startup is retried without a restart.
-    private static boolean sWebViewUseStartupTasksLogic;
-
     /**
      * This holds objects of classes that are defined in P and above to ensure that run-time class
      * verification does not occur until it is actually used for P and above.
@@ -318,43 +299,16 @@
         mWebViewDelegate.addWebViewAssetPath(ctx);
     }
 
-    void setWebViewContextExperimentValue(boolean enabled) {
-        if (enabled == sUseWebViewContext
-                || Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) return;
-        if (enabled) {
-            mWebViewPrefs.edit().putBoolean(WEBVIEW_CONTEXT_EXPERIMENT_PREF, true).apply();
-        } else {
-            mWebViewPrefs.edit().remove(WEBVIEW_CONTEXT_EXPERIMENT_PREF).apply();
-        }
-    }
-
-    void setWebViewDisableCHIPSExperimentValue(boolean isDisabled) {
-        if (isDisabled) {
-            mWebViewPrefs
-                    .edit()
-                    .putBoolean(WEBVIEW_PARTITIONED_COOKIES_DEFAULT_STATE_PREF, false)
-                    .apply();
-        } else {
-            mWebViewPrefs.edit().remove(WEBVIEW_PARTITIONED_COOKIES_DEFAULT_STATE_PREF).apply();
-        }
-    }
-
-    void setWebViewUseStartupTasksExperimentValue(boolean enabled) {
-        if (enabled) {
-            mWebViewPrefs.edit().putBoolean(WEBVIEW_USE_STARTUP_TASKS_LOGIC_PREF, true).apply();
-        } else {
-            mWebViewPrefs.edit().remove(WEBVIEW_USE_STARTUP_TASKS_LOGIC_PREF).apply();
-        }
-    }
-
     private boolean shouldEnableStartupTasksExperiment() {
         if (CommandLine.getInstance().hasSwitch(AwSwitches.WEBVIEW_USE_STARTUP_TASKS_LOGIC)) {
             return true;
         }
+        // TODO: Remove this once WebViewCachedFlags has landed (and seems safe).
         if (DisableStartupTasksSafeModeAction.isStartupTasksExperimentDisabled()) {
             return false;
         }
-        return sWebViewUseStartupTasksLogic;
+        return WebViewCachedFlags.get()
+                .isCachedFeatureEnabled(AwFeatures.WEBVIEW_USE_STARTUP_TASKS_LOGIC);
     }
 
     @SuppressWarnings({"NoContextGetApplicationContext", "DiscouragedApi"})
@@ -406,15 +360,7 @@
                 // Since N, getSharedPreferences creates the preference dir if it doesn't exist,
                 // causing a disk write.
                 mWebViewPrefs = ctx.getSharedPreferences(CHROMIUM_PREFS_NAME, Context.MODE_PRIVATE);
-                // Read the experiment value and use it to determine which Context to use.
-                sUseWebViewContext =
-                        mWebViewPrefs.getBoolean(WEBVIEW_CONTEXT_EXPERIMENT_PREF, false);
-                // The same is done for partitioned cookies.
-                sPartitionedCookiesDefaultState =
-                        mWebViewPrefs.getBoolean(
-                                WEBVIEW_PARTITIONED_COOKIES_DEFAULT_STATE_PREF, true);
-                sWebViewUseStartupTasksLogic =
-                        mWebViewPrefs.getBoolean(WEBVIEW_USE_STARTUP_TASKS_LOGIC_PREF, false);
+                WebViewCachedFlags.init(mWebViewPrefs);
             }
 
             if (shouldEnableContextExperiment(ctx)) {
@@ -578,7 +524,8 @@
 
             boolean partitionedCookies =
                     androidXConfig.getPartitionedCookiesEnabled() == null
-                            ? sPartitionedCookiesDefaultState
+                            ? !WebViewCachedFlags.get()
+                                    .isCachedFeatureEnabled(AwFeatures.WEBVIEW_DISABLE_CHIPS)
                             : androidXConfig.getPartitionedCookiesEnabled();
             // We use this to report the state of our partitioned override experiment if set.
             // Applying this after the override of the Android X API has potentially been set
@@ -1037,7 +984,8 @@
             return true;
         }
 
-        return sUseWebViewContext;
+        return WebViewCachedFlags.get()
+                .isCachedFeatureEnabled(AwFeatures.WEBVIEW_SEPARATE_RESOURCE_CONTEXT);
     }
 
     // These values are persisted to logs. Entries should not be renumbered and
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 6af8c9de..844d7db6 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -522,11 +522,6 @@
     private AwViewMethods mAwViewMethods;
     private final FullScreenTransitionsState mFullScreenTransitionsState;
 
-    // The framework may temporarily detach our container view, for example during layout if
-    // we are a child of a ListView. This may cause many toggles of View focus, which we suppress
-    // when in this state.
-    private boolean mTemporarilyDetached;
-
     // True when this AwContents has been destroyed.
     // Do not use directly, call isDestroyed() instead.
     private boolean mIsDestroyed;
@@ -3354,11 +3349,7 @@
         //
         // The difference is important when the user enters full screen and the AwContents is
         // instead attached to a FullScreenView.
-
-        if (TRACE) Log.i(TAG, "%s onAttachedToWindow", this);
-        mTemporarilyDetached = false;
         mAwViewMethods.onAttachedToWindow();
-        mWindowAndroid.getWindowAndroid().getDisplay().addObserver(mDisplayObserver);
 
         if (mDisplayCutoutController != null) mDisplayCutoutController.onAttachedToWindow();
 
@@ -3389,9 +3380,6 @@
     /** @see android.view.View#onDetachedFromWindow() */
     @SuppressLint("MissingSuperCall")
     public void onDetachedFromWindow() {
-        if (TRACE) Log.i(TAG, "%s onDetachedFromWindow", this);
-
-        mWindowAndroid.getWindowAndroid().getDisplay().removeObserver(mDisplayObserver);
         mAwViewMethods.onDetachedFromWindow();
 
         mAwFrameMetricsListener = AwFrameMetricsListener
@@ -3411,12 +3399,12 @@
 
     /** @see android.view.View#onStartTemporaryDetach() */
     public void onStartTemporaryDetach() {
-        mTemporarilyDetached = true;
+        mAwViewMethods.onStartTemporaryDetach();
     }
 
     /** @see android.view.View#onFinishTemporaryDetach() */
     public void onFinishTemporaryDetach() {
-        mTemporarilyDetached = false;
+        mAwViewMethods.onFinishTemporaryDetach();
     }
 
     /**
@@ -4359,6 +4347,11 @@
         // attached to the Window and size tracking is enabled. It will be null otherwise.
         private AwWindowCoverageTracker mAwWindowCoverageTracker;
 
+        // The framework may temporarily detach our container view, for example during layout if
+        // we are a child of a ListView. This may cause many toggles of View focus, which we
+        // suppress when in this state.
+        private boolean mTemporarilyDetached;
+
         @Override
         public void onDraw(Canvas canvas) {
             try {
@@ -4621,12 +4614,17 @@
 
         @Override
         public void onAttachedToWindow() {
+            if (TRACE) Log.i(TAG, "%s onAttachedToWindow", AwContents.this);
+
             if (isDestroyed(NO_WARN)) return;
             if (mIsAttachedToWindow) {
                 Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring");
                 return;
             }
             mIsAttachedToWindow = true;
+            mTemporarilyDetached = false;
+
+            mWindowAndroid.getWindowAndroid().getDisplay().addObserver(mDisplayObserver);
 
             mViewEventSink.onAttachedToWindow();
             AwContentsJni.get()
@@ -4662,11 +4660,15 @@
 
         @Override
         public void onDetachedFromWindow() {
+            if (TRACE) Log.i(TAG, "%s onDetachedFromWindow", AwContents.this);
+
             if (isDestroyed(NO_WARN)) return;
             if (!mIsAttachedToWindow) {
                 Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
                 return;
             }
+
+            mWindowAndroid.getWindowAndroid().getDisplay().removeObserver(mDisplayObserver);
             detachWindowCoverageTracker();
 
             mIsAttachedToWindow = false;
@@ -4829,6 +4831,16 @@
         public boolean performAccessibilityAction(final int action, final Bundle arguments) {
             return false;
         }
+
+        @Override
+        public void onStartTemporaryDetach() {
+            mTemporarilyDetached = true;
+        }
+
+        @Override
+        public void onFinishTemporaryDetach() {
+            mTemporarilyDetached = false;
+        }
     }
 
     @NativeMethods
diff --git a/android_webview/java/src/org/chromium/android_webview/AwViewMethods.java b/android_webview/java/src/org/chromium/android_webview/AwViewMethods.java
index 3a3cd0c..f92aa3d2 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwViewMethods.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwViewMethods.java
@@ -114,5 +114,11 @@
     AccessibilityNodeProvider getAccessibilityNodeProvider();
 
     /** @see android.view.View#performAccessibilityAction */
-    public boolean performAccessibilityAction(final int action, final Bundle arguments);
+    boolean performAccessibilityAction(final int action, final Bundle arguments);
+
+    /** @see android.view.View#onStartTemporaryDetach() */
+    void onStartTemporaryDetach();
+
+    /** @see android.view.View#onFinishTemporaryDetach() */
+    void onFinishTemporaryDetach();
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/NullAwViewMethods.java b/android_webview/java/src/org/chromium/android_webview/NullAwViewMethods.java
index 9105228ff..72189954 100644
--- a/android_webview/java/src/org/chromium/android_webview/NullAwViewMethods.java
+++ b/android_webview/java/src/org/chromium/android_webview/NullAwViewMethods.java
@@ -192,4 +192,14 @@
     public boolean performAccessibilityAction(final int action, final Bundle arguments) {
         return false;
     }
+
+    @Override
+    public void onStartTemporaryDetach() {
+        // Intentional no-op.
+    }
+
+    @Override
+    public void onFinishTemporaryDetach() {
+        // Intentional no-op.
+    }
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 43e2b3f..27ffd8c 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -222,10 +222,6 @@
                 "Enables the ability to use Document Policy header to control feature"
                         + " ExpectNoLinkedResources."),
         Flag.baseFeature(
-                AwFeatures.WEBVIEW_EXTRA_HEADERS_SAME_ORIGIN_ONLY,
-                "Only allow extra headers added via loadUrl() to be sent to the same origin "
-                        + "as the original request."),
-        Flag.baseFeature(
                 BlinkFeatures.WEBVIEW_ACCELERATE_SMALL_CANVASES,
                 "Accelerate all canvases in webview."),
         Flag.baseFeature(
@@ -952,9 +948,6 @@
                 AwFeatures.WEBVIEW_WEBAUTHN,
                 "Enable WebAuthn setWebAuthenticationSupport / getWebAuthenticationSupport APIs."),
         Flag.baseFeature(
-                CcFeatures.THROTTLE_FRAME_RATE_ON_MANY_DID_NOT_PRODUCE_FRAME,
-                "Reduce frame rate when pixels aren't updated for many frames"),
-        Flag.baseFeature(
                 BlinkFeatures.BF_CACHE_OPEN_BROADCAST_CHANNEL,
                 "Start putting pages with broadcast channel into bfcache."),
         Flag.baseFeature(
diff --git a/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuPopulator.java b/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuPopulator.java
index e2052999..1e6fac8 100644
--- a/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuPopulator.java
+++ b/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuPopulator.java
@@ -60,7 +60,7 @@
         items.add(createListItem(Item.COPY_LINK_TEXT));
         items.add(createListItem(Item.OPEN_LINK));
 
-        groupedItems.add(new Pair<>(R.string.context_menu_copy_link_address, items));
+        groupedItems.add(new Pair<>(R.string.context_menu_link_title, items));
 
         return groupedItems;
     }
diff --git a/android_webview/java/strings/android_webview_strings.grd b/android_webview/java/strings/android_webview_strings.grd
index 81c4a717..3d722e8c 100644
--- a/android_webview/java/strings/android_webview_strings.grd
+++ b/android_webview/java/strings/android_webview_strings.grd
@@ -189,6 +189,9 @@
       <message name="IDS_CONTEXT_MENU_OPEN_LINK" desc="Context menu item to open the selected link in a relevant application. [CHAR_LIMIT=30]">
         Open link
       </message>
+      <message name="IDS_CONTEXT_MENU_LINK_TITLE" desc="The title of a context menu tab when the item pressed contains more than one type. This indicates that all the actions are related to the link.">
+        LINK
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/android_webview/java/strings/android_webview_strings_grd/IDS_CONTEXT_MENU_LINK_TITLE.png.sha1 b/android_webview/java/strings/android_webview_strings_grd/IDS_CONTEXT_MENU_LINK_TITLE.png.sha1
new file mode 100644
index 0000000..4ff9cdb
--- /dev/null
+++ b/android_webview/java/strings/android_webview_strings_grd/IDS_CONTEXT_MENU_LINK_TITLE.png.sha1
@@ -0,0 +1 @@
+3927ebc7681a1ed03ac1113a0ff433b6111e1b48
\ No newline at end of file
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java
index 68e93b0..1b5c8d4d 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java
@@ -11,6 +11,7 @@
 import android.webkit.WebViewClient;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
 import com.google.common.util.concurrent.SettableFuture;
@@ -49,6 +50,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
@@ -582,7 +584,9 @@
                 mActivityTestRule.executeJavaScriptAndWaitForResult(
                         awContents, contentsClient, syncGetJs);
 
-        if (header.equals("null")) return null;
+        if (header.equals("null")) {
+            return null;
+        }
         // JSON stringification applied by executeJavaScriptAndWaitForResult adds quotes
         // around returned strings.
         Assert.assertTrue(header.length() > 2);
@@ -1819,4 +1823,76 @@
         Assert.assertEquals(
                 shouldInterceptRequestCallCount, mShouldInterceptRequestHelper.getCallCount());
     }
+
+    @Test
+    @MediumTest
+    @Feature({"AndroidWebView", "Network"})
+    public void testInterceptRequestAllowsThreadBlocking() throws Throwable {
+        // This test asserts that WebView is resilient against blocking operations on the thread
+        // pool where shouldInterceptRequest calls are made.
+        //
+        // It works by creating a web page with a large (`parallelRequestCount`) number of sub
+        // requests.
+        // The number of sub resource requests is chosen to be high enough to exhaust the number of
+        // available threads in the default `base::ThreadPool` SequencedTaskRunner if no care is
+        // taken to handle blocking threads.
+        //
+        // Each call to shouldInterceptRequest will block until all the expected calls have been
+        // made, and only then will they be allowed to complete.
+        //
+        // If the thread pool can be exhausted, then WebView will be prevented from calling
+        // `shouldInterceptRequest` for some of the expected parallel pages, and the test will
+        // eventually time out.
+        //
+        // See https://crbug.com/404563944 for background.
+
+        final int parallelRequestCount = 10;
+
+        // Configure the main page with a number of iframes that load different pages.
+        String iframeTemplate = "<iframe src=\"/sub.html?idx=%d\"></iframe>\n";
+        StringBuilder sb = new StringBuilder("<html>");
+        for (int i = 0; i < parallelRequestCount; i++) {
+            sb.append(String.format(Locale.ROOT, iframeTemplate, i));
+        }
+        sb.append("</html>");
+        final String mainPageUrl = addPageToTestServer(mWebServer, "/", sb.toString());
+        addPageToTestServer(mWebServer, "/sub.html", "subpage");
+
+        final CountDownLatch latch = new CountDownLatch(parallelRequestCount);
+        mContentsClient =
+                new TestAwContentsClient() {
+                    @Override
+                    public WebResourceResponseInfo shouldInterceptRequest(
+                            AwWebResourceRequest request) {
+                        if (request.getUrl().contains("sub.html")) {
+                            latch.countDown();
+                            try {
+                                // Block until all expected calls to `shouldInterceptRequest` have
+                                // been made.
+                                latch.await();
+                            } catch (InterruptedException e) {
+                                throw new AssertionError("latch wait was interrupted", e);
+                            }
+                        }
+                        return super.shouldInterceptRequest(request);
+                    }
+                };
+
+        mTestContainerView = mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient);
+        mAwContents = mTestContainerView.getAwContents();
+
+        int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
+        mShouldInterceptRequestHelper = mContentsClient.getShouldInterceptRequestHelper();
+        int callCount = mShouldInterceptRequestHelper.getCallCount();
+
+        mActivityTestRule.loadUrlAsync(mAwContents, mainPageUrl);
+
+        // Wait until all calls to shouldInterceptRequest (main page + subpages) have completed.
+        // This will time out if the thread pool has been exhausted.
+        mShouldInterceptRequestHelper.waitForCallback(callCount, 1 + parallelRequestCount);
+        Assert.assertTrue(
+                "We should have seen at least all the requests for html pages.",
+                mShouldInterceptRequestHelper.getUrls().size() >= 1 + parallelRequestCount);
+        mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
index 0ecbf2db..6d03de8 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
@@ -32,7 +32,6 @@
 import org.chromium.android_webview.AwContentsClient.AwWebResourceError;
 import org.chromium.android_webview.AwSettings;
 import org.chromium.android_webview.WebviewErrorCode;
-import org.chromium.android_webview.common.AwFeatures;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.android_webview.test.util.JSUtils;
 import org.chromium.base.ThreadUtils;
@@ -327,17 +326,6 @@
         }
     }
 
-    /** Make a test server URL look like it is a different origin. */
-    private static String toDifferentOriginUrl(String url) {
-        if (url.contains("localhost")) {
-            return url.replace("localhost", "127.0.0.1");
-        } else if (url.contains("127.0.0.1")) {
-            return url.replace("127.0.0.1", "localhost");
-        } else {
-            throw new RuntimeException("Can't convert url " + url + " to different origin");
-        }
-    }
-
     /** Call loadUrl() and expect it to throw IllegalArgumentException. */
     private void loadWithInvalidHeaders(AwContents awContents, Map<String, String> extraHeaders)
             throws Exception {
@@ -545,94 +533,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @CommandLineFlags.Add("enable-features=" + AwFeatures.WEBVIEW_EXTRA_HEADERS_SAME_ORIGIN_ONLY)
-    // TODO(crbug.com/40051073) remove flag when enabled by default
-    public void testCrossOriginRedirectWithExtraHeaders() throws Throwable {
-        final TestAwContentsClient contentsClient = new TestAwContentsClient();
-        final AwTestContainerView testContainerView =
-                mActivityTestRule.createAwTestContainerViewOnMainSync(contentsClient);
-        final AwContents awContents = testContainerView.getAwContents();
-        final String echoRedirectedUrlHeader = "echo header";
-        final String echoInitialUrlHeader = "data content";
-
-        AwActivityTestRule.enableJavaScriptOnUiThread(awContents);
-
-        String[] extraHeaders = {
-            "X-ExtraHeaders1", "extra-header-data1", "x-extraHeaders2", "EXTRA-HEADER-DATA2"
-        };
-        final String redirectedUrl =
-                toDifferentOriginUrl(
-                        mTestServer.getURL(
-                                "/echoheader-and-set-data?header="
-                                        + extraHeaders[0]
-                                        + "&header="
-                                        + extraHeaders[2]));
-        final String initialUrl =
-                mTestServer.getURL(
-                        "/server-redirect-echoheader?url="
-                                + encodeUrl(redirectedUrl)
-                                + "&header="
-                                + extraHeaders[0]
-                                + "&header="
-                                + extraHeaders[2]);
-        loadUrlWithExtraHeadersSync(
-                awContents,
-                contentsClient.getOnPageFinishedHelper(),
-                initialUrl,
-                createHeadersMap(extraHeaders));
-        validateHeadersFromJson(
-                awContents, contentsClient, extraHeaders, echoInitialUrlHeader, true);
-        // Check that the headers were removed when the request was redirected to another origin.
-        validateHeadersFromJson(
-                awContents, contentsClient, extraHeaders, echoRedirectedUrlHeader, false);
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"AndroidWebView"})
-    @CommandLineFlags.Add("enable-features=" + AwFeatures.WEBVIEW_EXTRA_HEADERS_SAME_ORIGIN_ONLY)
-    // TODO(crbug.com/40051073) remove flag when enabled by default
-    public void testRedirectToPreviousExtraHeaders() throws Throwable {
-        final TestAwContentsClient contentsClient = new TestAwContentsClient();
-        final AwTestContainerView testContainerView =
-                mActivityTestRule.createAwTestContainerViewOnMainSync(contentsClient);
-        final AwContents awContents = testContainerView.getAwContents();
-        final String echoRedirectedUrlHeader = "echo header";
-
-        AwActivityTestRule.enableJavaScriptOnUiThread(awContents);
-
-        String[] extraHeaders = {
-            "X-ExtraHeaders1", "extra-header-data1", "x-extraHeaders2", "EXTRA-HEADER-DATA2"
-        };
-        final String redirectedUrl =
-                mTestServer.getURL(
-                        "/echoheader-and-set-data?header="
-                                + extraHeaders[0]
-                                + "&header="
-                                + extraHeaders[2]);
-        final String initialUrl =
-                mTestServer.getURL("/server-redirect-echoheader?url=" + encodeUrl(redirectedUrl));
-
-        // First load the redirect target URL with extra headers
-        loadUrlWithExtraHeadersSync(
-                awContents,
-                contentsClient.getOnPageFinishedHelper(),
-                redirectedUrl,
-                createHeadersMap(extraHeaders));
-        validateHeadersFromJson(
-                awContents, contentsClient, extraHeaders, echoRedirectedUrlHeader, true);
-
-        // Now load the initial URL without any extra headers and let it redirect;
-        // the extra headers should not be added to the redirected request.
-        mActivityTestRule.loadUrlSync(
-                awContents, contentsClient.getOnPageFinishedHelper(), initialUrl);
-        validateHeadersFromJson(
-                awContents, contentsClient, extraHeaders, echoRedirectedUrlHeader, false);
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"AndroidWebView"})
     // This test requires BFCache to be disabled in order to trigger the `onPageFinishedHelper`
     // so we can test the extra headers. Since the page is loaded with `Cache-control: no-store`, it
     // was not eligible for BFCache, and now `Cache-control: no-store` is no longer a blocking
diff --git a/android_webview/junit/src/org/chromium/android_webview/robolectric/WebViewCachedFlagsTest.java b/android_webview/junit/src/org/chromium/android_webview/robolectric/WebViewCachedFlagsTest.java
new file mode 100644
index 0000000..a0a4454
--- /dev/null
+++ b/android_webview/junit/src/org/chromium/android_webview/robolectric/WebViewCachedFlagsTest.java
@@ -0,0 +1,136 @@
+// Copyright 2025 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.android_webview.robolectric;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.webview.chromium.WebViewCachedFlags;
+
+import org.chromium.android_webview.common.AwFeatures;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.Features;
+import org.chromium.base.test.util.InMemorySharedPreferences;
+
+import java.util.Map;
+import java.util.Set;
+
+/** Tests for WebViewCachedFlags. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class WebViewCachedFlagsTest {
+    // Keep these in sync with the prefs names in WebViewCachedFlags.java.
+    private static final String CACHED_ENABLED_FLAGS_PREF = "CachedFlagsEnabled";
+    private static final String CACHED_DISABLED_FLAGS_PREF = "CachedFlagsDisabled";
+
+    @Test
+    @Feature({"AndroidWebView"})
+    @SmallTest
+    public void sharedPrefsAreDeletedOnInit() {
+        InMemorySharedPreferences sharedPrefs = new InMemorySharedPreferences();
+        sharedPrefs
+                .edit()
+                .putStringSet(CACHED_ENABLED_FLAGS_PREF, Set.of("Foo", "Bar"))
+                .putStringSet(CACHED_DISABLED_FLAGS_PREF, Set.of("Baz"))
+                .apply();
+        new WebViewCachedFlags(sharedPrefs, Map.of());
+        Assert.assertFalse(sharedPrefs.contains(CACHED_ENABLED_FLAGS_PREF));
+        Assert.assertFalse(sharedPrefs.contains(CACHED_DISABLED_FLAGS_PREF));
+    }
+
+    @Test
+    @Feature({"AndroidWebView"})
+    @SmallTest
+    public void flagsShowAsEnabledAndDisabledCorrectly() {
+        InMemorySharedPreferences sharedPrefs = new InMemorySharedPreferences();
+        sharedPrefs
+                .edit()
+                .putStringSet(CACHED_ENABLED_FLAGS_PREF, Set.of("Foo", "Bar"))
+                .putStringSet(CACHED_DISABLED_FLAGS_PREF, Set.of("Baz"))
+                .apply();
+        WebViewCachedFlags cachedFlags = new WebViewCachedFlags(sharedPrefs, Map.of());
+        Assert.assertTrue(cachedFlags.isCachedFeatureEnabled("Foo"));
+        Assert.assertTrue(cachedFlags.isCachedFeatureEnabled("Bar"));
+        Assert.assertFalse(cachedFlags.isCachedFeatureEnabled("Baz"));
+    }
+
+    @Test
+    @Feature({"AndroidWebView"})
+    @SmallTest
+    public void flagsDefaultToCorrectValueWhenNotCached() {
+        InMemorySharedPreferences sharedPrefs = new InMemorySharedPreferences();
+        sharedPrefs
+                .edit()
+                .putStringSet(CACHED_ENABLED_FLAGS_PREF, Set.of())
+                .putStringSet(CACHED_DISABLED_FLAGS_PREF, Set.of())
+                .apply();
+        WebViewCachedFlags cachedFlags =
+                new WebViewCachedFlags(
+                        sharedPrefs,
+                        Map.of(
+                                "Foo", WebViewCachedFlags.DefaultState.DISABLED,
+                                "Bar", WebViewCachedFlags.DefaultState.DISABLED,
+                                "Baz", WebViewCachedFlags.DefaultState.ENABLED));
+        Assert.assertFalse(cachedFlags.isCachedFeatureEnabled("Foo"));
+        Assert.assertFalse(cachedFlags.isCachedFeatureEnabled("Bar"));
+        Assert.assertTrue(cachedFlags.isCachedFeatureEnabled("Baz"));
+    }
+
+    @Test
+    @Feature({"AndroidWebView"})
+    @SmallTest
+    @Features.EnableFeatures({"Baz"})
+    @Features.DisableFeatures({"Foo", "Bar"})
+    public void flagsAreSetCorrectlyPostStartup() {
+        InMemorySharedPreferences sharedPrefs = new InMemorySharedPreferences();
+        sharedPrefs
+                .edit()
+                .putStringSet(CACHED_ENABLED_FLAGS_PREF, Set.of("Foo", "Bar"))
+                .putStringSet(CACHED_DISABLED_FLAGS_PREF, Set.of("Baz"))
+                .apply();
+        WebViewCachedFlags cachedFlags =
+                new WebViewCachedFlags(
+                        sharedPrefs,
+                        Map.of(
+                                "Foo", WebViewCachedFlags.DefaultState.ENABLED,
+                                "Bar", WebViewCachedFlags.DefaultState.ENABLED,
+                                "Baz", WebViewCachedFlags.DefaultState.ENABLED));
+
+        cachedFlags.onStartupCompleted(sharedPrefs);
+        Assert.assertEquals(
+                Set.of("Baz"), sharedPrefs.getStringSet(CACHED_ENABLED_FLAGS_PREF, Set.of()));
+        Assert.assertEquals(
+                Set.of("Foo", "Bar"),
+                sharedPrefs.getStringSet(CACHED_DISABLED_FLAGS_PREF, Set.of()));
+    }
+
+    @Test
+    @Feature({"AndroidWebView"})
+    @SmallTest
+    public void manualFlagsAreMigrated() {
+        InMemorySharedPreferences sharedPrefs = new InMemorySharedPreferences();
+        sharedPrefs
+                .edit()
+                .putBoolean("useWebViewResourceContext", true)
+                .putBoolean("defaultWebViewPartitionedCookiesState", true)
+                .putBoolean("webViewUseStartupTasksLogic", true)
+                .apply();
+        WebViewCachedFlags cachedFlags = new WebViewCachedFlags(sharedPrefs, Map.of());
+
+        // The flags should be enabled if the prefs were present.
+        Assert.assertTrue(
+                cachedFlags.isCachedFeatureEnabled(AwFeatures.WEBVIEW_SEPARATE_RESOURCE_CONTEXT));
+        Assert.assertTrue(cachedFlags.isCachedFeatureEnabled(AwFeatures.WEBVIEW_DISABLE_CHIPS));
+        Assert.assertTrue(
+                cachedFlags.isCachedFeatureEnabled(AwFeatures.WEBVIEW_USE_STARTUP_TASKS_LOGIC));
+        // Check that we removed the old prefs.
+        Assert.assertFalse(sharedPrefs.contains("useWebViewResourceContext"));
+        Assert.assertFalse(sharedPrefs.contains("defaultWebViewPartitionedCookiesState"));
+        Assert.assertFalse(sharedPrefs.contains("webViewUseStartupTasksLogic"));
+    }
+}
diff --git a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc
index 16684ac..58d2458 100644
--- a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc
+++ b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc
@@ -18,6 +18,7 @@
 #include "components/component_updater/component_updater_command_line_config_policy.h"
 #include "components/component_updater/configurator_impl.h"
 #include "components/prefs/pref_service.h"
+#include "components/update_client/crx_cache.h"
 #include "components/update_client/crx_downloader_factory.h"
 #include "components/update_client/network.h"
 #include "components/update_client/patch/in_process_patcher.h"
@@ -44,7 +45,13 @@
           base::BindRepeating(
               [](PrefService* pref_service) { return pref_service; },
               pref_service),
-          nullptr)) {}
+          nullptr)) {
+  base::FilePath path;
+  crx_cache_ = base::MakeRefCounted<update_client::CrxCache>(
+      base::android::GetCacheDirectory(&path)
+          ? std::optional<base::FilePath>(path.AppendASCII("webview_crx_cache"))
+          : std::nullopt);
+}
 
 AwComponentUpdaterConfigurator::~AwComponentUpdaterConfigurator() = default;
 
@@ -201,13 +208,9 @@
                                                               pref_service);
 }
 
-std::optional<base::FilePath> AwComponentUpdaterConfigurator::GetCrxCachePath()
-    const {
-  base::FilePath path;
-  return base::android::GetCacheDirectory(&path)
-             ? std::optional<base::FilePath>(
-                   path.AppendASCII(("webview_crx_cache")))
-             : std::nullopt;
+scoped_refptr<update_client::CrxCache>
+AwComponentUpdaterConfigurator::GetCrxCache() const {
+  return crx_cache_;
 }
 
 bool AwComponentUpdaterConfigurator::IsConnectionMetered() const {
diff --git a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h
index 4dcc6a3..731c432 100644
--- a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h
+++ b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h
@@ -17,6 +17,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/update_client/activity_data_service.h"
 #include "components/update_client/configurator.h"
+#include "components/update_client/crx_cache.h"
 #include "components/update_client/crx_downloader_factory.h"
 #include "components/update_client/network.h"
 #include "components/update_client/patcher.h"
@@ -65,7 +66,7 @@
   GetProtocolHandlerFactory() const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   update_client::UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<update_client::CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
  protected:
@@ -81,6 +82,7 @@
   scoped_refptr<update_client::CrxDownloaderFactory> crx_downloader_factory_;
   scoped_refptr<update_client::UnzipperFactory> unzip_factory_;
   scoped_refptr<update_client::PatcherFactory> patch_factory_;
+  scoped_refptr<update_client::CrxCache> crx_cache_;
 };
 
 scoped_refptr<update_client::Configurator> MakeAwComponentUpdaterConfigurator(
diff --git a/android_webview/nonembedded/component_updater/aw_component_updater_configurator_unittest.cc b/android_webview/nonembedded/component_updater/aw_component_updater_configurator_unittest.cc
index f656006..2847972 100644
--- a/android_webview/nonembedded/component_updater/aw_component_updater_configurator_unittest.cc
+++ b/android_webview/nonembedded/component_updater/aw_component_updater_configurator_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "components/component_updater/component_updater_command_line_config_policy.h"
 #include "components/component_updater/component_updater_switches.h"
@@ -43,6 +44,7 @@
   base::CommandLine* GetCommandLine() { return cmdline_.get(); }
 
  private:
+  base::test::TaskEnvironment environment_;
   std::unique_ptr<TestingPrefServiceSimple> pref_service_;
   std::unique_ptr<base::CommandLine> cmdline_;
 };
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 9f99e2f1..c0df7b8 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -912,6 +912,7 @@
     "../junit/src/org/chromium/android_webview/robolectric/ShouldInterceptRequestMediatorTest.java",
     "../junit/src/org/chromium/android_webview/robolectric/SupportLibTest.java",
     "../junit/src/org/chromium/android_webview/robolectric/WebAddressParserTest.java",
+    "../junit/src/org/chromium/android_webview/robolectric/WebViewCachedFlagsTest.java",
     "../junit/src/org/chromium/android_webview/robolectric/common/FlagOverrideHelperTest.java",
     "../junit/src/org/chromium/android_webview/robolectric/common/services/ServiceNamesTest.java",
     "../junit/src/org/chromium/android_webview/robolectric/metrics/AwMetricsUtilsTest.java",
diff --git a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
index 1383016a..d8bce7d5 100644
--- a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5436,6 +5436,14 @@
     getter isComposing
     method constructor
     method getTargetRanges
+interface IntegrityViolationReportBody : ReportBody
+    attribute @@toStringTag
+    getter blockedURL
+    getter destination
+    getter documentURL
+    getter reportOnly
+    method constructor
+    method toJSON
 interface InterestEvent : Event
     attribute @@toStringTag
     getter source
diff --git a/android_webview/tools/run_cts.pydeps b/android_webview/tools/run_cts.pydeps
index a80607f7..9f26c3bf 100644
--- a/android_webview/tools/run_cts.pydeps
+++ b/android_webview/tools/run_cts.pydeps
@@ -74,7 +74,6 @@
 //third_party/catapult/devil/devil/devil_env.py
 //third_party/catapult/devil/devil/utils/__init__.py
 //third_party/catapult/devil/devil/utils/cmd_helper.py
-//third_party/catapult/devil/devil/utils/host_utils.py
 //third_party/catapult/devil/devil/utils/lazy/__init__.py
 //third_party/catapult/devil/devil/utils/lazy/weak_constant.py
 //third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 6b0b469..6a5a0639 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2786,7 +2786,7 @@
 // Shows the spatial audio toggle in audio settings page.
 BASE_FEATURE(kShowSpatialAudioToggle,
              "ShowSpatialAudioToggle",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Only collect metrics for the server certificate verification failure in
 // EAP networks.
diff --git a/base/android/java/src/org/chromium/base/BinderCallsListener.java b/base/android/java/src/org/chromium/base/BinderCallsListener.java
index b4b545fa..8349b17 100644
--- a/base/android/java/src/org/chromium/base/BinderCallsListener.java
+++ b/base/android/java/src/org/chromium/base/BinderCallsListener.java
@@ -325,6 +325,7 @@
                             SystemClock.uptimeMillis() - mCurrentTransactionStartTimeMillis;
                     mTotalTimeSpentInBinderCallsMillis += transactionDurationMillis;
                     if (mObserver != null) {
+                        assert mCurrentInterfaceDescriptor != null;
                         mObserver.accept("onTransactEnded", mCurrentInterfaceDescriptor);
                     }
 
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index 7786dc3..49f1fd1 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -18,7 +18,6 @@
 import org.chromium.build.annotations.Nullable;
 
 import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
 
 /** Helper methods to deal with threading related tasks. */
 @NullMarked
@@ -202,19 +201,6 @@
     }
 
     /**
-     * Run the supplied FutureTask on the main thread. The method will block only if the current
-     * thread is the main thread.
-     *
-     * @param task The FutureTask to run
-     * @return The queried task (to aid inline construction)
-     */
-    @NullUnmarked // https://github.com/uber/NullAway/issues/1075
-    public static <T extends @Nullable Object> FutureTask<T> runOnUiThread(FutureTask<T> task) {
-        PostTask.runOrPostTask(TaskTraits.UI_DEFAULT, task);
-        return task;
-    }
-
-    /**
      * Run the supplied Runnable on the main thread. The method will block only if the current
      * thread is the main thread.
      *
@@ -225,19 +211,6 @@
     }
 
     /**
-     * Post the supplied FutureTask to run on the main thread. The method will not block, even if
-     * called on the UI thread.
-     *
-     * @param task The FutureTask to run
-     * @return The queried task (to aid inline construction)
-     */
-    @NullUnmarked // https://github.com/uber/NullAway/issues/1075
-    public static <T extends @Nullable Object> FutureTask<T> postOnUiThread(FutureTask<T> task) {
-        PostTask.postTask(TaskTraits.UI_DEFAULT, task);
-        return task;
-    }
-
-    /**
      * Post the supplied Runnable to run on the main thread. The method will not block, even if
      * called on the UI thread.
      *
diff --git a/base/android/java/src/org/chromium/base/task/ChromiumExecutorServiceFactory.java b/base/android/java/src/org/chromium/base/task/ChromiumExecutorServiceFactory.java
index 1a1f177..69e7d91 100644
--- a/base/android/java/src/org/chromium/base/task/ChromiumExecutorServiceFactory.java
+++ b/base/android/java/src/org/chromium/base/task/ChromiumExecutorServiceFactory.java
@@ -11,6 +11,7 @@
 import com.google.common.util.concurrent.MoreExecutors;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
 import org.chromium.build.annotations.Nullable;
 
 import java.util.Collection;
@@ -40,7 +41,8 @@
         return System.nanoTime();
     }
 
-    private static final class ScheduledFutureTask<V> extends FutureTask<V>
+    @NullUnmarked // https://github.com/uber/NullAway/issues/1212
+    private static final class ScheduledFutureTask<V extends @Nullable Object> extends FutureTask<V>
             implements RunnableScheduledFuture<V> {
         /** The time in nanoseconds when the task is scheduled to execute. */
         private long mNanoTaskScheduledStartTime;
@@ -57,7 +59,7 @@
         /** The time in nanoseconds when the task is actually executed. */
         private long mNanoTaskActualStartTime;
 
-        ScheduledFutureTask(Runnable runnable, @Nullable V result, long nanoDelay) {
+        ScheduledFutureTask(Runnable runnable, V result, long nanoDelay) {
             super(runnable, result);
             mNanoTaskScheduledStartTime = getCurrentTimeNanos() + nanoDelay;
             mNanoTaskPeriod = 0;
@@ -73,7 +75,7 @@
 
         ScheduledFutureTask(
                 Runnable runnable,
-                @Nullable V result,
+                V result,
                 long nanoInitialDelay,
                 long nanoPeriod,
                 long nanoInterTaskDelay) {
@@ -137,14 +139,15 @@
 
         @Override
         public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
-            ScheduledFutureTask<Void> t =
+            ScheduledFutureTask<@Nullable Void> t =
                     new ScheduledFutureTask<>(command, null, unit.toNanos(delay));
             postTask(t);
             return t;
         }
 
         @Override
-        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+        public <V extends @Nullable Object> ScheduledFuture<V> schedule(
+                Callable<V> callable, long delay, TimeUnit unit) {
             ScheduledFutureTask<V> t = new ScheduledFutureTask<V>(callable, unit.toNanos(delay));
             postTask(t);
             return t;
@@ -153,7 +156,7 @@
         @Override
         public ScheduledFuture<?> scheduleAtFixedRate(
                 Runnable command, long initialDelay, long period, TimeUnit unit) {
-            ScheduledFutureTask<Void> t =
+            ScheduledFutureTask<@Nullable Void> t =
                     new ScheduledFutureTask<>(
                             command,
                             null,
@@ -167,7 +170,7 @@
         @Override
         public ScheduledFuture<?> scheduleWithFixedDelay(
                 Runnable command, long initialDelay, long delay, TimeUnit unit) {
-            ScheduledFutureTask<Void> t =
+            ScheduledFutureTask<@Nullable Void> t =
                     new ScheduledFutureTask<>(
                             command,
                             null,
@@ -259,11 +262,12 @@
             PostTask.postDelayedTask(mTaskTraits, runnable, 0);
         }
 
-        private <T> void postTask(ScheduledFutureTask<T> task) {
+        @NullUnmarked // https://github.com/uber/NullAway/issues/1075
+        private <T extends @Nullable Object> void postTask(ScheduledFutureTask<T> task) {
             PostTask.postDelayedTask(mTaskTraits, () -> runTask(task), task.getDelay(MILLISECONDS));
         }
 
-        private <T> void runTask(ScheduledFutureTask<T> task) {
+        private <T extends @Nullable Object> void runTask(ScheduledFutureTask<T> task) {
             task.run();
             if (!task.isPeriodic() || task.isCancelled()) {
                 return;
diff --git a/base/android/java/src/org/chromium/base/task/PostTask.java b/base/android/java/src/org/chromium/base/task/PostTask.java
index 192c37d..a6d907a 100644
--- a/base/android/java/src/org/chromium/base/task/PostTask.java
+++ b/base/android/java/src/org/chromium/base/task/PostTask.java
@@ -15,6 +15,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.build.BuildConfig;
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
 import org.chromium.build.annotations.Nullable;
 
 import java.util.ArrayList;
@@ -174,9 +175,10 @@
      * @param r The task to be run with the specified traits.
      */
     public static void runSynchronously(@TaskTraits int taskTraits, Runnable r) {
-        runSynchronouslyInternal(taskTraits, new FutureTask<Void>(r, null));
+        runSynchronouslyInternal(taskTraits, new FutureTask<@Nullable Void>(r, null));
     }
 
+    @NullUnmarked // https://github.com/uber/NullAway/issues/1075
     private static <T extends @Nullable Object> T runSynchronouslyInternal(
             @TaskTraits int taskTraits, FutureTask<T> task) {
         // Ensure no task origin "caused by" is added, since we are wrapping in a RuntimeException
diff --git a/base/apple/foundation_util.h b/base/apple/foundation_util.h
index 632d3b2..d1c2761 100644
--- a/base/apple/foundation_util.h
+++ b/base/apple/foundation_util.h
@@ -11,6 +11,7 @@
 #include <Security/Security.h>
 
 #include <string>
+#include <string_view>
 
 #include "base/apple/scoped_cftyperef.h"
 #include "base/base_export.h"
@@ -133,14 +134,13 @@
 
 #undef TYPE_NAME_FOR_CF_TYPE_DECL
 
-// Returns the base bundle ID, which can be set by SetBaseBundleID but
-// defaults to a reasonable string. This never returns NULL. BaseBundleID
-// returns a pointer to static storage that must not be freed.
-BASE_EXPORT const char* BaseBundleID();
+// Returns the base bundle ID, which can be set by SetBaseBundleIDOverride,
+// below, but defaults to a reasonable string.
+BASE_EXPORT std::string_view BaseBundleID();
 
-// Sets the base bundle ID to override the default. The implementation will
-// make its own copy of new_base_bundle_id.
-BASE_EXPORT void SetBaseBundleID(const char* new_base_bundle_id);
+// Sets a base bundle ID to override the default value returned by
+// BaseBundleID(), above.
+BASE_EXPORT void SetBaseBundleIDOverride(std::string_view new_base_bundle_id);
 
 // CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more specific
 // CoreFoundation type. The compatibility of the passed object is found by
diff --git a/base/apple/foundation_util.mm b/base/apple/foundation_util.mm
index 4fc41ac4..52924898 100644
--- a/base/apple/foundation_util.mm
+++ b/base/apple/foundation_util.mm
@@ -7,8 +7,6 @@
 #include <CoreFoundation/CoreFoundation.h>
 #import <Foundation/Foundation.h>
 #include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
 
 #include <algorithm>
 #include <vector>
@@ -22,6 +20,7 @@
 #include "base/containers/adapters.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
@@ -294,11 +293,17 @@
 
 #undef TYPE_NAME_FOR_CF_TYPE_DEFN
 
-static const char* base_bundle_id;
+namespace {
+std::optional<std::string>& GetBaseBundleIDOverrideValue() {
+  static NoDestructor<std::optional<std::string>> base_bundle_id;
+  return *base_bundle_id;
+}
+}  // namespace
 
-const char* BaseBundleID() {
-  if (base_bundle_id) {
-    return base_bundle_id;
+std::string_view BaseBundleID() {
+  std::optional<std::string>& override = GetBaseBundleIDOverrideValue();
+  if (override.has_value()) {
+    return override.value();
   }
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -308,12 +313,8 @@
 #endif
 }
 
-void SetBaseBundleID(const char* new_base_bundle_id) {
-  if (new_base_bundle_id != base_bundle_id) {
-    free((void*)base_bundle_id);
-    base_bundle_id =
-        new_base_bundle_id ? UNSAFE_TODO(strdup(new_base_bundle_id)) : nullptr;
-  }
+void SetBaseBundleIDOverride(std::string_view new_base_bundle_id) {
+  GetBaseBundleIDOverrideValue() = std::string(new_base_bundle_id);
 }
 
 #define CF_CAST_DEFN(TypeCF)                                       \
diff --git a/base/apple/mach_port_rendezvous_unittest.cc b/base/apple/mach_port_rendezvous_unittest.cc
index 276a1a3..5c2c1fff 100644
--- a/base/apple/mach_port_rendezvous_unittest.cc
+++ b/base/apple/mach_port_rendezvous_unittest.cc
@@ -254,7 +254,7 @@
 MULTIPROCESS_TEST_MAIN(FailToRendezvous) {
   // The rendezvous system uses the BaseBundleID to construct the bootstrap
   // server name, so changing it will result in a failure to look it up.
-  base::apple::SetBaseBundleID("org.chromium.totallyfake");
+  apple::SetBaseBundleIDOverride("org.chromium.totallyfake");
   CHECK_EQ(nullptr, base::MachPortRendezvousClient::GetInstance());
   return 0;
 }
diff --git a/base/time/time_conversion_posix.cc b/base/time/time_conversion_posix.cc
index 69810cff..8b4c615 100644
--- a/base/time/time_conversion_posix.cc
+++ b/base/time/time_conversion_posix.cc
@@ -46,35 +46,39 @@
 
 // static
 Time Time::FromTimeVal(struct timeval t) {
-  DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond));
+  DCHECK_LT(t.tv_usec, static_cast<int>(kMicrosecondsPerSecond));
   DCHECK_GE(t.tv_usec, 0);
-  if (t.tv_usec == 0 && t.tv_sec == 0) {
-    return Time();
-  }
+
+  // TODO(crbug.com/41405098): Handle negative values including Time::Min().
+
   if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
       t.tv_sec == std::numeric_limits<time_t>::max()) {
     return Max();
   }
-  return Time((static_cast<int64_t>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
-              t.tv_usec + kTimeTToMicrosecondsOffset);
+
+  return Time::UnixEpoch() + Seconds(t.tv_sec) + Microseconds(t.tv_usec);
 }
 
 struct timeval Time::ToTimeVal() const {
-  struct timeval result;
   if (is_null()) {
-    result.tv_sec = 0;
-    result.tv_usec = 0;
-    return result;
+    return {
+        .tv_sec = 0,
+        .tv_usec = 0,
+    };
   }
-  if (is_max()) {
-    result.tv_sec = std::numeric_limits<time_t>::max();
-    result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
-    return result;
-  }
-  int64_t us = us_ - kTimeTToMicrosecondsOffset;
-  result.tv_sec = static_cast<time_t>(us / Time::kMicrosecondsPerSecond);
-  result.tv_usec = us % Time::kMicrosecondsPerSecond;
-  return result;
+
+  // TODO(crbug.com/41405098): Handle negative values including Time::Min().
+
+  const int64_t us = us_ - kTimeTToMicrosecondsOffset;
+  return {
+      .tv_sec = is_max()
+                    ? std::numeric_limits<time_t>::max()
+                    : saturated_cast<time_t>(us / Time::kMicrosecondsPerSecond),
+      .tv_usec =
+          is_max()
+              ? static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1
+              : saturated_cast<suseconds_t>(us % Time::kMicrosecondsPerSecond),
+  };
 }
 
 }  // namespace base
diff --git a/build/android/apk_operations.pydeps b/build/android/apk_operations.pydeps
index cde63ff..5455106a 100644
--- a/build/android/apk_operations.pydeps
+++ b/build/android/apk_operations.pydeps
@@ -48,7 +48,6 @@
 ../../third_party/catapult/devil/devil/devil_env.py
 ../../third_party/catapult/devil/devil/utils/__init__.py
 ../../third_party/catapult/devil/devil/utils/cmd_helper.py
-../../third_party/catapult/devil/devil/utils/host_utils.py
 ../../third_party/catapult/devil/devil/utils/lazy/__init__.py
 ../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py
 ../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps
index 523ae642..f87ec1b 100644
--- a/build/android/test_runner.pydeps
+++ b/build/android/test_runner.pydeps
@@ -78,7 +78,6 @@
 ../../third_party/catapult/devil/devil/utils/__init__.py
 ../../third_party/catapult/devil/devil/utils/cmd_helper.py
 ../../third_party/catapult/devil/devil/utils/file_utils.py
-../../third_party/catapult/devil/devil/utils/host_utils.py
 ../../third_party/catapult/devil/devil/utils/lazy/__init__.py
 ../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py
 ../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/build/autoroll/fetch_util.py b/build/autoroll/fetch_util.py
index e2cf294..c6e1c39 100644
--- a/build/autoroll/fetch_util.py
+++ b/build/autoroll/fetch_util.py
@@ -4,13 +4,20 @@
 
 import hashlib
 import json
+import logging
 import pathlib
 import os
 import subprocess
+import sys
 import zipfile
 import re
 
 _SRC_PATH = pathlib.Path(__file__).resolve().parents[2]
+
+sys.path.insert(1, str(_SRC_PATH / 'third_party/depot_tools'))
+import gclient_eval
+
+
 _FETCH_ALL_PATH = _SRC_PATH / 'third_party/android_deps/fetch_all.py'
 _HASH_LENGTH = 15
 _SKIP_FILES = ('OWNERS', 'cipd.yaml')
@@ -21,6 +28,58 @@
 //                instead.
 '''
 
+ANDROIDX_CIPD_PACKAGE = 'chromium/third_party/androidx'
+
+
+def _get_current_cipd_instance():
+  with open(os.path.join(_SRC_PATH, 'DEPS'), 'rt') as f:
+    gclient_dict = gclient_eval.Exec(f.read())
+    return gclient_eval.GetCIPD(gclient_dict, 'src/third_party/androidx/cipd',
+                                ANDROIDX_CIPD_PACKAGE)
+
+
+def _query_cipd_tags(version):
+  cipd_output = subprocess.check_output(
+      ['cipd', 'describe', ANDROIDX_CIPD_PACKAGE, '-version', version],
+      encoding='utf-8')
+  # Output looks like:
+  # Package:       chromium/third_party/androidx
+  # Instance ID:   gUjEawxv5mQO8yfbuC8W-rx4V3zYE-4LTWggXpZHI4sC
+  # Registered by: user:chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com
+  # Registered at: 2025-01-06 17:54:48.034135 +0000 UTC
+  # Refs:
+  #   latest
+  # Tags:
+  #   details0:version-cr-012873390
+  #   version:cr-012873390
+  lines = cipd_output.split('\n')
+  tags = {}
+  parsing_tags = False
+  for line in lines:
+    if not line.strip():
+      continue
+    if line.startswith('Tags:'):
+      parsing_tags = True
+      continue
+    if parsing_tags:
+      tag, value = line.strip().split(':', 1)
+      tags[tag] = value
+  return tags
+
+
+def get_current_androidx_version():
+  cipd_instance = _get_current_cipd_instance()
+  cipd_tags = _query_cipd_tags(cipd_instance)
+  version_string = cipd_tags['version']
+  version = version_string[len('cr-0'):]
+  logging.info('Resolved current androidx version to %s', version)
+  return version
+
+
+def make_androidx_maven_url(version):
+  return ('https://androidx.dev/snapshots/builds/' + version +
+          '/artifacts/repository')
+
 
 def generate_version_map_str(bom_path, with_hash=False):
   """Generate groovy code to fill the versionCache map.
diff --git a/build/config/c++/c++.gni b/build/config/c++/c++.gni
index c29d898..3e7a300 100644
--- a/build/config/c++/c++.gni
+++ b/build/config/c++/c++.gni
@@ -141,6 +141,35 @@
 assert(!(is_ios && libcxx_is_shared),
        "Can't build libc++ as a shared library on iOS.")
 
+if (libcxx_is_shared) {
+  libcxx_target_type = "shared_library"
+} else if (is_win) {
+  libcxx_target_type = "source_set"
+} else {
+  # Build as a static_library instead of a source_set when possible. Static
+  # library semantics are more ideal for libc++, because they ensure that only
+  # libc++ object files needed to satisfy unresolved symbols at link time are
+  # actually linked into the output. Especially for small targets with minimal
+  # use of libc++, this can provide space savings and a more predictable result,
+  # and cut down on the number of unnecessary static initializers.
+  libcxx_target_type = "static_library"
+}
+
+if (libcxx_target_type == "shared_library" ||
+    export_libcxxabi_from_executables) {
+  # libc++'s target type follows that of libc++, except:
+  #  - When libc++ is built as a shared_library, libc++abi should be a
+  #    source_set, so that libc++abi can be be linked into the libc++
+  #    shared_library in full.
+  #  - When exporting libc++abi from executables, libc++abi should be a
+  #    source_set, so that all of libc++abi is linked into executables
+  #    regardless of whether they directly depend on any particular portion of
+  #    it.
+  libcxxabi_target_type = "source_set"
+} else {
+  libcxxabi_target_type = libcxx_target_type
+}
+
 # Chromium will require using its libc++ library implementation. Warn if the
 # current configuration is not using it.
 if ((!use_custom_libcxx || !use_custom_libcxx_for_host) &&
diff --git a/build/config/rust.gni b/build/config/rust.gni
index 8c074fc..953935d 100644
--- a/build/config/rust.gni
+++ b/build/config/rust.gni
@@ -364,7 +364,22 @@
   }
 }
 
-assert(!toolchain_has_rust || rust_abi_target != "")
+if (toolchain_has_rust) {
+  assert(rust_abi_target != "")
+
+  _known_rust_target_triples_filepath = "//build/rust/known-target-triples.txt"
+  _is_rust_abi_target_a_known_triple = false
+  _known_rust_target_triples_ =
+      read_file(_known_rust_target_triples_filepath, "list lines")
+  foreach(_known_triple, _known_rust_target_triples_) {
+    if (_known_triple == rust_abi_target) {
+      _is_rust_abi_target_a_known_triple = true
+    }
+  }
+  assert(_is_rust_abi_target_a_known_triple,
+         "`${rust_abi_target}` needs to be added to " +
+             "`//${_known_rust_target_triples_filepath}`")
+}
 
 # This variable is passed to the Rust libstd build.
 rust_target_arch = ""
diff --git a/build/fuchsia/test/common.py b/build/fuchsia/test/common.py
index df76e08..90a6016a8 100644
--- a/build/fuchsia/test/common.py
+++ b/build/fuchsia/test/common.py
@@ -372,7 +372,7 @@
             if proc.returncode == 0:
                 return
             time.sleep(3)
-            retry_counter.record(1)
+            retry_counter.record()
         ssh_run(cmd, target_id=target_id, check=True)
 
     for package in packages:
@@ -422,7 +422,7 @@
             time.sleep(5)
         else:
             monitors.count('ffx', 'get_ssh_address', ipv4_only and 'ipv4' or '',
-                           'failed').record(1)
+                           'failed').record()
             raise RuntimeError('No addresses found for target.')
     ssh_port = int(addr['ssh_port'])
     if ssh_port == 0:
diff --git a/build/rust/known-target-triples.txt b/build/rust/known-target-triples.txt
new file mode 100644
index 0000000..3a033bf
--- /dev/null
+++ b/build/rust/known-target-triples.txt
@@ -0,0 +1,42 @@
+# This file lists all target triples (as spelled/expected by `rustc`) that
+# Chromium supports when building Rust libraries.
+#
+# Contents of this file are manually built, by trying to list all possible
+# values of `rust_abi_target` as set in  `//build/config/rust.gni`.
+#
+# `gnrt`'s `build.rs` uses this file to ask `rustc` how to translate Rust's
+# conditional dependency expressions (e.g. `#[cfg(target_env = "msvc")]`) into
+# GN equivalents.
+aarch64-apple-darwin
+aarch64-apple-ios
+aarch64-apple-ios-macabi
+aarch64-apple-ios-sim
+aarch64-apple-tvos
+aarch64-apple-tvos-sim
+aarch64-linux-android
+aarch64-pc-windows-msvc
+aarch64-unknown-fuchsia
+aarch64-unknown-linux-gnu
+arm64e-apple-ios
+arm-unknown-linux-gnueabi
+arm-unknown-linux-gnueabihf
+armv7-linux-androideabi
+armv7-unknown-linux-gnueabi
+armv7-unknown-linux-gnueabihf
+armv7s-apple-ios
+i386-apple-ios
+i686-linux-android
+i686-pc-windows-msvc
+i686-unknown-linux-gnu
+riscv64-linux-android
+riscv64gc-unknown-linux-gnu
+thumbv7neon-linux-androideabi
+thumbv7neon-unknown-linux-gnueabihf
+x86_64-apple-darwin
+x86_64-apple-ios
+x86_64-apple-ios-macabi
+x86_64-apple-tvos
+x86_64-linux-android
+x86_64-pc-windows-msvc
+x86_64-unknown-fuchsia
+x86_64-unknown-linux-gnu
diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn
index f411f2d5..2b4c153 100644
--- a/buildtools/third_party/libc++/BUILD.gn
+++ b/buildtools/third_party/libc++/BUILD.gn
@@ -292,13 +292,7 @@
   }
 }
 
-if (libcxx_is_shared) {
-  _libcxx_target_type = "shared_library"
-} else {
-  _libcxx_target_type = "source_set"
-}
-
-target(_libcxx_target_type, "libc++") {
+target(libcxx_target_type, "libc++") {
   # Most things that need to depend on libc++ should do so via the implicit
   # 'common_deps' dependency below.  Some targets that package libc++.so may
   # need to explicitly depend on libc++.
diff --git a/buildtools/third_party/libc++abi/BUILD.gn b/buildtools/third_party/libc++abi/BUILD.gn
index 331ea447..99135cc 100644
--- a/buildtools/third_party/libc++abi/BUILD.gn
+++ b/buildtools/third_party/libc++abi/BUILD.gn
@@ -6,7 +6,7 @@
 import("//build/config/c++/c++.gni")
 import("//build/config/unwind.gni")
 
-source_set("libc++abi") {
+target(libcxxabi_target_type, "libc++abi") {
   if (export_libcxxabi_from_executables) {
     visibility = [ "//build/config:executable_deps" ]
   } else {
diff --git a/cc/base/features.cc b/cc/base/features.cc
index 5fa413e..11157a84 100644
--- a/cc/base/features.cc
+++ b/cc/base/features.cc
@@ -172,10 +172,6 @@
              "SendExplicitDecodeRequestsImmediately",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kThrottleFrameRateOnManyDidNotProduceFrame,
-             "ThrottleFrameRateOnManyDidNotProduceFrame",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kNewContentForCheckerboardedScrolls,
              "NewContentForCheckerboardedScrolls",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -184,13 +180,6 @@
              "AllowLCDTextWithFilter",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// By default, frame rate starts being throttled when 4 consecutive "did not
-// produce frame" are observed. It stops being throttled when there's a drawn
-// frame.
-const base::FeatureParam<int> kNumDidNotProduceFrameBeforeThrottle{
-    &kThrottleFrameRateOnManyDidNotProduceFrame,
-    "num_did_not_produce_frame_before_throttle", 4};
-
 BASE_FEATURE(kMultipleImplOnlyScrollAnimations,
              "MultipleImplOnlyScrollAnimations",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/cc/base/features.h b/cc/base/features.h
index cfb84cb..31520bd 100644
--- a/cc/base/features.h
+++ b/cc/base/features.h
@@ -175,12 +175,6 @@
 // away rather than piggy-backing on the next BeginMainFrame.
 CC_BASE_EXPORT BASE_DECLARE_FEATURE(kSendExplicitDecodeRequestsImmediately);
 
-// Whether frame rate should be throttled when there were many "did not produce
-// frame" recently.
-CC_BASE_EXPORT BASE_DECLARE_FEATURE(kThrottleFrameRateOnManyDidNotProduceFrame);
-CC_BASE_EXPORT extern const base::FeatureParam<int>
-    kNumDidNotProduceFrameBeforeThrottle;
-
 // When enabled, the CC tree priority will be switched to
 // NEW_CONTENT_TAKES_PRIORITY during long scroll that cause checkerboarding.
 CC_BASE_EXPORT BASE_DECLARE_FEATURE(kNewContentForCheckerboardedScrolls);
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc
index 5177fe3d..7fad3bc 100644
--- a/cc/mojo_embedder/viz_layer_context.cc
+++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -571,6 +571,7 @@
   if (layer.HasAnyRarePropertySet()) {
     auto rare_properties = viz::mojom::RareProperties::New();
     rare_properties->filter_quality = layer.GetFilterQuality();
+    rare_properties->dynamic_range_limit = layer.GetDynamicRangeLimit();
 
     // NOTE: If the layer's RareProperties is present, then `capture_bounds()`
     // is guaranteed to be non-null.
diff --git a/cc/paint/tone_map_util.cc b/cc/paint/tone_map_util.cc
index 986f4337..e70e197 100644
--- a/cc/paint/tone_map_util.cc
+++ b/cc/paint/tone_map_util.cc
@@ -4,10 +4,10 @@
 
 #include "cc/paint/tone_map_util.h"
 
+#include <cmath>
 #include <string_view>
 #include <utility>
 
-#include "base/json/json_reader.h"
 #include "cc/paint/paint_image.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkColorFilter.h"
@@ -15,6 +15,7 @@
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/effects/SkColorMatrix.h"
 #include "third_party/skia/include/effects/SkRuntimeEffect.h"
+#include "ui/gfx/hdr_metadata_agtm.h"
 
 namespace cc {
 
@@ -111,6 +112,107 @@
       SkNamedTransferFn::kLinear, SkNamedGamut::kRec2020));
 }
 
+// AGTM tone mapping shader.
+static constexpr char kAgtmToneMapSKSL[] =
+    "uniform half altr_i_weight;\n"
+    "uniform half altr_j_weight;\n"
+    "uniform half4 altr_i_mix_rgbx;\n"
+    "uniform half4 altr_j_mix_rgbx;\n"
+    "uniform half4 altr_i_mix_Mmcx;\n"
+    "uniform half4 altr_j_mix_Mmcx;\n"
+    "uniform shader altr_i_curve;\n"
+    "uniform shader altr_j_curve;\n"
+    "uniform half gain_min;\n"
+    "uniform half gain_span;\n"
+    "uniform half gain_application_offset;\n"
+    "uniform half curve_scale;\n"
+    "\n"
+    "half3 EvalComponentMixing(half3 color, bool j) {\n"
+    "  half4 rgbx = j ? altr_j_mix_rgbx : altr_i_mix_rgbx;\n"
+    "  half4 Mmcx = j ? altr_j_mix_Mmcx : altr_i_mix_Mmcx;\n"
+    "  half M = max(max(color.r, color.g), color.b);\n"
+    "  half m = min(min(color.r, color.g), color.b);\n"
+    "  half common = dot(rgbx.rgb, color) +\n"
+    "                Mmcx[0] * M +\n"
+    "                Mmcx[1] * m;\n"
+    "  return Mmcx[2] * color + half3(common);\n"
+    "}\n"
+    "half EvalGain(half color, bool j) {\n"
+    "  half2 tc = half2(curve_scale * color + 0.5, 0.5);\n"
+    "  half y = j ? altr_j_curve.eval(tc).a : altr_i_curve.eval(tc).a;\n"
+    "  return gain_min + gain_span * y;\n"
+    "}\n"
+    "half4 main(half4 color) {\n"
+    "  half3 G = half3(0.0);\n"
+    "  if (altr_i_weight > 0.0) {\n"
+    "    half3 mixed = EvalComponentMixing(color.rgb, false);\n"
+    "    G += altr_i_weight * half3(EvalGain(mixed.r, false),\n"
+    "                               EvalGain(mixed.g, false),\n"
+    "                               EvalGain(mixed.b, false));\n"
+    "  }\n"
+    "  if (altr_j_weight > 0.0) {\n"
+    "    half3 mixed = EvalComponentMixing(color.rgb, true);\n"
+    "    G += altr_j_weight * half3(EvalGain(mixed.r, true),\n"
+    "                               EvalGain(mixed.g, true),\n"
+    "                               EvalGain(mixed.b, true));\n"
+    "  }\n"
+    "  color.rgb *= exp2(G);\n"
+    "  return color;\n"
+    "}\n";
+
+sk_sp<SkColorFilter> GetAgtmFilter(const gfx::HdrMetadataAgtmParsed& params,
+                                   float H_target) {
+  auto result = SkRuntimeEffect::MakeForColorFilter(
+      SkString(kAgtmToneMapSKSL, sizeof(kAgtmToneMapSKSL) - 1),
+      /*options=*/{});
+  CHECK(result.effect) << result.errorText.c_str();
+
+  SkRuntimeShaderBuilder builder(result.effect);
+  builder.uniform("gain_min") = params.gain_min;
+  builder.uniform("gain_span") = params.gain_span;
+  builder.uniform("gain_application_offset") = params.gain_application_offset;
+
+  // Set the alternate representation weightings and parameters.
+  size_t altr_i = gfx::HdrMetadataAgtmParsed::kBaselineIndex;
+  size_t altr_j = gfx::HdrMetadataAgtmParsed::kBaselineIndex;
+  float altr_i_weight = 0.f;
+  float altr_j_weight = 0.f;
+  params.ComputeAlternateWeights(H_target, altr_i, altr_i_weight, altr_j,
+                                 altr_j_weight);
+  builder.uniform("altr_i_weight") = altr_i_weight;
+  if (altr_i == gfx::HdrMetadataAgtmParsed::kBaselineIndex) {
+    DCHECK_EQ(altr_i_weight, 0.f);
+    DCHECK_EQ(altr_j, gfx::HdrMetadataAgtmParsed::kBaselineIndex);
+    builder.child("altr_i_curve") = nullptr;
+    builder.uniform("altr_i_mix_rgbx") = SkColor4f();
+    builder.uniform("altr_i_mix_Mmcx") = SkColor4f();
+  } else {
+    const auto& altr = params.alternates[altr_i];
+    builder.child("altr_i_curve") =
+        altr.curve->makeRawShader(SkSamplingOptions(SkFilterMode::kLinear));
+    builder.uniform("altr_i_mix_rgbx") = altr.mix_rgbx;
+    builder.uniform("altr_i_mix_Mmcx") = altr.mix_Mmcx;
+    builder.uniform("curve_scale") =
+        params.baseline_max_component / (altr.curve->width() - 1.f);
+  }
+  builder.uniform("altr_j_weight") = altr_j_weight;
+  if (altr_j == gfx::HdrMetadataAgtmParsed::kBaselineIndex) {
+    DCHECK_EQ(altr_j_weight, 0.f);
+    builder.child("altr_j_curve") = nullptr;
+    builder.uniform("altr_j_mix_rgbx") = SkColor4f();
+    builder.uniform("altr_j_mix_Mmcx") = SkColor4f();
+  } else {
+    const auto& altr = params.alternates[altr_j];
+    builder.child("altr_j_curve") =
+        altr.curve->makeRawShader(SkSamplingOptions(SkFilterMode::kLinear));
+    builder.uniform("altr_j_mix_rgbx") = altr.mix_rgbx;
+    builder.uniform("altr_j_mix_Mmcx") = altr.mix_Mmcx;
+  }
+  auto filter = builder.makeColorFilter();
+  CHECK(filter);
+  return filter->makeWithWorkingColorSpace(params.gain_application_color_space);
+}
+
 }  // namespace
 
 bool ToneMapUtil::UseGainmapShader(const PaintImage& image) {
@@ -157,6 +259,10 @@
   skcms_TransferFunction trfn;
   image->colorSpace()->transferFn(&trfn);
 
+  gfx::HdrMetadataAgtmParsed agtm;
+  const bool agtm_parsed = metadata.has_value() && metadata->agtm.has_value() &&
+                           agtm.Parse(metadata->agtm.value());
+
   // The remaineder of the function will construct `filter` to perform all
   // transformations (scaling, OOTF, and tone mapping).
   sk_sp<SkColorFilter> filter;
@@ -164,7 +270,8 @@
   // Several stages will use the reference white luminance, so extract it
   // early.
   const float reference_white_luminance =
-      gfx::HDRMetadata::GetReferenceWhiteLuminance(metadata);
+      agtm_parsed ? agtm.hdr_reference_white
+                  : gfx::HDRMetadata::GetReferenceWhiteLuminance(metadata);
 
   // The HLG or PQ SkColorSpace may have a white level baked into it. Re-scale
   // to be relative to the white level from the metadata, and apply the
@@ -194,7 +301,11 @@
   }
 
   // Apply tone mapping.
-  {
+  if (agtm_parsed) {
+    auto tone_map_filter =
+        GetAgtmFilter(agtm, std::log2(target_linear_hdr_headroom));
+    filter = SkColorFilters::Compose(tone_map_filter, std::move(filter));
+  } else {
     const float content_max_luminance =
         gfx::HDRMetadata::GetContentMaxLuminance(metadata);
     auto tone_map_filter = GetReinhardToneMapFilter(
diff --git a/cc/trees/frame_rate_estimator.cc b/cc/trees/frame_rate_estimator.cc
index 01d2203..36f9ef34 100644
--- a/cc/trees/frame_rate_estimator.cc
+++ b/cc/trees/frame_rate_estimator.cc
@@ -17,12 +17,6 @@
 
 constexpr auto kInputPriorityDelay = base::Milliseconds(250);
 
-bool IsThrottleFrameRateOnManyDidNotProduceFrameEnabled() {
-  static const bool feature_allowed = base::FeatureList::IsEnabled(
-      features::kThrottleFrameRateOnManyDidNotProduceFrame);
-  return feature_allowed;
-}
-
 }  // namespace
 
 FrameRateEstimator::FrameRateEstimator(base::SequencedTaskRunner* task_runner)
@@ -47,14 +41,10 @@
 void FrameRateEstimator::WillDraw(base::TimeTicks now) {
   TRACE_EVENT1(
       "cc,benchmark", "FrameRateEstimator::WillDraw", "Info",
-      base::StringPrintf("num_did_not_produce_frame_since_last_draw: %" PRIu64
-                         "\nin_video_conference_mode: %d\ninput_priority_mode: "
-                         "%d\nkNumDidNotProduceFrameBeforeThrottle: %d",
-                         num_did_not_produce_frame_since_last_draw_,
-                         in_video_conference_mode_, input_priority_mode_,
-                         features::kNumDidNotProduceFrameBeforeThrottle.Get()));
+      base::StringPrintf("\nin_video_conference_mode: %d\ninput_priority_mode: "
+                         "%d",
+                         in_video_conference_mode_, input_priority_mode_));
 
-  num_did_not_produce_frame_since_last_draw_ = 0u;
   if (!in_video_conference_mode_ || input_priority_mode_) {
     return;
   }
@@ -91,15 +81,6 @@
     return viz::BeginFrameArgs::DefaultInterval() * 2;
   }
 
-  static const uint64_t num_did_not_produce_frame_before_throttle =
-      static_cast<uint64_t>(
-          features::kNumDidNotProduceFrameBeforeThrottle.Get());
-  if (IsThrottleFrameRateOnManyDidNotProduceFrameEnabled() &&
-      num_did_not_produce_frame_since_last_draw_ >
-          num_did_not_produce_frame_before_throttle) {
-    return viz::BeginFrameArgs::DefaultInterval() * 2;
-  }
-
   return viz::BeginFrameArgs::MinInterval();
 }
 
@@ -116,7 +97,6 @@
 
 void FrameRateEstimator::DidNotProduceFrame() {
   num_of_consecutive_frames_with_min_delta_ = 0u;
-  ++num_did_not_produce_frame_since_last_draw_;
 }
 
 }  // namespace cc
diff --git a/cc/trees/frame_rate_estimator.h b/cc/trees/frame_rate_estimator.h
index cc581da..aa724c59 100644
--- a/cc/trees/frame_rate_estimator.h
+++ b/cc/trees/frame_rate_estimator.h
@@ -21,7 +21,7 @@
 // InputPriorityMode in the next 250ms(kInputPriorityDelay) if
 // NotifyInputEvent() is called and exit after the delay. Throttling is
 // disabled in InputPriorityMode despite other conditions.
-// 1. In video conference mode:
+// * In video conference mode:
 // The frame rate will be throttled to half of the default when:
 //   Video conference mode is set and
 //   the last drawn consecutive_frames_with_min_delta_ <
@@ -29,13 +29,6 @@
 // The throttling will be stopped when:
 //   Video conference mode is unset or
 //   the last drawn consecutive_frames_with_min_delta_ >= 4.
-// 2. In consecutive didNotProduceFrame
-// mode(features::kThrottleFrameRateOnManyDidNotProduceFrame):
-// The frame rate will be throttled to half of the default when:
-//   The num_did_not_produce_frame_since_last_draw_ >
-//   4(kNumDidNotProduceFrameBeforeThrottle).
-// The throttling will be stopped when:
-//   There's a drawn frame.
 class CC_EXPORT FrameRateEstimator {
  public:
   explicit FrameRateEstimator(base::SequencedTaskRunner* task_runner);
@@ -51,9 +44,6 @@
  private:
   void OnExitInputPriorityMode();
 
-  // Number of "did not produce frame" since the last draw.
-  uint64_t num_did_not_produce_frame_since_last_draw_ = 0;
-
   // Whether videoconference mode is enabled. In this mode, frame rate is
   // reduced when there is no recent input and many frames with a small
   // interval were produced.
diff --git a/cc/trees/frame_rate_estimator_unittest.cc b/cc/trees/frame_rate_estimator_unittest.cc
index 41def9b..c19c0f80 100644
--- a/cc/trees/frame_rate_estimator_unittest.cc
+++ b/cc/trees/frame_rate_estimator_unittest.cc
@@ -7,7 +7,6 @@
 #include <array>
 #include <memory>
 
-#include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/time/time.h"
@@ -24,10 +23,6 @@
   ~FrameRateEstimatorTest() override = default;
 
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures(
-        /* enabled_features*/ {features::
-                                   kThrottleFrameRateOnManyDidNotProduceFrame},
-        /* disabled_features*/ {});
     task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
     estimator_ = std::make_unique<FrameRateEstimator>(task_runner_.get());
   }
@@ -41,7 +36,6 @@
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   base::SimpleTestTickClock test_tick_clock_;
   std::unique_ptr<FrameRateEstimator> estimator_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(FrameRateEstimatorTest, ToggleEstimationEnabled) {
@@ -107,52 +101,5 @@
   }
 }
 
-TEST_F(FrameRateEstimatorTest, ThrottleWhenManyDidNotProduceFrame) {
-  const base::TimeDelta kIntervalForHalfFps =
-      viz::BeginFrameArgs::DefaultInterval() * 2;
-  test_tick_clock_.Advance(viz::BeginFrameArgs::DefaultInterval());
-  estimator_->WillDraw(test_tick_clock_.NowTicks());
-  EXPECT_EQ(estimator_->GetPreferredInterval(),
-            viz::BeginFrameArgs::MinInterval());
-
-  // Consecutive DidNotProduceFrame.
-  size_t consecutive_num =
-      static_cast<size_t>(
-          features::kNumDidNotProduceFrameBeforeThrottle.Get()) +
-      1;
-  for (size_t i = 0; i < consecutive_num; ++i) {
-    estimator_->DidNotProduceFrame();
-  }
-  EXPECT_EQ(estimator_->GetPreferredInterval(), kIntervalForHalfFps);
-  // Stop throttling if draw.
-  test_tick_clock_.Advance(viz::BeginFrameArgs::DefaultInterval());
-  estimator_->WillDraw(test_tick_clock_.NowTicks());
-  EXPECT_EQ(estimator_->GetPreferredInterval(),
-            viz::BeginFrameArgs::MinInterval());
-}
-
-TEST_F(FrameRateEstimatorTest, ManyDidNotProduceFrameWhenInput) {
-  const base::TimeDelta kIntervalForHalfFps =
-      viz::BeginFrameArgs::DefaultInterval() * 2;
-  test_tick_clock_.Advance(viz::BeginFrameArgs::DefaultInterval());
-  estimator_->WillDraw(test_tick_clock_.NowTicks());
-  EXPECT_EQ(estimator_->GetPreferredInterval(),
-            viz::BeginFrameArgs::MinInterval());
-
-  // Consecutive DidNotProduceFrame.
-  size_t consecutive_num =
-      static_cast<size_t>(
-          features::kNumDidNotProduceFrameBeforeThrottle.Get()) +
-      1;
-  for (size_t i = 0; i < consecutive_num; ++i) {
-    estimator_->DidNotProduceFrame();
-  }
-  EXPECT_EQ(estimator_->GetPreferredInterval(), kIntervalForHalfFps);
-  // No throttlling if input event happens.
-  estimator_->NotifyInputEvent();
-  EXPECT_EQ(estimator_->GetPreferredInterval(),
-            viz::BeginFrameArgs::MinInterval());
-}
-
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 625d110b5..10d17649 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3587,16 +3587,7 @@
       "Frame Sequence Number", ack.frame_id.sequence_number);
   frame_rate_estimator_.DidNotProduceFrame();
   if (layer_tree_frame_sink_) {
-    static const bool feature_allowed = base::FeatureList::IsEnabled(
-        features::kThrottleFrameRateOnManyDidNotProduceFrame);
-    if (feature_allowed) {
-      viz::BeginFrameAck adjust_ack = ack;
-      adjust_ack.preferred_frame_interval =
-          frame_rate_estimator_.GetPreferredInterval();
-      layer_tree_frame_sink_->DidNotProduceFrame(adjust_ack, reason);
-    } else {
-      layer_tree_frame_sink_->DidNotProduceFrame(ack, reason);
-    }
+    layer_tree_frame_sink_->DidNotProduceFrame(ack, reason);
   }
   // While scrolling, we save all event metrics. It is possible that this
   // results in a 0 delta scroll, which has no damage. We take the metrics here
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index ced0c66..fed34f8 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -1081,20 +1081,27 @@
   return IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
 }
 
+void LayerTreeImpl::ValidateEffectTreeeMapping(ElementId element_id,
+                                               PropertyMutation mutation) {
+  auto count = property_trees()->effect_tree().element_id_to_node_index().count(
+      element_id);
+
+  if (count != 1) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "Compositing.Animation.MissingPropertyNodeForElementId", mutation);
+  }
+}
+
 void LayerTreeImpl::SetTransformMutated(ElementId element_id,
                                         const gfx::Transform& transform) {
-  DCHECK_EQ(1u,
-            property_trees()->transform_tree().element_id_to_node_index().count(
-                element_id));
+  ValidateEffectTreeeMapping(element_id, PropertyMutation::kTransform);
   if (property_trees()->transform_tree_mutable().OnTransformAnimated(element_id,
                                                                      transform))
     set_needs_update_draw_properties();
 }
 
 void LayerTreeImpl::SetOpacityMutated(ElementId element_id, float opacity) {
-  DCHECK_EQ(1u,
-            property_trees()->effect_tree().element_id_to_node_index().count(
-                element_id));
+  ValidateEffectTreeeMapping(element_id, PropertyMutation::kOpacity);
   if (property_trees()->effect_tree_mutable().OnOpacityAnimated(element_id,
                                                                 opacity))
     set_needs_update_draw_properties();
@@ -1102,9 +1109,7 @@
 
 void LayerTreeImpl::SetFilterMutated(ElementId element_id,
                                      const FilterOperations& filters) {
-  DCHECK_EQ(1u,
-            property_trees()->effect_tree().element_id_to_node_index().count(
-                element_id));
+  ValidateEffectTreeeMapping(element_id, PropertyMutation::kFilter);
   if (property_trees()->effect_tree_mutable().OnFilterAnimated(element_id,
                                                                filters))
     set_needs_update_draw_properties();
@@ -1113,9 +1118,7 @@
 void LayerTreeImpl::SetBackdropFilterMutated(
     ElementId element_id,
     const FilterOperations& backdrop_filters) {
-  DCHECK_EQ(1u,
-            property_trees()->effect_tree().element_id_to_node_index().count(
-                element_id));
+  ValidateEffectTreeeMapping(element_id, PropertyMutation::kBackdropFilter);
   if (property_trees()->effect_tree_mutable().OnBackdropFilterAnimated(
           element_id, backdrop_filters))
     set_needs_update_draw_properties();
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 93496c4..150698c 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -271,6 +271,19 @@
     return const_reverse_iterator(layer_list_.crend());
   }
 
+  // Tests precondition for mutating a property based on element id.
+  // These enumerated values are used in metrics, and must not be renumbered.
+  // New values must be added to the end of the list increasing kMaxValue, and
+  // obsolete values must be preserved.
+  enum class PropertyMutation {
+    kTransform = 0,
+    kOpacity = 1,
+    kFilter = 2,
+    kBackdropFilter = 3,
+    kMaxValue = kBackdropFilter
+  };
+  void ValidateEffectTreeeMapping(ElementId, PropertyMutation);
+
   void SetTransformMutated(ElementId element_id,
                            const gfx::Transform& transform);
   void SetOpacityMutated(ElementId element_id, float opacity);
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 5f328e7..0c541f3 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -2590,13 +2590,13 @@
 
 DrawTransformData& PropertyTrees::FetchDrawTransformsDataFromCache(
     int transform_id,
-    int dest_id) const {
+    int effect_id) const {
   for (auto& transform_data : cached_data_.draw_transforms[transform_id]) {
     // We initialize draw_transforms with 1 element vectors when
     // ResetCachedData, so if we hit an invalid target id, it means it's the
     // first time we compute draw transforms after reset.
-    if (transform_data.target_id == dest_id ||
-        transform_data.target_id == kInvalidPropertyNodeId) {
+    if (transform_data.effect_id == effect_id ||
+        transform_data.effect_id == kInvalidPropertyNodeId) {
       return transform_data;
     }
   }
@@ -2604,7 +2604,7 @@
   cached_data_.draw_transforms[transform_id].push_back(DrawTransformData());
   DrawTransformData& data = cached_data_.draw_transforms[transform_id].back();
   data.update_number = kInvalidUpdateNumber;
-  data.target_id = dest_id;
+  data.effect_id = effect_id;
   return data;
 }
 
@@ -2636,10 +2636,10 @@
   int dest_id = effect_node->transform_id;
 
   DrawTransformData& data =
-      FetchDrawTransformsDataFromCache(transform_id, dest_id);
+      FetchDrawTransformsDataFromCache(transform_id, effect_id);
 
   DCHECK(data.update_number != cached_data_.transform_tree_update_number ||
-         data.target_id != kInvalidPropertyNodeId);
+         data.effect_id != kInvalidPropertyNodeId);
   if (data.update_number == cached_data_.transform_tree_update_number)
     return data.transforms;
 
@@ -2679,7 +2679,7 @@
   if (!already_computed_inverse)
     data.transforms.to_valid = true;
   data.update_number = cached_data_.transform_tree_update_number;
-  data.target_id = dest_id;
+  data.effect_id = effect_id;
   data.transforms.from_target = from_target;
   data.transforms.to_target = target_space_transform;
   return data.transforms;
@@ -2697,7 +2697,7 @@
   for (auto& draw_transforms_for_id : cached_data_.draw_transforms) {
     draw_transforms_for_id.resize(1);
     draw_transforms_for_id[0].update_number = kInvalidUpdateNumber;
-    draw_transforms_for_id[0].target_id = kInvalidPropertyNodeId;
+    draw_transforms_for_id[0].effect_id = kInvalidPropertyNodeId;
   }
 }
 
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 1dd3f5e..3067771 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -747,7 +747,7 @@
 
 struct DrawTransformData {
   int update_number = kInvalidUpdateNumber;
-  int target_id = kInvalidPropertyNodeId;
+  int effect_id = kInvalidPropertyNodeId;
 
   // TODO(sunxd): Move screen space transforms here if it can improve
   // performance.
diff --git a/chrome/VERSION b/chrome/VERSION
index 3e0d8314e..c38e913a 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=138
 MINOR=0
-BUILD=7165
+BUILD=7166
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 66eae5a..ce68883 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -530,7 +530,6 @@
       "//chrome/browser/ui/android/page_info:java",
       "//chrome/browser/ui/android/pdf:java",
       "//chrome/browser/ui/android/pdf:pdf_provider_java",
-      "//chrome/browser/ui/android/plus_addresses:java",
       "//chrome/browser/ui/android/preloading:java",
       "//chrome/browser/ui/android/quickactionsearchwidget:java",
       "//chrome/browser/ui/android/searchactivityutils:java",
@@ -541,6 +540,7 @@
       "//chrome/browser/ui/android/web_app_header:java",
       "//chrome/browser/ui/android/whats_new:java",
       "//chrome/browser/ui/messages/android:java",
+      "//chrome/browser/ui/plus_addresses/android:java",
       "//chrome/browser/uid/android:java",
       "//chrome/browser/usb/android:java",
       "//chrome/browser/user_education:java",
@@ -1142,7 +1142,6 @@
       "//chrome/browser/ui/android/night_mode:junit",
       "//chrome/browser/ui/android/omnibox:junit",
       "//chrome/browser/ui/android/pdf:junit",
-      "//chrome/browser/ui/android/plus_addresses:junit",
       "//chrome/browser/ui/android/searchactivityutils:junit",
       "//chrome/browser/ui/android/settings_promo_card:junit",
       "//chrome/browser/ui/android/signin:junit",
@@ -1152,6 +1151,7 @@
       "//chrome/browser/ui/android/webid/internal:junit",
       "//chrome/browser/ui/android/whats_new:junit",
       "//chrome/browser/ui/messages/android:junit",
+      "//chrome/browser/ui/plus_addresses/android:junit",
       "//chrome/browser/uid/android:junit",
       "//chrome/browser/usb/android:junit",
       "//chrome/browser/user_education:junit",
@@ -2360,8 +2360,8 @@
       "//chrome/browser/touch_to_fill/password_manager/password_generation/android/internal:javatests",
       "//chrome/browser/ui/android/digital_credentials:javatests",
       "//chrome/browser/ui/android/fast_checkout/internal:javatests",
-      "//chrome/browser/ui/android/plus_addresses:javatests",
       "//chrome/browser/ui/android/webid/internal:javatests",
+      "//chrome/browser/ui/plus_addresses/android:javatests",
       "//components/ip_protection/android/android_auth_client_lib/javatests:ip_protection_auth_javatests",
     ]
 
@@ -3319,11 +3319,11 @@
       "//chrome/browser/ui/android/hats/internal:jni_headers",
       "//chrome/browser/ui/android/logo:jni_headers",
       "//chrome/browser/ui/android/omnibox:jni_headers",
-      "//chrome/browser/ui/android/plus_addresses:jni_headers",
       "//chrome/browser/ui/android/preloading:jni_headers",
       "//chrome/browser/ui/android/toolbar:jni_headers",
       "//chrome/browser/ui/android/webid:jni_headers",
       "//chrome/browser/ui/messages/android:jni_headers",
+      "//chrome/browser/ui/plus_addresses/android:jni_headers",
       "//chrome/browser/util:jni_headers",
       "//chrome/browser/webauthn/android:jni_headers",
       "//components/browser_ui/device_lock/android:device_lock_bridge_jni_headers",
diff --git a/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected b/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected
index 5423706..2a63a13 100644
--- a/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected
@@ -486,7 +486,7 @@
         android:exported="false"
         android:hardwareAccelerated="false"
         android:label="WebXR"
-        android:launchMode="singleTask"
+        android:launchMode="singleInstancePerTask"
         android:noHistory="true"
         android:resizeableActivity="false"
         android:screenOrientation="landscape"
diff --git a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
index 0a66d33..5f2df15 100644
--- a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
@@ -464,7 +464,7 @@
         android:exported="false"
         android:hardwareAccelerated="false"
         android:label="WebXR"
-        android:launchMode="singleTask"
+        android:launchMode="singleInstancePerTask"
         android:noHistory="true"
         android:resizeableActivity="false"
         android:screenOrientation="landscape"
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index e06b136..faf9c9b5 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -27,9 +27,7 @@
     "java/res/anim/iph_touch_point_animation.xml",
     "java/res/anim/iph_touch_point_background_alpha_animation.xml",
     "java/res/anim/iph_touch_point_background_animation.xml",
-    "java/res/color-night/tab_grid_dialog_bg_color.xml",
     "java/res/color-night/tab_hover_card_bg_color.xml",
-    "java/res/color/tab_grid_dialog_bg_color.xml",
     "java/res/color/tab_hover_card_bg_color.xml",
     "java/res/drawable/archived_tab_icon.xml",
     "java/res/drawable/chevron_right.xml",
diff --git a/chrome/android/features/tab_ui/java/res/color-night/tab_grid_dialog_bg_color.xml b/chrome/android/features/tab_ui/java/res/color-night/tab_grid_dialog_bg_color.xml
deleted file mode 100644
index 4c9a1ac..0000000
--- a/chrome/android/features/tab_ui/java/res/color-night/tab_grid_dialog_bg_color.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2025 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:color="?attr/colorSurfaceContainerLow" />
-</selector>
diff --git a/chrome/android/features/tab_ui/java/res/color/tab_grid_dialog_bg_color.xml b/chrome/android/features/tab_ui/java/res/color/tab_grid_dialog_bg_color.xml
deleted file mode 100644
index 8a60d84..0000000
--- a/chrome/android/features/tab_ui/java/res/color/tab_grid_dialog_bg_color.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2025 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:color="?attr/colorSurface" />
-</selector>
diff --git a/chrome/android/features/tab_ui/java/res/values/colors.xml b/chrome/android/features/tab_ui/java/res/values/colors.xml
index 3277daf..b43e0e0 100644
--- a/chrome/android/features/tab_ui/java/res/values/colors.xml
+++ b/chrome/android/features/tab_ui/java/res/values/colors.xml
@@ -26,8 +26,6 @@
     <color name="incognito_tab_tile_number_color">@color/baseline_neutral_90</color>
     <color name="incognito_tab_tile_number_selected_color">@color/baseline_primary_20</color>
 
-    <color name="incognito_tab_grid_dialog_background_color">@color/gm3_baseline_surface_container_low_dark</color>
-
     <color name="incognito_tab_grid_dialog_ungroup_bar_bg_hovered_color">@color/baseline_primary_80</color>
 
     <color name="incognito_tab_grid_dialog_ungroup_bar_text_color">@color/baseline_primary_80</color>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
index 7374d9d..fb099d5 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
@@ -215,26 +215,18 @@
      */
     public static @ColorInt int getTabGridDialogBackgroundColor(
             Context context, boolean isIncognito) {
-        if (isIncognito) {
-            return context.getColor(R.color.incognito_tab_grid_dialog_background_color);
-        } else {
-            return ContextCompat.getColor(context, R.color.tab_grid_dialog_bg_color);
-        }
+        return SurfaceColorUpdateUtils.getTabGridDialogBackgroundColor(context, isIncognito);
     }
 
     private static @ColorInt int getTabGridDialogUngroupBarBackgroundColor(
             Context context, boolean isIncognito, boolean isTabHovered) {
-        if (isIncognito) {
-            return context.getColor(
-                    isTabHovered
-                            ? R.color.incognito_tab_grid_dialog_ungroup_bar_bg_hovered_color
-                            : R.color.incognito_tab_grid_dialog_background_color);
-        } else {
-            return MaterialColors.getColor(
-                    context,
-                    isTabHovered ? org.chromium.chrome.R.attr.colorPrimary : R.attr.colorSurface,
-                    TAG);
+        if (isTabHovered) {
+            return isIncognito
+                    ? context.getColor(
+                            R.color.incognito_tab_grid_dialog_ungroup_bar_bg_hovered_color)
+                    : SemanticColorUtils.getColorPrimary(context);
         }
+        return getTabGridDialogBackgroundColor(context, isIncognito);
     }
 
     private static @ColorInt int getTabGridDialogUngroupBarTextColor(
@@ -357,7 +349,7 @@
     public static @ColorInt int getTabSelectionToolbarBackground(
             Context context, boolean isIncognito, @CreationMode int creationMode) {
         if (creationMode == CreationMode.DIALOG) {
-            return ContextCompat.getColor(context, R.color.tab_grid_dialog_bg_color);
+            return getTabGridDialogBackgroundColor(context, isIncognito);
         }
         return SurfaceColorUpdateUtils.getGridTabSwitcherBackgroundColor(context, isIncognito);
     }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java
index 06adb98..59918b4 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java
@@ -434,8 +434,7 @@
     @UiThreadTest
     public void testSetDialogBackgroundColor() {
         int incognitoColor =
-                ContextCompat.getColor(
-                        sActivity, R.color.incognito_tab_grid_dialog_background_color);
+                ContextCompat.getColor(sActivity, R.color.gm3_baseline_surface_container_low_dark);
 
         mModel.set(TabGridDialogProperties.DIALOG_BACKGROUND_COLOR, incognitoColor);
 
@@ -447,8 +446,7 @@
     @UiThreadTest
     public void testSetUngroupbarBackgroundColor() {
         int incognitoColor =
-                ContextCompat.getColor(
-                        sActivity, R.color.incognito_tab_grid_dialog_background_color);
+                ContextCompat.getColor(sActivity, R.color.gm3_baseline_surface_container_low_dark);
 
         mModel.set(TabGridDialogProperties.DIALOG_UNGROUP_BAR_BACKGROUND_COLOR, incognitoColor);
 
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java
index f370f510..ac032bc 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java
@@ -33,6 +33,7 @@
 import org.chromium.chrome.test.R;
 import org.chromium.chrome.test.transit.ChromeTransitTestRules;
 import org.chromium.chrome.test.transit.FreshCtaTransitTestRule;
+import org.chromium.chrome.test.transit.Journeys;
 import org.chromium.chrome.test.transit.hub.TabSwitcherSearchStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.util.ActivityTestUtils;
@@ -43,6 +44,7 @@
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 
 /** Tests for search in the tab switcher. */
@@ -114,11 +116,8 @@
     @Restriction(PHONE)
     public void testHubSearchBox_Phone_Incognito() throws IOException {
         ChromeTabbedActivity cta = mCtaTestRule.getActivity();
-        TabSwitcherSearchTestUtils.openUrls(
-                        mTestServer,
-                        mInitialPage,
-                        Arrays.asList("/chrome/test/data/android/navigate/one.html"),
-                        /* incognito= */ true)
+        List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
+        Journeys.createIncognitoTabsWithWebPages(mInitialPage, mTestServer.getURLs(urlsToOpen))
                 .openIncognitoTabSwitcher();
 
         mRenderTestRule.render(
@@ -158,11 +157,8 @@
     @Restriction(TABLET)
     public void testHubSearchLoupe_Tablet_Incognito() throws IOException {
         ChromeTabbedActivity cta = mCtaTestRule.getActivity();
-        TabSwitcherSearchTestUtils.openUrls(
-                        mTestServer,
-                        mInitialPage,
-                        Arrays.asList("/chrome/test/data/android/navigate/one.html"),
-                        /* incognito= */ true)
+        List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
+        Journeys.createIncognitoTabsWithWebPages(mInitialPage, mTestServer.getURLs(urlsToOpen))
                 .openIncognitoTabSwitcher();
 
         mRenderTestRule.render(
@@ -176,12 +172,10 @@
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testZeroPrefixSuggestions_ShownInRegular(boolean nightModeEnabled)
             throws IOException {
+        List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/test.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer,
-                                mInitialPage,
-                                Arrays.asList("/chrome/test/data/android/test.html"),
-                                /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(true);
@@ -195,12 +189,10 @@
     @MediumTest
     @Feature({"RenderTest"})
     public void testZeroPrefixSuggestions_HiddenInIncognito() throws IOException {
+        List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/test.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer,
-                                mInitialPage,
-                                Arrays.asList("/chrome/test/data/android/test.html"),
-                                /* incognito= */ true)
+                Journeys.createIncognitoTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openIncognitoTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(false);
@@ -215,12 +207,10 @@
     @Feature({"RenderTest"})
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testRenderTypedSuggestions(boolean nightModeEnabled) throws IOException {
+        List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer,
-                                mInitialPage,
-                                Arrays.asList("/chrome/test/data/android/navigate/one.html"),
-                                /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("one.html");
@@ -235,12 +225,10 @@
     @MediumTest
     @Feature({"RenderTest"})
     public void testRenderTypedSuggestions_Incognito() throws IOException {
+        List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer,
-                                mInitialPage,
-                                Arrays.asList("/chrome/test/data/android/navigate/one.html"),
-                                /* incognito= */ true)
+                Journeys.createIncognitoTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openIncognitoTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("one.html");
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java
index 56e3f5c1..8f75547 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java
@@ -60,6 +60,7 @@
 import org.chromium.chrome.test.R;
 import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule;
 import org.chromium.chrome.test.transit.ChromeTransitTestRules;
+import org.chromium.chrome.test.transit.Journeys;
 import org.chromium.chrome.test.transit.hub.TabSwitcherSearchStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.util.BookmarkTestUtil;
@@ -137,8 +138,8 @@
                         "/chrome/test/data/android/test.html",
                         "/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(true);
@@ -159,8 +160,8 @@
                         "/chrome/test/data/android/test.html",
                         "/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(true);
@@ -186,8 +187,8 @@
         ChromeTabbedActivity cta = mCtaTestRule.getActivity();
         List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(true);
@@ -217,8 +218,8 @@
                         "/chrome/test/data/android/test.html",
                         "/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(true);
@@ -244,8 +245,8 @@
     public void testZeroPrefixSuggestions_Incognito() {
         List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ true)
+                Journeys.createIncognitoTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openIncognitoTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(false);
@@ -259,8 +260,8 @@
                         "/chrome/test/data/android/test.html",
                         "/chrome/test/data/android/test.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.checkSuggestionsShown(true);
@@ -274,8 +275,8 @@
     public void testTypedSuggestions() {
         List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("one.html");
@@ -293,8 +294,8 @@
                         "/chrome/test/data/android/test.html",
                         "/chrome/test/data/android/test.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("test.html");
@@ -321,8 +322,8 @@
         ChromeTabbedActivity cta = mCtaTestRule.getActivity();
         List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("one.html");
@@ -352,8 +353,8 @@
                         "/chrome/test/data/android/navigate/one.html",
                         "/chrome/test/data/android/test.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ false)
+                Journeys.prepareRegularTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openRegularTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("one.html");
@@ -376,8 +377,8 @@
     public void testTypedSuggestions_Incognito() {
         List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ true)
+                Journeys.createIncognitoTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openIncognitoTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("one.html");
@@ -426,8 +427,8 @@
         ChromeTabbedActivity cta = mCtaTestRule.getActivity();
         List<String> urlsToOpen = Arrays.asList("/chrome/test/data/android/navigate/one.html");
         TabSwitcherSearchStation tabSwitcherSearchStation =
-                TabSwitcherSearchTestUtils.openUrls(
-                                mTestServer, mInitialPage, urlsToOpen, /* incognito= */ true)
+                Journeys.createIncognitoTabsWithWebPages(
+                                mInitialPage, mTestServer.getURLs(urlsToOpen))
                         .openIncognitoTabSwitcher()
                         .openTabSwitcherSearch();
         tabSwitcherSearchStation.typeInOmnibox("foobar");
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTestUtils.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTestUtils.java
index 0009ccd..6319a327 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTestUtils.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTestUtils.java
@@ -16,14 +16,11 @@
 import org.chromium.chrome.browser.searchwidget.SearchActivity;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.R;
-import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.util.ActivityTestUtils;
 import org.chromium.chrome.test.util.OmniboxTestUtils;
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.ui.base.DeviceFormFactor;
 
-import java.util.List;
-
 /** Test utils for hub search. */
 public class TabSwitcherSearchTestUtils {
     /** Launch the SearchActivity and wait for ZPS to load. */
@@ -56,34 +53,4 @@
         activityTestRule.getEmbeddedTestServerRule().setServerPort(serverPort);
         return activityTestRule.getTestServer();
     }
-
-    /**
-     * Opens the given urls, the first URL will be opened in the current active tab (unless
-     * incognito). The rest of the URLs will be opened in new tabs.
-     *
-     * @return The {@link WebPageStation} of the last opened URL.
-     */
-    // TODO(crbug.com/393653256): Consider reusing for more tab suites.
-    public static WebPageStation openUrls(
-            EmbeddedTestServer testServer,
-            WebPageStation webPageStation,
-            List<String> urlsToOpen,
-            boolean incognito) {
-        WebPageStation lastStation = webPageStation;
-        for (int i = 0; i < urlsToOpen.size(); i++) {
-            String url = testServer.getURL(urlsToOpen.get(i));
-            if (i == 0) {
-                if (incognito) {
-                    lastStation =
-                            lastStation.openNewIncognitoTabFast().loadWebPageProgrammatically(url);
-                } else {
-                    lastStation = lastStation.loadWebPageProgrammatically(url);
-                }
-            } else {
-                lastStation = lastStation.openFakeLinkToWebPage(url);
-            }
-        }
-
-        return lastStation;
-    }
 }
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 17013b2..3c6b68b 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -1204,7 +1204,7 @@
             {{ self.chrome_activity_common() }}
             android:excludeFromRecents="true"
             android:noHistory="true"
-            android:launchMode="singleTask"
+            android:launchMode="singleInstancePerTask"
             android:exported="false"
             android:resizeableActivity="false"
             android:screenOrientation="landscape"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/OWNERS
deleted file mode 100644
index ca12311..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://chrome/android/java/src/org/chromium/chrome/browser/payments/OWNERS
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 b190b1d..203c36d 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
@@ -881,6 +881,13 @@
         if (mTabFactory != null) {
             mTabFactory.destroyTabModelOrchestrator();
         }
+
+        // If tab models have not been initialized, any early created tabs would leak.
+        if (mTabProvider != null
+                && mTabProvider.getTab() != null
+                && !mTabProvider.getTab().isDestroyed()) {
+            mTabProvider.getTab().destroy();
+        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
index cf4abd2..867c3b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
@@ -400,7 +400,8 @@
         Preference homepagePref = addPreferenceIfAbsent(PREF_HOMEPAGE);
         setOnOffSummary(homepagePref, HomepageManager.getInstance().isHomepageEnabled());
 
-        if (HomeModulesConfigManager.getInstance().hasModuleShownInSettings()) {
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.NEW_TAB_PAGE_CUSTOMIZATION)
+                && HomeModulesConfigManager.getInstance().hasModuleShownInSettings()) {
             addPreferenceIfAbsent(PREF_HOME_MODULES_CONFIG);
         } else {
             removePreferenceIfPresent(PREF_HOME_MODULES_CONFIG);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
index 3656145..bcaf7c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
@@ -194,11 +194,14 @@
                 currentTab,
                 (ShareParams p) -> {
                     if (p != null) {
+                        var webContents = currentTab.getWebContents();
+                        var renderFrameHost =
+                                webContents != null ? webContents.getMainFrame() : null;
+
                         var extras =
                                 new ChromeShareExtras.Builder()
                                         .setIsUrlOfVisiblePage(true)
-                                        .setRenderFrameHost(
-                                                currentTab.getWebContents().getMainFrame())
+                                        .setRenderFrameHost(renderFrameHost)
                                         .build();
                         share(p, extras, shareOrigin);
                         return;
@@ -264,7 +267,7 @@
 
     private void triggerShareWithCanonicalUrlResolved(
             final WindowAndroid window,
-            final WebContents webContents,
+            final @Nullable WebContents webContents,
             final String title,
             final @NonNull GURL visibleUrl,
             final GURL canonicalUrl,
@@ -277,7 +280,7 @@
                         .setSaveLastUsed(!shareDirectly)
                         .setShareDirectly(shareDirectly)
                         .setIsUrlOfVisiblePage(true)
-                        .setRenderFrameHost(webContents.getMainFrame())
+                        .setRenderFrameHost(webContents != null ? webContents.getMainFrame() : null)
                         .build(),
                 shareOrigin);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java
index 25fc363..511d399 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java
@@ -125,4 +125,9 @@
         if (mTab.isDestroyed() || mTab.isClosing()) return;
         mTab.loadUrl(loadUrlParams);
     }
+
+    @Override
+    public boolean isCustomTab() {
+        return mTab.isCustomTab();
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 73d29f65..836685ab 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -147,6 +147,7 @@
 import org.chromium.chrome.browser.history.BrowsingHistoryBridge;
 import org.chromium.chrome.browser.history.HistoryItem;
 import org.chromium.chrome.browser.history.TestBrowsingHistoryObserver;
+import org.chromium.chrome.browser.lifecycle.InflationObserver;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.page_load_metrics.PageLoadMetrics;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
@@ -1256,6 +1257,55 @@
         histograms.pollInstrumentationThreadUntilSatisfied();
     }
 
+    /** Tests that we don't leak the tab when finishing early. */
+    @Test
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.CCT_EARLY_NAV})
+    public void testEarlyFinish() throws Exception {
+        CallbackHelper helper = new CallbackHelper();
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    ApplicationStatus.registerStateListenerForAllActivities(
+                            new ActivityStateListener() {
+                                @Override
+                                public void onActivityStateChange(
+                                        Activity activity, @ActivityState int state) {
+                                    if (!(activity instanceof CustomTabActivity)) return;
+                                    if (state == ActivityState.CREATED) {
+                                        ((CustomTabActivity) activity)
+                                                .getLifecycleDispatcher()
+                                                .register(
+                                                        new InflationObserver() {
+                                                            @Override
+                                                            public void onPreInflationStartup() {
+                                                                activity.finish();
+                                                            }
+
+                                                            @Override
+                                                            public void onPostInflationStartup() {}
+                                                        });
+                                    }
+                                    if (state == ActivityState.DESTROYED) {
+                                        Assert.assertTrue(
+                                                ((CustomTabActivity) activity)
+                                                        .getActivityTab()
+                                                        .isDestroyed());
+                                        helper.notifyCalled();
+                                    }
+                                }
+                            });
+                });
+
+        CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait();
+        Context context = ApplicationProvider.getApplicationContext();
+        Intent intent = CustomTabsIntentTestUtils.createMinimalCustomTabIntent(context, mTestPage);
+        final var token = SessionHolder.getSessionHolderFromIntent(intent);
+        Assert.assertTrue(connection.newSession(token.getSessionAsCustomTab()));
+        mCustomTabActivityTestRule.launchActivity(intent);
+
+        helper.waitForNext();
+    }
+
     /** Tests that calling warmup() is optional without prerendering. */
     @Test
     @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
index f399c330..b232359 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
@@ -785,25 +785,37 @@
         intended(IntentMatchers.hasData("https://test.plusaddresses.google.com"));
     }
 
+    /**
+     * Verifies that when the feature flag is enabled, the PREF_HOME_MODULES_CONFIG is removed from
+     * the settings page.
+     */
     @Test
     @SmallTest
-    public void testHomeModulesConfigSettingsWithCustomizableModule() {
+    @EnableFeatures(ChromeFeatureList.NEW_TAB_PAGE_CUSTOMIZATION)
+    public void testHomeModulesConfigSettingsWithCustomizableModuleWhileFeatureTurnOn() {
+        when(mHomeModulesConfigManager.hasModuleShownInSettings()).thenReturn(true);
+        HomeModulesConfigManager.setInstanceForTesting(mHomeModulesConfigManager);
+        startSettings();
+        assertSettingsNotExists(MainSettings.PREF_HOME_MODULES_CONFIG);
+    }
+
+    /**
+     * Verifies that when the feature flag is disabled by default, the PREF_HOME_MODULES_CONFIG is
+     * removed from the settings page, only if hasModuleShownInSettings returns false.
+     */
+    @Test
+    @SmallTest
+    public void testHomeModulesConfigSettingsWithCustomizableModuleWhileFeatureTurnOff() {
         when(mHomeModulesConfigManager.hasModuleShownInSettings()).thenReturn(true);
         HomeModulesConfigManager.setInstanceForTesting(mHomeModulesConfigManager);
         startSettings();
         assertSettingsExists(
                 MainSettings.PREF_HOME_MODULES_CONFIG, HomeModulesConfigSettings.class);
-    }
 
-    @Test
-    @SmallTest
-    public void testHomeModulesConfigSettingsWithoutCustomizableModule() {
         when(mHomeModulesConfigManager.hasModuleShownInSettings()).thenReturn(false);
         HomeModulesConfigManager.setInstanceForTesting(mHomeModulesConfigManager);
         startSettings();
-        Assert.assertNull(
-                "Home modules config setting should not be shown on automotive",
-                mMainSettings.findPreference(MainSettings.PREF_HOME_MODULES_CONFIG));
+        assertSettingsNotExists(MainSettings.PREF_HOME_MODULES_CONFIG);
     }
 
     @Test
@@ -1087,6 +1099,11 @@
         return pref;
     }
 
+    private void assertSettingsNotExists(String prefKey) {
+        Preference pref = mMainSettings.findPreference(prefKey);
+        Assert.assertNull(pref);
+    }
+
     private boolean supportAddressBarSettings() {
         return ToolbarPositionController.isToolbarPositionCustomizationEnabled(
                 ContextUtils.getApplicationContext(), false);
diff --git a/chrome/android/junit/BUILD.gn b/chrome/android/junit/BUILD.gn
index ee74ec43..754b1555 100644
--- a/chrome/android/junit/BUILD.gn
+++ b/chrome/android/junit/BUILD.gn
@@ -1274,7 +1274,7 @@
       "src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java",
       "src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java",
       "src/org/chromium/chrome/browser/webauthn/AuthenticatorIncognitoConfirmationBottomsheetTest.java",
-      "src/org/chromium/content/browser/webid/IdentityCredentialsDelegateTest.java",
+      "src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegateTest.java",
     ]
 
     deps = [
diff --git a/chrome/android/junit/src/org/chromium/content/browser/webid/IdentityCredentialsDelegateTest.java b/chrome/android/junit/src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegateTest.java
similarity index 83%
rename from chrome/android/junit/src/org/chromium/content/browser/webid/IdentityCredentialsDelegateTest.java
rename to chrome/android/junit/src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegateTest.java
index cf7b0f8..c387be0 100644
--- a/chrome/android/junit/src/org/chromium/content/browser/webid/IdentityCredentialsDelegateTest.java
+++ b/chrome/android/junit/src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegateTest.java
@@ -11,11 +11,11 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import static org.chromium.content.browser.webid.IdentityCredentialsDelegate.BUNDLE_KEY_IDENTITY_TOKEN;
-import static org.chromium.content.browser.webid.IdentityCredentialsDelegate.BUNDLE_KEY_PROVIDER_DATA;
-import static org.chromium.content.browser.webid.IdentityCredentialsDelegate.BUNDLE_KEY_REQUEST_JSON;
-import static org.chromium.content.browser.webid.IdentityCredentialsDelegate.EXTRA_CREDENTIAL_DATA;
-import static org.chromium.content.browser.webid.IdentityCredentialsDelegate.EXTRA_GET_CREDENTIAL_RESPONSE;
+import static org.chromium.content.browser.webid.DigitalCredentialsPresentationDelegate.BUNDLE_KEY_IDENTITY_TOKEN;
+import static org.chromium.content.browser.webid.DigitalCredentialsPresentationDelegate.BUNDLE_KEY_PROVIDER_DATA;
+import static org.chromium.content.browser.webid.DigitalCredentialsPresentationDelegate.BUNDLE_KEY_REQUEST_JSON;
+import static org.chromium.content.browser.webid.DigitalCredentialsPresentationDelegate.EXTRA_CREDENTIAL_DATA;
+import static org.chromium.content.browser.webid.DigitalCredentialsPresentationDelegate.EXTRA_GET_CREDENTIAL_RESPONSE;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -34,12 +34,12 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.content.browser.webid.IdentityCredentialsDelegate.DigitalCredential;
 
-/** Unit tests for {@link IdentityCredentialsDelegate}. */
+/** Unit tests for {@link DigitalCredentialsPresentationDelegate}. */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(
         manifest = Config.NONE,
         sdk = {Build.VERSION_CODES.TIRAMISU, Build.VERSION_CODES.UPSIDE_DOWN_CAKE})
-public class IdentityCredentialsDelegateTest {
+public class DigitalCredentialsPresentationDelegateTest {
     private static final String INTENT_HELPER_EXTRA_CREDENTIAL_TYPE =
             "androidx.identitycredentials.EXTRA_CREDENTIAL_TYPE";
     private static final String INTENT_HELPER_EXTRA_CREDENTIAL_DATA =
@@ -107,7 +107,7 @@
         Bundle bundle = packageIntentInResponseBundle(intent);
 
         DigitalCredential credential =
-                IdentityCredentialsDelegate.extractDigitalCredentialFromResponseBundle(
+                DigitalCredentialsPresentationDelegate.extractDigitalCredentialFromResponseBundle(
                         Activity.RESULT_OK, bundle);
 
         assertNotNull(credential);
@@ -123,7 +123,7 @@
         Bundle bundle = packageIntentInResponseBundle(intent);
 
         DigitalCredential extractedCredential =
-                IdentityCredentialsDelegate.extractDigitalCredentialFromResponseBundle(
+                DigitalCredentialsPresentationDelegate.extractDigitalCredentialFromResponseBundle(
                         Activity.RESULT_OK, bundle);
 
         assertNotNull(extractedCredential);
@@ -140,7 +140,7 @@
         Bundle bundle = packageIntentInResponseBundle(intent);
 
         DigitalCredential extractedCredential =
-                IdentityCredentialsDelegate.extractDigitalCredentialFromResponseBundle(
+                DigitalCredentialsPresentationDelegate.extractDigitalCredentialFromResponseBundle(
                         Activity.RESULT_OK, bundle);
 
         // Since the modern format contains a protocol, it is preferred.
@@ -158,7 +158,7 @@
         Bundle bundle = packageIntentInResponseBundle(intent);
 
         DigitalCredential extractedCredential =
-                IdentityCredentialsDelegate.extractDigitalCredentialFromResponseBundle(
+                DigitalCredentialsPresentationDelegate.extractDigitalCredentialFromResponseBundle(
                         Activity.RESULT_OK, bundle);
 
         // Since the modern format doesn't contain a protocol, the full response is considered as
@@ -178,8 +178,9 @@
         assertThrows(
                 NullPointerException.class,
                 () -> {
-                    IdentityCredentialsDelegate.extractDigitalCredentialFromResponseBundle(
-                            Activity.RESULT_OK, bundle);
+                    DigitalCredentialsPresentationDelegate
+                            .extractDigitalCredentialFromResponseBundle(
+                                    Activity.RESULT_OK, bundle);
                 });
     }
 
@@ -193,8 +194,9 @@
         assertThrows(
                 JSONException.class,
                 () -> {
-                    IdentityCredentialsDelegate.extractDigitalCredentialFromResponseBundle(
-                            Activity.RESULT_OK, bundle);
+                    DigitalCredentialsPresentationDelegate
+                            .extractDigitalCredentialFromResponseBundle(
+                                    Activity.RESULT_OK, bundle);
                 });
     }
-}
+}
\ No newline at end of file
diff --git a/chrome/android/modules/readaloud/public/BUILD.gn b/chrome/android/modules/readaloud/public/BUILD.gn
index c22002e3e..8f8731e 100644
--- a/chrome/android/modules/readaloud/public/BUILD.gn
+++ b/chrome/android/modules/readaloud/public/BUILD.gn
@@ -6,6 +6,7 @@
 
 android_library("java") {
   sources = [
+    "java/src/org/chromium/chrome/modules/readaloud/Feedback.java",
     "java/src/org/chromium/chrome/modules/readaloud/Playback.java",
     "java/src/org/chromium/chrome/modules/readaloud/PlaybackArgs.java",
     "java/src/org/chromium/chrome/modules/readaloud/PlaybackListener.java",
diff --git a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/Feedback.java b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/Feedback.java
new file mode 100644
index 0000000..3286657
--- /dev/null
+++ b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/Feedback.java
@@ -0,0 +1,70 @@
+// Copyright 2025 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.modules.readaloud;
+
+import org.chromium.build.annotations.NullMarked;
+import java.util.Locale;
+
+/** Enum definitions for Audio Overviews feedback args. */
+@NullMarked
+public class Feedback {
+    public enum FeedbackType {
+        NONE(0),
+        POSITIVE(1),
+        NEGATIVE(2);
+
+        private final int mValue;
+
+        FeedbackType(int value) {
+            mValue = value;
+        }
+
+        public int getValue() {
+            return mValue;
+        }
+
+        public static FeedbackType fromValue(int value) {
+            for (FeedbackType type : values()) {
+                if (type.getValue() == value) {
+                    return type;
+                }
+            }
+            throw new IllegalArgumentException("Unknown value: " + value);
+        }
+    }
+
+    public enum NegativeFeedbackReason {
+        NOT_FACTUALLY_CORRECT(0),
+        BAD_VOICE(1),
+        NOT_ENGAGING(2),
+        OFFENSIVE(3),
+        TECHNICAL_ISSUE(4),
+        OTHER(5);
+
+        private final int mValue;
+
+        NegativeFeedbackReason(int value) {
+            mValue = value;
+        }
+
+        public int getValue() {
+            return mValue;
+        }
+
+        public static NegativeFeedbackReason fromValue(int value) {
+            for (NegativeFeedbackReason reason : values()) {
+                if (reason.getValue() == value) {
+                    return reason;
+                }
+            }
+            throw new IllegalArgumentException("Unknown value: " + value);
+        }
+
+        @Override
+        public String toString() {
+          return String.format(Locale.US, "%s (%d)", this.name(), this.getValue());
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackArgs.java b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackArgs.java
index 81555f1..b79fcf9 100644
--- a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackArgs.java
+++ b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackArgs.java
@@ -104,64 +104,6 @@
         }
     }
 
-    public enum FeedbackType {
-        NONE(0),
-        POSITIVE(1),
-        NEGATIVE(2);
-
-        private final int mValue;
-
-        FeedbackType(int value) {
-            mValue = value;
-        }
-
-        public int getValue() {
-            return mValue;
-        }
-
-        public static FeedbackType fromValue(int value) {
-            for (FeedbackType type : values()) {
-                if (type.getValue() == value) {
-                    return type;
-                }
-            }
-            throw new IllegalArgumentException("Unknown value: " + value);
-        }
-    }
-
-    public enum NegativeFeedbackReason {
-        NOT_FACTUALLY_CORRECT(0),
-        BAD_VOICE(1),
-        NOT_ENGAGING(2),
-        OFFENSIVE(3),
-        TECHNICAL_ISSUE(4),
-        OTHER(5);
-
-        private final int mValue;
-
-        NegativeFeedbackReason(int value) {
-            mValue = value;
-        }
-
-        public int getValue() {
-            return mValue;
-        }
-
-        public static NegativeFeedbackReason fromValue(int value) {
-            for (NegativeFeedbackReason reason : values()) {
-                if (reason.getValue() == value) {
-                    return reason;
-                }
-            }
-            throw new IllegalArgumentException("Unknown value: " + value);
-        }
-
-        @Override
-        public String toString() {
-          return String.format(Locale.US, "%s (%d)", this.name(), this.getValue());
-        }
-    }
-
     /**
      * Encapsulates info about a TTS voice that can be used for playback. Tone is only relevant for
      * the UI, language and voiceId are required for the server request.
diff --git a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/Player.java b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/Player.java
index 8e976af5..d6cde8a 100644
--- a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/Player.java
+++ b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/Player.java
@@ -16,8 +16,8 @@
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.user_education.UserEducationHelper;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.NegativeFeedbackReason;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
+import org.chromium.chrome.modules.readaloud.Feedback.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackModeSelectionEnablementStatus;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
diff --git a/chrome/app/chrome_exe_main_mac.cc b/chrome/app/chrome_exe_main_mac.cc
index a465d38..ff265a14 100644
--- a/chrome/app/chrome_exe_main_mac.cc
+++ b/chrome/app/chrome_exe_main_mac.cc
@@ -78,22 +78,7 @@
 // As quite a hack of a workaround, the offset of the arm64 slice within the fat
 // main executable is influenced to land at the desired location by introducing
 // padding to the x86_64 slice that precedes it. The arm64 slice needs to remain
-// at offset 288kB (since 123.0.6312.10). The signed x86_64 slice size has grown
-// from 249072 in 122.0.6261.143 to 269712 in 123.0.6312.10 (including 56kB of
-// current padding). Future versions need to be padded to be in the range
-// (262144, 278528] so that the arm64 slice that follows it begins at offset
-// 288kB. To allow for the possibility of small-scale (up to +/-8kB) size
-// changes, the target size for the padded x86_64 slice is 270336 bytes.
-
-// As of this writing 125.0.6378.0's x86_64 slice has shrunk back down to
-// 249312. To make up the 78368-byte difference, 76kB (77824 bytes) of padding
-// is added to the x86_64 slice to ensure that its size is stable, causing the
-// arm64 slice to land where it needs to be when universalized. This padding
-// needs to be added to the thin form of the x86_64 image before being fed to
-// universalizer.py. Why 77824 bytes and not 78368? To keep it an even multiple
-// of linker pages (not machine pages: linker pages are 4kB for lld targeting
-// x86_64 and 16kB for ld64 targeting x86_64, but Chrome uses lld). In any case,
-// I'll make up some of the 544-byte difference with one more weird trick below.
+// at offset 288kB (since 123.0.6312.10).
 //
 // There are several terrible ways to insert this padding into the x86_64 image.
 // Best would be something that considers the size of the x86_64 image without
@@ -109,38 +94,42 @@
 // suppresses the warning, but does not prevent the compiler or linker from
 // removing it.
 //
-// For example, 76kB of padding causes the unsigned linker output to grow by
-// 76kB precisely, but the signed output will grow by slightly more. This is
-// because the code signature's code directory contains SHA-1 and SHA-256
-// hashes of each 4kB code signing page (note, not machine pages or linker
-// pages) in the image, adding 20 and 32 bytes each (macOS 12.0.1
-// https://github.com/apple-oss-distributions/Security/blob/main/OSX/libsecurity_codesigning/lib/signer.cpp#L298
-// Security::CodeSigning::SecCodeSigner::Signer::prepare). For the 76kB
-// addition, the code signature grows by (76 / 4) * (20 + 32) = 998 bytes, thus
-// the total size of the linker output grows by 76kB + 998 = 78822 bytes. It is
-// not possible to control this any more granularly: if the buffer were sized at
-// 76kB - 998 = 76826 bytes, it would either cause no change in the space
-// allocated to the __TEXT segment (due to padding for alignment) or would cause
-// the segment to shrink by a linker page (note, not a code signing or machine
-// page) which would which would cause the linker output to shrink by the same
-// amount and would be absolutely undesirable. Luckily, the net growth of 78822
-// bytes is almost at the target of 78368. In any event, having the signed
-// x86_64 slice sized at 269792 bytes instead of 270336 should not be a problem.
-// So long as the size is in the proper 16kB range, the 16kB alignment for the
-// arm64 slice that follows it in the fat file will cause it to appear at the
-// desired 288kB.
+// The arm64 slice will be 16kB-aligned, so as long as the signed x86_64 slice
+// ends anywhere in the offset range (272kB, 288kB], the desired alignment will
+// be preserved. The x86_64 slice begins at offset 16kB (the fat header precedes
+// it, and it is also 16kB-aligned), so the signed x86_64 slice’s size must be
+// in the range (256kB, 272kB] in order for the slice’s end to be in the
+// required range of offsets. To allow for small amounts of growth and
+// shrinkage, the signed x86_64 slice’s size should target the middle of this
+// range, or 264kB.
+//
+// At build time, the signed slice’s size is not known. Although subject to
+// change, recent (2025-05, 138.0.7160) code signatures for official builds of
+// the correct size introduce 22656 extra bytes beyond the size of the unsigned
+// slice. With this signature length in mind, the size target for the unsigned
+// x86_64 slice is 264kB - 22656 = 247680.
+//
+// With an unpadded unsigned size of 27024, (247680 - 27024) = 220656 bytes of
+// padding are desirable. The padding can only be introduced with 4kB precision,
+// so 216kB of padding is introduced.
 //
 // If the main executable has a significant change in size, this will need to be
-// revised. Hopefully a more elegant solution will become apparent before that's
-// required.
-#if !defined(DCHECK_ALWAYS_ON)
-__attribute__((used)) const char kGrossPaddingForCrbug1300598[64 * 1024] = {};
-#else
-// DCHECK builds are larger and therefore require less padding. See
-// https://crbug.com/1394196 for the calculations, and
-// https://crbug.com/357698332 for further follow-up.
-__attribute__((used)) const char kGrossPaddingForCrbug1300598[44 * 1024] = {};
-#endif  // !defined(DCHECK_ALWAYS_ON)
+// revised.
+//
+// If you’re here because of an InvalidAppGeometryException (checked at code
+// signing time), recalculate the required padding for the x86_64 slice: take
+// the reported signed x86_64 slice’s size reported by lipo -detailed_info and
+// subtract 264k (270336) from it. If positive, remove padding in 4kB
+// increments, and if negative, add padding in 4kB increments. The objective is
+// to arrive at a signed x86_64 slice whose size is as close to 264kB as
+// possible.
+//
+// (Each 4kB page added or removed here will result in slightly more than 4kB
+// added or removed from the signed slice: it’s actually 4kB plus 32 bytes, 4128
+// bytes total, accounting for both the padding and the additional SHA-256 hash
+// incorporated into the code signature. The difference is <1% and can be
+// ignored in most cases.)
+__attribute__((used)) const char kGrossPaddingForCrbug1300598[216 * 1024] = {};
 #endif
 
 [[noreturn]] void FatalError(const char* format, ...) {
diff --git a/chrome/app/chrome_main_mac.mm b/chrome/app/chrome_main_mac.mm
index 4136ae2..a5348f7 100644
--- a/chrome/app/chrome_main_mac.mm
+++ b/chrome/app/chrome_main_mac.mm
@@ -83,7 +83,8 @@
         chrome::GetFrameworkBundlePath());
 
     NSBundle* base_bundle = chrome::OuterAppBundle();
-    base::apple::SetBaseBundleID(base_bundle.bundleIdentifier.UTF8String);
+    base::apple::SetBaseBundleIDOverride(
+        base::SysNSStringToUTF8(base_bundle.bundleIdentifier));
 
     base::FilePath child_exe_path =
         chrome::GetFrameworkBundlePath().Append("Helpers").Append(
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index cd15610c..28c343d 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1014,13 +1014,13 @@
       </if>
 
       <!-- Installer Downloader infobar -->
-      <message name="IDS_INSTALLER_DOWNLOADER_DISCLAIMER" desc=" Installer downloader infobar message for downloading the Chromium installer.">
+      <message name="IDS_INSTALLER_DOWNLOADER_DISCLAIMER" desc=" Installer downloader infobar message for downloading the Chromium installer." translateable="false">
         Download the Chromium Installer.
       </message>
-      <message name="IDS_INSTALLER_DOWNLOADER_LINK_TEXT" desc="Link text for the installer downloader infobar, 'Learn More'.">
+      <message name="IDS_INSTALLER_DOWNLOADER_LINK_TEXT" desc="Link text for the installer downloader infobar, 'Learn More'."  translateable="false">
         Learn More
       </message>
-      <message name="IDS_INSTALLER_DOWNLOADER_BUTTON_LABEL" desc="Button label for the installer downloader infobar to download the Chromium installer.">
+      <message name="IDS_INSTALLER_DOWNLOADER_BUTTON_LABEL" desc="Button label for the installer downloader infobar to download the Chromium installer."  translateable="false">
         Download Chromium Installer
       </message>
 
diff --git a/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_BUTTON_LABEL.png.sha1 b/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_BUTTON_LABEL.png.sha1
deleted file mode 100644
index aafc32e..0000000
--- a/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_BUTTON_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-cadb34df7af2db33457e7b335d26fc4443ffc33a
\ No newline at end of file
diff --git a/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_DISCLAIMER.png.sha1 b/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_DISCLAIMER.png.sha1
deleted file mode 100644
index aafc32e..0000000
--- a/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_DISCLAIMER.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-cadb34df7af2db33457e7b335d26fc4443ffc33a
\ No newline at end of file
diff --git a/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_LINK_TEXT.png.sha1 b/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_LINK_TEXT.png.sha1
deleted file mode 100644
index aafc32e..0000000
--- a/chrome/app/chromium_strings_grd/IDS_INSTALLER_DOWNLOADER_LINK_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-cadb34df7af2db33457e7b335d26fc4443ffc33a
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 488feba..3f1e31a1 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -18073,25 +18073,6 @@
     <message name = "IDS_CHROMELABS_ENABLED_WITH_VARIATION_NAME" desc="Label for combobox option for an enabled variation that will have a description describing what variation is enabled in the placeholder.">
       Enabled – <ph name="VARIATION_NAME">$1<ex>tabs shrink to pinned tab width</ex></ph>
     </message>
-    <!-- ChromeLabs Tab Scrolling -->
-    <message name="IDS_TAB_SCROLLING_EXPERIMENT_NAME" desc="Name for Tab Scrolling experiment">
-      Tab Scrolling
-    </message>
-    <message name="IDS_TAB_SCROLLING_EXPERIMENT_DESCRIPTION" desc="Description for Tab Scrolling experiment">
-      Enables tab strip to scroll left and right when full.
-    </message>
-    <message name="IDS_TABS_SHRINK_TO_PINNED_TAB_WIDTH" desc="Label describing tab behavior will shrink to pinned tab width">
-      Tabs shrink to pinned tab width
-    </message>
-    <message name="IDS_TABS_SHRINK_TO_MEDIUM_WIDTH" desc="Label describing tab behavior will shrink to medium width">
-      Tabs shrink to a medium width
-    </message>
-    <message name="IDS_TABS_SHRINK_TO_LARGE_WIDTH" desc="Label describing tab behavior will shrink to large width">
-      Tabs shrink to a large width
-    </message>
-    <message name="IDS_TABS_DO_NOT_SHRINK" desc="Label describing tab behavior will not shrink">
-      Tabs don't shrink
-    </message>
     <!-- Lens Region Search bubble dialog -->
     <message name="IDS_LENS_REGION_SEARCH_BUBBLE_TEXT" desc="Text that is shown in the Lens Region Search education bubble when starting the feature. Informs the user to drag over the screen to select a region to search with Google Lens.">
       Select an area to search with Lens
@@ -18600,6 +18581,9 @@
       <message name="IDS_IMAGE_COPIED_TOAST_BODY" desc="Text on a toast notification that is shown when an image is successfully copied.">
         Image copied
       </message>
+      <message name="IDS_VIDEO_FRAME_COPIED_TOAST_BODY" desc="Text on a toast notification that is shown when a video frame is successfully copied.">
+        Video frame copied
+      </message>
       <message name="IDS_LINK_COPIED_TO_HIGHLIGHT_TOAST_BODY" desc="Text on a toast notification that is shown when a link to highlight is successfully copied.">
         Link copied to highlight
       </message>
diff --git a/chrome/app/generated_resources_grd/IDS_TABS_DO_NOT_SHRINK.png.sha1 b/chrome/app/generated_resources_grd/IDS_TABS_DO_NOT_SHRINK.png.sha1
deleted file mode 100644
index 4b680fba..0000000
--- a/chrome/app/generated_resources_grd/IDS_TABS_DO_NOT_SHRINK.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-358a467ed714b4949a8660b8dd053fcec129561a
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_LARGE_WIDTH.png.sha1 b/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_LARGE_WIDTH.png.sha1
deleted file mode 100644
index 4b680fba..0000000
--- a/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_LARGE_WIDTH.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-358a467ed714b4949a8660b8dd053fcec129561a
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_MEDIUM_WIDTH.png.sha1 b/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_MEDIUM_WIDTH.png.sha1
deleted file mode 100644
index 4b680fba..0000000
--- a/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_MEDIUM_WIDTH.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-358a467ed714b4949a8660b8dd053fcec129561a
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_PINNED_TAB_WIDTH.png.sha1 b/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_PINNED_TAB_WIDTH.png.sha1
deleted file mode 100644
index 4b680fba..0000000
--- a/chrome/app/generated_resources_grd/IDS_TABS_SHRINK_TO_PINNED_TAB_WIDTH.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-358a467ed714b4949a8660b8dd053fcec129561a
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TAB_SCROLLING_EXPERIMENT_DESCRIPTION.png.sha1 b/chrome/app/generated_resources_grd/IDS_TAB_SCROLLING_EXPERIMENT_DESCRIPTION.png.sha1
deleted file mode 100644
index a9717410..0000000
--- a/chrome/app/generated_resources_grd/IDS_TAB_SCROLLING_EXPERIMENT_DESCRIPTION.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-22e9f21270b9004f7984e3dba0909d6ffeb12a6c
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TAB_SCROLLING_EXPERIMENT_NAME.png.sha1 b/chrome/app/generated_resources_grd/IDS_TAB_SCROLLING_EXPERIMENT_NAME.png.sha1
deleted file mode 100644
index a9717410..0000000
--- a/chrome/app/generated_resources_grd/IDS_TAB_SCROLLING_EXPERIMENT_NAME.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-22e9f21270b9004f7984e3dba0909d6ffeb12a6c
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_VIDEO_FRAME_COPIED_TOAST_BODY.png.sha1 b/chrome/app/generated_resources_grd/IDS_VIDEO_FRAME_COPIED_TOAST_BODY.png.sha1
new file mode 100644
index 0000000..0c31c44
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_VIDEO_FRAME_COPIED_TOAST_BODY.png.sha1
@@ -0,0 +1 @@
+2de3b36871d779469a88ca94090754421b102ee4
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index acd08bc..47d351af 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2544,6 +2544,7 @@
     "//third_party/libyuv",
     "//third_party/metrics_proto",
     "//third_party/re2",
+    "//third_party/search_engines_data:search_engines_scaled_resources_grit",
     "//third_party/webrtc_overrides:webrtc_component",
     "//third_party/widevine/cdm:buildflags",
     "//third_party/widevine/cdm:headers",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 034b997..989d8e44 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6023,9 +6023,6 @@
     {"feed-discofeed-endpoint", flag_descriptions::kFeedDiscoFeedEndpointName,
      flag_descriptions::kFeedDiscoFeedEndpointDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(feed::kDiscoFeedEndpoint)},
-    {"feed-dynamic-colors", flag_descriptions::kFeedDynamicColorsName,
-     flag_descriptions::kFeedDynamicColorsDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(feed::kFeedDynamicColors)},
     {"feed-follow-ui-update", flag_descriptions::kFeedFollowUiUpdateName,
      flag_descriptions::kFeedFollowUiUpdateDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(feed::kFeedFollowUiUpdate)},
@@ -6832,6 +6829,10 @@
      FEATURE_VALUE_TYPE(features::kDynamicColorGamut)},
 #endif
 
+    {"hdr-agtm", flag_descriptions::kHdrAgtmName,
+     flag_descriptions::kHdrAgtmDescription, kOsAll,
+     FEATURE_VALUE_TYPE(features::kHdrAgtm)},
+
     {"memlog", flag_descriptions::kMemlogName,
      flag_descriptions::kMemlogDescription, kOsAll,
      MULTI_VALUE_TYPE(kMemlogModeChoices)},
@@ -10187,6 +10188,13 @@
      FEATURE_VALUE_TYPE(chrome::android::kAndroidNativePagesInNewTab)},
 #endif  // BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(IS_ANDROID)
+    {"android-progress-bar-visual-update",
+     flag_descriptions::kAndroidProgressBarVisualUpdateName,
+     flag_descriptions::kAndroidProgressBarVisualUpdateDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kAndroidProgressBarVisualUpdate)},
+#endif  // BUILDFLAG(IS_ANDROID)
+
 #if BUILDFLAG(IS_CHROMEOS)
     {"enable-missive-storage-config", flag_descriptions::kMissiveStorageName,
      flag_descriptions::kMissiveStorageDescription, kOsCrOS,
@@ -11815,6 +11823,14 @@
      kOsAndroid,
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillThirdPartyModeContentProvider)},
+#endif
+
+#if !BUILDFLAG(IS_ANDROID)
+    {"three-button-password-save-dialog",
+     flag_descriptions::kThreeButtonPasswordSaveDialogName,
+     flag_descriptions::kThreeButtonPasswordSaveDialogDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kThreeButtonPasswordSaveDialog)},
+
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_MAC)
diff --git a/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service.cc b/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service.cc
index 94db948..b3121e6 100644
--- a/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service.cc
+++ b/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service.cc
@@ -994,9 +994,20 @@
 void AXMediaAppUntrustedService::ShowOcrServiceFailedToInitializeMessage() {
   DCHECK_EQ(ocr_status_, OcrStatus::kInitializationFailed);
   ui::AXTreeUpdate document_update;
-  document_update.nodes = CreateStatusNodesWithLandmark();
-  DCHECK_GT(document_update.nodes.size(), 0u);
-  document_update.root_id = document_update.nodes[0].id;
+  ui::AXNodeData& document_root_data = document_update.nodes.emplace_back();
+  document_root_data.id = kDocumentRootNodeId;
+  document_root_data.role = ax::mojom::Role::kPdfRoot;
+  document_update.root_id = document_root_data.id;
+
+  std::vector<ui::AXNodeData> status_nodes;
+  status_nodes = CreateStatusNodesWithLandmark();
+  DCHECK_GE(status_nodes.size(), 1u);
+  document_root_data.child_ids.push_back(status_nodes.at(0).id);
+
+  document_update.nodes.insert(std::end(document_update.nodes),
+                               std::begin(status_nodes),
+                               std::end(status_nodes));
+
   UpdateDocumentTree(document_update);
 }
 
diff --git a/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service_browsertest.cc b/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service_browsertest.cc
index 1da2884d..b1063d7e 100644
--- a/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service_browsertest.cc
+++ b/chrome/browser/accessibility/media_app/ax_media_app_untrusted_service_browsertest.cc
@@ -239,21 +239,22 @@
   EXPECT_TRUE(service_->IsAccessibilityEnabled());
   EXPECT_EQ(
       "AXTree has_parent_tree title=PDF document\n"
-      "id=10000 banner <div> child_ids=10001 offset_container_id=1 (-1, "
+      "id=1 pdfRoot child_ids=10000 (0, 0)-(0, 0)\n"
+      "  id=10000 banner <div> child_ids=10001 offset_container_id=1 (-1, "
       "-1)-(1, 1) text_align=left is_page_breaking_object=true "
       "is_line_breaking_object=true has_aria_attribute=true\n"
-      "  id=10001 status <div> child_ids=10002 offset_container_id=10000 (0, "
+      "    id=10001 status <div> child_ids=10002 offset_container_id=10000 (0, "
       "0)-(1, 1) text_align=left container_relevant=additions text "
       "container_live=polite relevant=additions text live=polite "
       "container_atomic=true container_busy=false atomic=true "
       "is_line_breaking_object=true has_aria_attribute=true\n"
-      "    id=10002 staticText name=This PDF is inaccessible. Couldn't "
+      "      id=10002 staticText name=This PDF is inaccessible. Couldn't "
       "download text extraction files. Please try again later. child_ids=10003 "
       "offset_container_id=10001 (0, 0)-(1, 1) text_align=left "
       "container_relevant=additions text container_live=polite "
       "relevant=additions text live=polite container_atomic=true "
       "container_busy=false atomic=true is_line_breaking_object=true\n"
-      "      id=10003 inlineTextBox name=This PDF is inaccessible. Couldn't "
+      "        id=10003 inlineTextBox name=This PDF is inaccessible. Couldn't "
       "download text extraction files. Please try again later. "
       "offset_container_id=10002 (0, 0)-(1, 1) text_align=left\n",
       service_->GetDocumentTreeToStringForTesting());
@@ -271,21 +272,22 @@
   EXPECT_TRUE(service_->IsAccessibilityEnabled());
   EXPECT_EQ(
       "AXTree has_parent_tree title=PDF document\n"
-      "id=10000 banner <div> child_ids=10001 offset_container_id=1 (-1, "
+      "id=1 pdfRoot child_ids=10000 (0, 0)-(0, 0)\n"
+      "  id=10000 banner <div> child_ids=10001 offset_container_id=1 (-1, "
       "-1)-(1, 1) text_align=left is_page_breaking_object=true "
       "is_line_breaking_object=true has_aria_attribute=true\n"
-      "  id=10001 status <div> child_ids=10002 offset_container_id=10000 (0, "
+      "    id=10001 status <div> child_ids=10002 offset_container_id=10000 (0, "
       "0)-(1, 1) text_align=left container_relevant=additions text "
       "container_live=polite relevant=additions text live=polite "
       "container_atomic=true container_busy=false atomic=true "
       "is_line_breaking_object=true has_aria_attribute=true\n"
-      "    id=10002 staticText name=This PDF is inaccessible. Couldn't "
+      "      id=10002 staticText name=This PDF is inaccessible. Couldn't "
       "download text extraction files. Please try again later. child_ids=10003 "
       "offset_container_id=10001 (0, 0)-(1, 1) text_align=left "
       "container_relevant=additions text container_live=polite "
       "relevant=additions text live=polite container_atomic=true "
       "container_busy=false atomic=true is_line_breaking_object=true\n"
-      "      id=10003 inlineTextBox name=This PDF is inaccessible. Couldn't "
+      "        id=10003 inlineTextBox name=This PDF is inaccessible. Couldn't "
       "download text extraction files. Please try again later. "
       "offset_container_id=10002 (0, 0)-(1, 1) text_align=left\n",
       service_->GetDocumentTreeToStringForTesting());
diff --git a/chrome/browser/android/metrics/uma_session_stats.cc b/chrome/browser/android/metrics/uma_session_stats.cc
index 9d34dc4..919e717d 100644
--- a/chrome/browser/android/metrics/uma_session_stats.cc
+++ b/chrome/browser/android/metrics/uma_session_stats.cc
@@ -300,7 +300,7 @@
   DCHECK(g_browser_process);
 
   g_metrics_consent_for_testing = consent;
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 }
 
 // Starts/stops the MetricsService based on existing consent and upload
diff --git a/chrome/browser/apps/app_service/publishers/chrome_app_deprecation.cc b/chrome/browser/apps/app_service/publishers/chrome_app_deprecation.cc
index f8217ea..41be9a8 100644
--- a/chrome/browser/apps/app_service/publishers/chrome_app_deprecation.cc
+++ b/chrome/browser/apps/app_service/publishers/chrome_app_deprecation.cc
@@ -30,84 +30,135 @@
 
 namespace {
 // TODO(crbug.com/413912653): Split the allowlists per context.
-constexpr auto kUserInstalledAllowlist = base::MakeFixedFlatSet<
-    std::string_view>(
+constexpr auto kCommonAllowlist = base::MakeFixedFlatSet<std::string_view>(
     {"aakfkoilmhehmmadlkedfbcelkbamdkj", "aepgaekjheajlcifmpjcnpbjcencoefn",
      "afoipjmffplafpbfjopglheidddioiai", "afpnehpifljbjjplppeplamalioanmio",
-     "anjihnbmjbbpofafpmklejenkgnjfcdi", "aoijoapjiidlaapoinclpjkmpaeckiff",
-     "aphendncpdekdkepekckjkiloclamieb", "baifnloidiaigliddpkifgokjemcbcei",
-     "bajigdlccokpmeadnhpfhpehdefbgaen", "bbkieeoaobjflkeakhemifofdbbfhnic",
-     "bhfbomkadeplbpgfmiihpglmenahkmao", "bikbageiaongkigeijiahadjbcgindbj",
-     "bnkchehofckdmggiknjidlamlpokbodf", "bpmgmelggoioalpijejanjhbjkfeehbg",
-     "cahbpjmendhigemdnlifkfmdhnipbdil", "cajomgbhgfomgakdejohnkomlblhhlmo",
-     "cdebpoondplobcgjepkgplleeeeojmpa", "cdgdgmknjolkacdiheibdjmidfkooodf",
-     "cedlmaejgblmkmnddjikaagkhbfonihp", "cgpnjolncgemfdgbfokgdbmhpondgjmm",
-     "coomdpjcngcbdefihidllngfemgnmlhh", "dcfnglblnliiebcjiffpnecdkjnomjbl",
-     "demfodeljeofljmbplgpcncaebjmboog", "demlnppodlnndiacjgbijdjnnnoninak",
-     "deokbmklnlnlikckmachjjhgnidefhhg", "dgmhhjhnkhlmooconggnbjhlmpkpliij",
-     "djkbhkgnbiknnlinckcclejmjkddokhl", "djobiocnmcaeodjcdhbhjgjndhiadgod",
-     "eaghkdkaebflfmmhidgnldnncfpknpne", "ealfhldampafeomimeidejkicmipkgkh",
-     "eblkmenpohbbmbelfaggegpjfjokihke", "ecgoodkkapeinahfgidbfknincokmhdg",
-     "efadkfcohfppfffgblnflcakfhfdjiig", "ejbidlmioeopgmjieecjihnlgacicoie",
-     "ejoilaclhpbfooagcjdkkmklhjipgmll", "ekiflcmfallbndjhecchfcipbaajdfhl",
-     "ekigfkofdacepchbgkogfedfapdekjgp", "emejfeljcemojhhcmobdeflgjabpafip",
-     "emlbfhdjchamibhjgcokeipljabljheo", "enfpdhommpcbfiojillmflopkkjbcjmf",
-     "faidilipbonmepcjdkhjfencfaaccgic", "famkiocmnjimafojaajdngnidmgnacme",
-     "fecgcoakonfhepcppcbddeefeoekhbah", "fenegagmedfckampfgjbeoflcpcpdppc",
-     "ffhbnjlppmbnhahkbkcjgapgfinabjgb", "fhohelmkloeoheiminpldlhkdfcmjbfm",
-     "fjdejbdegplidjpkgcblpdibepibfifg", "fmfiolcdkhopmhgjbmlgpfcpfbeneope",
-     "fnbgnnegegboidihpleofgakpegcidim", "fooeehkjmkcohfidagefenolegldgmpp",
-     "gbfihfamagomeondkhooeamjajjadpio", "geopjmggmojbcnjlkcnfbgdniomaioif",
-     "gfajignjkjbleogeegcgjimnkooihmdm", "ggaabodlngcnbdcpkfacegoacchkalmn",
-     "ggddmkhlbkollcjopbnkbbhnikncfena", "gjenjmcioeobmpllaeopaoibabhgcohi",
-     "glcdffonolecglhbodpaeijkhgdfkbon", "gnddkmpjjjcimefninepfmmddpgaaado",
-     "gnogkjfeajjnafijfmffnkgenhnkdnfp", "gpgnoonhefbmngkiafpedbligiiekfcp",
-     "haiffjcadagjlijoggckpgfnoeiflnem", "hanegekdenjamflmdgcbjlobfkijeblp",
-     "hclmbafbgpncekjmadbbcpekilflmkfg", "hgdemhjioannjiccnfgmllghllhpncpm",
-     "hginjgofkfbdfpkjcchdklbkkdbigpna", "hhcgnlnhaapiekdelngjichnccjfkbnc",
-     "hkmlofdlheebfpgfcmgbdjddnoniccno", "hmpdelcfcndndcoldocpdmakeabbihgb",
-     "hnlanngibjpmdolooednhkedmfbdbmhc", "hpdnjcbgolagabfgcgjpicbknmgefakl",
-     "hplnogolijklhfbbfogccgickedplpeo", "iedihkacboebiliakaicmedjmajmjiep",
-     "ighapdcohmkppihdjdejlbkolhbgnlfm", "ihlmfpkjommgamcgofmdmojpeolimlfe",
-     "iiaffmacblgjekhogmghdjfflchkjmmg", "iilndnicahkogiklibnnibmmeikacnfo",
-     "iinmojhiolplpndeijdkfoghkokbfadb", "iiopclfeneoimifgocjnhcjpjgaojhho",
-     "ijdoledcajbpfbkiafmmimjhmkmdppjo", "ikgemedabaijdochaempgdpfebllgfcc",
-     "iknkgipmikbpldmppngljbedofgmanfm", "inaonhfifmcnldmdnlbnfpikjndebkbj",
-     "jfhndkehlkceadabhedbcclclbclhnbh", "jgafcpolgeedpieaadaeeaoanackiina",
-     "jglaiblkoeelgfdabnhpcpdnodjonclf", "jjkgijommndbjlekbalbbiiidnigcgfl",
-     "jjlhmikmcgmheddmlfeckndcedkmcpng", "jjnejapcbafplbdkbombhmmjnafplkon",
-     "jjoncgfekjbknjfejfonaochdpdedbka", "jnnkgopblccifpnkfpfkmdafjebjlhcc",
-     "jnojnnofimbdpeihiddafgagckdlnlpe", "jpmngkkdajjfkdknhbifjbglkckbklee",
-     "kahkblckpdgogkogmfhfnldpjhdpfiia", "kdbdkbbfhghbggpjmpapmobihghkdmkh",
-     "kdndmepchimlohdcdkokdddpbnniijoa", "kenkpdjcfppbccchillfdjkjnejjgand",
-     "kflikliicodcopdhibchdfaninnhbalf", "kfllildicglifipmhpnlmpfbkdponghk",
-     "khpfeaanjngmcnplbdlpegiifgpfgdco", "khplkoflcklpnlofodhlnjeiodbmejoe",
-     "kjceddihhogmglodncbmpembbclhnpda", "kljahdaehfmgddhnibkikcjfppjcjjcn",
-     "kmfbmibhlikajdfjbddlolmdkkbiephg", "lbfgjakkeeccemhonnolnmglmfmccaag",
-     "lemoeliioheohdcoogohonkamhloahbb", "likeoemlchnioaoaklldmcnilhhpjamo",
-     "lknebpkncfibkhjkimejlgppnjgemobn", "lmhpnmjggoibofacnookchiemlihmjdd",
-     "lnnghenlbgaeloipgjlafjhlccipbpnm", "maegcedffmoidlccpjahiglkaacbncnn",
-     "mclaaifjbcglkbdhdkaamamplpjoabih", "mdmkkicfmmkgmpkmkdikhlbggogpicma",
-     "medpmkohocjidlghgmnnkpfigfpddaok", "mhbelemjphdecdagmmengimkkiefmcej",
-     "mhfhafklkbgalhbdihiccegaldefdigp", "mhjpnpdhahbahbjedoihlganncneknfo",
-     "millmignkmpaolllendlllaibmeehohd", "mkjgggeeejocddadcegdhcchhmemokcn",
-     "mndakpenoffnhdmpcpnajekhpbonggeo", "mpjaajdhcmmkeikfdgffdpdjncdnmhmk",
-     "ncjnakhgkcldedboafigaailhldnellf", "ndlolfeihajiaklmehdnajjoblphkppd",
-     "nenolmmehjhaggnamcglapjjdofcojao", "nghoaommfphpdlipedlebgcnmphedhdb",
-     "ngiaihbicdcdflfkhilnaaeobnchggkk", "nhebofpemjfflnkmaneaopjickpliokk",
-     "njofdhegeeccijokfiijflbfajgjclch", "oanbapfpojpdpjppgcmdhcjehacnccbm",
-     "ocnncjgbkiomppnchhbmmcpblifejpco", "odcalbcbcmnepllckjhdndgmolpnddjo",
-     "oefoedhdllfdpfpjhhccdiglflemnfdb", "oflckobdemeldmjddmlbaiaookhhcngo",
-     "ofmlpkdeaopippomdfamngkpnbagkdem", "ogmfbebknnapidhhefcdgmoafjeblnjo",
-     "okaiidkcbkpimeiebofglgpobdafmmeb", "ondpjadajoodngapikdebdcnjcjkeecc",
-     "opalidednimmhdfbcpdmoihhpkahgkak", "pdgbdkbnajhamggjjlhlapedeolflpgm",
-     "pdpgalakpabfiiadeiimoolhemoleaeg", "pgolnnkmmlpbnhfcfbephcnkooejbcep",
-     "pifpopligmljinioeacaccciabhbbpjo", "plhmjahmpikllpphfaoopdhnkbpffccm",
-     "pnclfbefcgmenbbbpljbhbdacgkgkjlh", "ppkfnjlimknmjoaemnpidmdlfchhehel"});
+     "ahpbemfdnadmigmdjhebofmeaonbpfmc", "anjihnbmjbbpofafpmklejenkgnjfcdi",
+     "aoijoapjiidlaapoinclpjkmpaeckiff", "aphendncpdekdkepekckjkiloclamieb",
+     "baifnloidiaigliddpkifgokjemcbcei", "bajigdlccokpmeadnhpfhpehdefbgaen",
+     "bbkieeoaobjflkeakhemifofdbbfhnic", "bhfbomkadeplbpgfmiihpglmenahkmao",
+     "bikbageiaongkigeijiahadjbcgindbj", "bnkchehofckdmggiknjidlamlpokbodf",
+     "bpmgmelggoioalpijejanjhbjkfeehbg", "cahbpjmendhigemdnlifkfmdhnipbdil",
+     "cajomgbhgfomgakdejohnkomlblhhlmo", "cdebpoondplobcgjepkgplleeeeojmpa",
+     "cdgdgmknjolkacdiheibdjmidfkooodf", "cedlmaejgblmkmnddjikaagkhbfonihp",
+     "cgpnjolncgemfdgbfokgdbmhpondgjmm", "coomdpjcngcbdefihidllngfemgnmlhh",
+     "dcfnglblnliiebcjiffpnecdkjnomjbl", "demfodeljeofljmbplgpcncaebjmboog",
+     "demlnppodlnndiacjgbijdjnnnoninak", "deokbmklnlnlikckmachjjhgnidefhhg",
+     "dgmhhjhnkhlmooconggnbjhlmpkpliij", "djkbhkgnbiknnlinckcclejmjkddokhl",
+     "djobiocnmcaeodjcdhbhjgjndhiadgod", "eaghkdkaebflfmmhidgnldnncfpknpne",
+     "ealfhldampafeomimeidejkicmipkgkh", "eblkmenpohbbmbelfaggegpjfjokihke",
+     "ecgoodkkapeinahfgidbfknincokmhdg", "efadkfcohfppfffgblnflcakfhfdjiig",
+     "ejbidlmioeopgmjieecjihnlgacicoie", "ejoilaclhpbfooagcjdkkmklhjipgmll",
+     "ekiflcmfallbndjhecchfcipbaajdfhl", "ekigfkofdacepchbgkogfedfapdekjgp",
+     "emejfeljcemojhhcmobdeflgjabpafip", "emlbfhdjchamibhjgcokeipljabljheo",
+     "enfpdhommpcbfiojillmflopkkjbcjmf", "faidilipbonmepcjdkhjfencfaaccgic",
+     "famkiocmnjimafojaajdngnidmgnacme", "fecgcoakonfhepcppcbddeefeoekhbah",
+     "fenegagmedfckampfgjbeoflcpcpdppc", "ffhbnjlppmbnhahkbkcjgapgfinabjgb",
+     "fhohelmkloeoheiminpldlhkdfcmjbfm", "fjdejbdegplidjpkgcblpdibepibfifg",
+     "fmfiolcdkhopmhgjbmlgpfcpfbeneope", "fnbgnnegegboidihpleofgakpegcidim",
+     "fooeehkjmkcohfidagefenolegldgmpp", "gbfihfamagomeondkhooeamjajjadpio",
+     "geopjmggmojbcnjlkcnfbgdniomaioif", "gfajignjkjbleogeegcgjimnkooihmdm",
+     "ggaabodlngcnbdcpkfacegoacchkalmn", "ggddmkhlbkollcjopbnkbbhnikncfena",
+     "gjenjmcioeobmpllaeopaoibabhgcohi", "glcdffonolecglhbodpaeijkhgdfkbon",
+     "gnddkmpjjjcimefninepfmmddpgaaado", "gnogkjfeajjnafijfmffnkgenhnkdnfp",
+     "gpgnoonhefbmngkiafpedbligiiekfcp", "haiffjcadagjlijoggckpgfnoeiflnem",
+     "hanegekdenjamflmdgcbjlobfkijeblp", "hclmbafbgpncekjmadbbcpekilflmkfg",
+     "hgdemhjioannjiccnfgmllghllhpncpm", "hginjgofkfbdfpkjcchdklbkkdbigpna",
+     "hhcgnlnhaapiekdelngjichnccjfkbnc", "hkmlofdlheebfpgfcmgbdjddnoniccno",
+     "hmpdelcfcndndcoldocpdmakeabbihgb", "hnlanngibjpmdolooednhkedmfbdbmhc",
+     "hpdnjcbgolagabfgcgjpicbknmgefakl", "hplnogolijklhfbbfogccgickedplpeo",
+     "iedihkacboebiliakaicmedjmajmjiep", "ighapdcohmkppihdjdejlbkolhbgnlfm",
+     "ihlmfpkjommgamcgofmdmojpeolimlfe", "iiaffmacblgjekhogmghdjfflchkjmmg",
+     "iilndnicahkogiklibnnibmmeikacnfo", "iinmojhiolplpndeijdkfoghkokbfadb",
+     "iiopclfeneoimifgocjnhcjpjgaojhho", "ijdoledcajbpfbkiafmmimjhmkmdppjo",
+     "ikgemedabaijdochaempgdpfebllgfcc", "iknkgipmikbpldmppngljbedofgmanfm",
+     "inaonhfifmcnldmdnlbnfpikjndebkbj", "jfhndkehlkceadabhedbcclclbclhnbh",
+     "jgafcpolgeedpieaadaeeaoanackiina", "jglaiblkoeelgfdabnhpcpdnodjonclf",
+     "jjkgijommndbjlekbalbbiiidnigcgfl", "jjlhmikmcgmheddmlfeckndcedkmcpng",
+     "jjnejapcbafplbdkbombhmmjnafplkon", "jjoncgfekjbknjfejfonaochdpdedbka",
+     "jnnkgopblccifpnkfpfkmdafjebjlhcc", "jnojnnofimbdpeihiddafgagckdlnlpe",
+     "jpmngkkdajjfkdknhbifjbglkckbklee", "kahkblckpdgogkogmfhfnldpjhdpfiia",
+     "kdbdkbbfhghbggpjmpapmobihghkdmkh", "kdndmepchimlohdcdkokdddpbnniijoa",
+     "kenkpdjcfppbccchillfdjkjnejjgand", "kflikliicodcopdhibchdfaninnhbalf",
+     "kfllildicglifipmhpnlmpfbkdponghk", "khpfeaanjngmcnplbdlpegiifgpfgdco",
+     "khplkoflcklpnlofodhlnjeiodbmejoe", "kjceddihhogmglodncbmpembbclhnpda",
+     "kljahdaehfmgddhnibkikcjfppjcjjcn", "kmfbmibhlikajdfjbddlolmdkkbiephg",
+     "lbfgjakkeeccemhonnolnmglmfmccaag", "lemoeliioheohdcoogohonkamhloahbb",
+     "likeoemlchnioaoaklldmcnilhhpjamo", "lknebpkncfibkhjkimejlgppnjgemobn",
+     "lmhpnmjggoibofacnookchiemlihmjdd", "lnnghenlbgaeloipgjlafjhlccipbpnm",
+     "maegcedffmoidlccpjahiglkaacbncnn", "mclaaifjbcglkbdhdkaamamplpjoabih",
+     "mdmkkicfmmkgmpkmkdikhlbggogpicma", "medpmkohocjidlghgmnnkpfigfpddaok",
+     "mhbelemjphdecdagmmengimkkiefmcej", "mhfhafklkbgalhbdihiccegaldefdigp",
+     "mhjpnpdhahbahbjedoihlganncneknfo", "millmignkmpaolllendlllaibmeehohd",
+     "mkjgggeeejocddadcegdhcchhmemokcn", "mndakpenoffnhdmpcpnajekhpbonggeo",
+     "mpjaajdhcmmkeikfdgffdpdjncdnmhmk", "ncjnakhgkcldedboafigaailhldnellf",
+     "ndlolfeihajiaklmehdnajjoblphkppd", "nenolmmehjhaggnamcglapjjdofcojao",
+     "nghoaommfphpdlipedlebgcnmphedhdb", "ngiaihbicdcdflfkhilnaaeobnchggkk",
+     "nhebofpemjfflnkmaneaopjickpliokk", "njofdhegeeccijokfiijflbfajgjclch",
+     "oanbapfpojpdpjppgcmdhcjehacnccbm", "ocnncjgbkiomppnchhbmmcpblifejpco",
+     "odcalbcbcmnepllckjhdndgmolpnddjo", "oefoedhdllfdpfpjhhccdiglflemnfdb",
+     "oflckobdemeldmjddmlbaiaookhhcngo", "ofmlpkdeaopippomdfamngkpnbagkdem",
+     "ogmfbebknnapidhhefcdgmoafjeblnjo", "okaiidkcbkpimeiebofglgpobdafmmeb",
+     "ondpjadajoodngapikdebdcnjcjkeecc", "opalidednimmhdfbcpdmoihhpkahgkak",
+     "pdgbdkbnajhamggjjlhlapedeolflpgm", "pdpgalakpabfiiadeiimoolhemoleaeg",
+     "pgolnnkmmlpbnhfcfbephcnkooejbcep", "pifpopligmljinioeacaccciabhbbpjo",
+     "plhmjahmpikllpphfaoopdhnkbpffccm", "pnclfbefcgmenbbbpljbhbdacgkgkjlh",
+     "ppkfnjlimknmjoaemnpidmdlfchhehel"});
+
+constexpr auto kUserInstalledAllowlist = base::flat_set<std::string_view>();
 
 // TODO(crbug.com/383754553): Add the finalised list only in M138 builds.
 constexpr auto kKioskSessionAllowlist =
-    base::MakeFixedFlatSet<std::string_view>({""});
+    base::MakeFixedFlatSet<std::string_view>(
+        {"adbijfidmjidmkkpiglnfkflcoblkfmn", "adpfhflbokfdhnfakijgjkpkjegncbpl",
+         "agkggapglfgffelalcfgbjmhkaljnbmn", "alhlkpgheiefedomljbenmkpconkffhk",
+         "amdpebpoiccejfcnocgebkidfmkcdfei", "aoebmljacknghkklaholjkflllbghhnj",
+         "bgldcjbajnkfkephalfogfgklkgjnjeo", "bhcnmihmgdljpnnoobnbdmdjhmfgcpio",
+         "bloholppicibpgbagaebcaagiikicjbn", "cafpcfibibiomlehdnmabchhekeifbgb",
+         "cdomppfkcljjopjijjdchhjfioljaeph", "cgihdamofndnjjlglmcaabdafhmoconf",
+         "ckmkndfplnldgohnnkhmeokbmedpdbjl", "clbgknjcblogheibmcbbdlpkollmgofh",
+         "cmhiajbopgbagidplpiaclnpglmhbhka", "cpbpbhkfonocjjamhjeabdihibkoajlc",
+         "dakemaookmhkdfgcgebakflmhgdhille", "dakmgckkclepfbfeldlgenikiobflcne",
+         "ddhhodggehedggajomidnmgchfnbeold", "dfjigmapgofdlgieniibjdcddlaafick",
+         "dinalfjmfmjkdnkgbbjncgchmghijpgl", "ealpglkmnpenllgjjgdojoemohidefdm",
+         "edhlcbaemfhpoblalbdgeegmaddjdcae", "edpaojhfdnnebhmmhdlpnpomoaopfjod",
+         "efdahhfldoeikfglgolhibmdidbnpneo", "emlbcjpcbepfnhpkiidenlnfdjbghmpg",
+         "fammfnbkkollpklfkachppebochgakjg", "fcichhfeoaikaoldkncmggipmpcbgffg",
+         "fdlpibjfnlhnmeckjjhfiejfdghkmkdm", "gbecpjnejcnafnkgfciepngjcndodann",
+         "gbgncgdjjnelalecmmkimnlgfpmbihog", "gcefeoeohcoeoofmehgjfipjiepodlhg",
+         "gdehbmmmjkddbonbmknngoigkleicpec", "genfdmkliekafjhadcpnhefgicceohhd",
+         "gmdgbdlpbnhiogedlhmdiceocbgcbpgi", "gobhocmdcdpfebockbogdfhnebgmemnf",
+         "hadonmdpeimgfpmmmeldbmjiknnbfdhk", "hbcogfhdhehbfnedbbboiiddpkkjjnio",
+         "hbfbekdejbpmnpilhdnfokjehnianfeb", "hblfbmjdaalalhifaajnnodlkiloengc",
+         "hchdcamjekgapahefjapegmaapggeafe", "hebfpdlglfmneladiogocbflmbjneeoh",
+         "hgkaljnpgngpcgnaonmbdgaolefknaaj", "hhbmmipodfklmbmiaegcbmbfmmfbngnf",
+         "hjbkdjhfdcinjcljfbealemkioalnfao", "ibboejlnnenbhpjfpgoglholgpdjjeff",
+         "icfpencnfmadodjpbbdipkkkljmamine", "iflkfmkmpafjfdkkokpkjpjmiogkdjjl",
+         "igknghlgndjihblholjbbhjbcfilkilb", "ilehifjdadbblbcnciiggmcbmobkikcb",
+         "jamdkebjilnlfjndffcnekbipcfkhmem", "jcgamccimilnfjpbkbadommjcaplmfod",
+         "jefdfinffojbalcgpkigjjijghmllgil", "jiecdjmgkgmgmbonhifblhfaaecnomcj",
+         "jifdnnnegbhoagepoobbmajnpkmcbjig", "jjlmjgfhdijljijikefhmgmhbchnkmnm",
+         "jmiabaaccndlngedakcjbpbgokhgcpfd", "jnlegeoomaehdodfmpmlflpjapebjjjl",
+         "jnlhnplbndpohngdfjhmdinlpofclhdp", "kacodfanpfkedlelnagnbgfbaabjfddn",
+         "kbkcdgjhbdlplagmlcpafgamnapneoba", "kcdfcljkllboedjeoaicmmabopnnaoaa",
+         "kdffphekpginklcnoefcelkjclbjnbmi", "kedeaijhpgoggdafoabafeldkoolemig",
+         "kgoklcfigmpofpbkdglgbhfgpjdjgppl", "kjbdapadhmcgplddmcggjkhacdnpjmod",
+         "kpjcmnnhdgonbhjnfhebgapnkicknmpp", "lfemdemifjedlccfbhpocnicmjlcgmce",
+         "lgpjgoglfmjggeggfelogaboagbcaklg", "lmdoekjmofbfghllkonahbfdcckmgjlf",
+         "lnokaenamkoojjbhehhpggplknlbejmi", "mbkamiddebohpehiafofidepfffpffln",
+         "mfejnceblfpkdodajfohmjimcbipnhhh", "mfgkakkfpnhfmnipnbehiglkjijancnk",
+         "mhboapffkffmmcggindghkakhdhmjcje", "mhdohnfjdghnpjmhnlodibcnjlaeinap",
+         "mkgbgfehlfaioaejpaedngdohcpdpbpd", "nanoidlkencgghkphophigbmnohnbbcb",
+         "nclhjadnjgfjocbnfmlcfnagnieialof", "nddaogoljagaikdogplnajkdggkfmgei",
+         "ngpbnegpinocjhpnppjeppllflpgafkk", "nhlaojpmboioihghmmdbhgcbjgmcicdk",
+         "nickmpjdfebcopckkfjmflblnmijbiom", "nloplhgjobaomjdppnbcdjfgbefifbdo",
+         "obgbgecgadcagmhnanalmklenjajimld", "oblnbnkmblikfegpcngkcbppphcenhjj",
+         "ocljbfllcpgnlnnaommbmaphaagjmkmj", "odjaaghiehpobimgdjjfofmablbaleem",
+         "ofaokfiblaffkgcapcilcehdhlidehcd", "olaaocfpicpjiocmoklnbfpdlbglbadp",
+         "omkghcboodpimaoimdkmigofhjcpmpeb", "omlplbdgdcpaaknjnkodikcklbkhefoh",
+         "oopdabjckchhklpldcdjllmedcdnbdio", "pjdhfcpflabeafmgdpgdfdejbhkdcgja",
+         "pjicdfmcmiihceiefbmioikgkcicochj", "plebdlehcdhfkmidnmfpolcifjngmdck",
+         "pmcgpdpmlgkeociebbpdbppimbeheoli"});
 
 // The std::unordered_set<std::string_view> type has complex constructors and
 // for static variables it would require an exit-time destructor. For these
@@ -123,11 +174,12 @@
 bool IsAllowlisted(std::string_view app_id, AllowlistContext context) {
   switch (context) {
     case AllowlistContext::UserInstalled:
-      return kUserInstalledAllowlist.contains(app_id) ||
+      return kCommonAllowlist.contains(app_id) ||
+             kUserInstalledAllowlist.contains(app_id) ||
              testAllowlistedApps->contains(app_id.data());
     case AllowlistContext::KioskSession:
-      return kKioskSessionAllowlist.contains(app_id) ||
-             kUserInstalledAllowlist.contains(app_id) ||
+      return kCommonAllowlist.contains(app_id) ||
+             kKioskSessionAllowlist.contains(app_id) ||
              testAllowlistedApps->contains(app_id.data());
   }
 }
diff --git a/chrome/browser/apps/app_shim/mach_bootstrap_acceptor.cc b/chrome/browser/apps/app_shim/mach_bootstrap_acceptor.cc
index 2db9ed3..f525d4c 100644
--- a/chrome/browser/apps/app_shim/mach_bootstrap_acceptor.cc
+++ b/chrome/browser/apps/app_shim/mach_bootstrap_acceptor.cc
@@ -13,17 +13,15 @@
 #include "base/apple/foundation_util.h"
 #include "base/apple/mach_logging.h"
 #include "base/mac/scoped_mach_msg_destroy.h"
-#include "base/strings/stringprintf.h"
+#include "base/strings/strcat.h"
 #include "chrome/common/mac/app_mode_common.h"
 
 namespace apps {
 
 MachBootstrapAcceptor::MachBootstrapAcceptor(const std::string& name_fragment,
                                              Delegate* delegate)
-    : server_name_(base::StringPrintf("%s.%s",
-                                      base::apple::BaseBundleID(),
-                                      name_fragment.c_str())
-                       .c_str()),
+    : server_name_(
+          base::StrCat({base::apple::BaseBundleID(), ".", name_fragment})),
       delegate_(delegate) {
   DCHECK(delegate_);
 }
diff --git a/chrome/browser/ash/accessibility/chromevox_panel.cc b/chrome/browser/ash/accessibility/chromevox_panel.cc
index e306efdf..dc3e3ef2 100644
--- a/chrome/browser/ash/accessibility/chromevox_panel.cc
+++ b/chrome/browser/ash/accessibility/chromevox_panel.cc
@@ -12,13 +12,15 @@
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "extensions/common/constants.h"
+#include "ui/accessibility/accessibility_features.h"
 #include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
 namespace {
 
-const char kChromeVoxPanelRelativeUrl[] = "/chromevox/mv2/panel/panel.html";
+const char kChromeVoxMV2PanelRelativeUrl[] = "/chromevox/mv2/panel/panel.html";
+const char kChromeVoxPanelRelativeUrl[] = "/chromevox/mv3/panel/panel.html";
 const char kDisableSpokenFeedbackURLFragment[] = "close";
 const char kFocusURLFragment[] = "focus";
 const char kFullscreenURLFragment[] = "fullscreen";
@@ -100,7 +102,11 @@
 std::string ChromeVoxPanel::GetUrlForContent() {
   std::string url(EXTENSION_PREFIX);
   url += extension_misc::kChromeVoxExtensionId;
-  url += kChromeVoxPanelRelativeUrl;
+  if (::features::IsAccessibilityManifestV3EnabledForChromeVox()) {
+    url += kChromeVoxPanelRelativeUrl;
+  } else {
+    url += kChromeVoxMV2PanelRelativeUrl;
+  }
 
   return url;
 }
diff --git a/chrome/browser/ash/app_list/search/search_metrics_util.h b/chrome/browser/ash/app_list/search/search_metrics_util.h
index 920b2b7..4907cb0 100644
--- a/chrome/browser/ash/app_list/search/search_metrics_util.h
+++ b/chrome/browser/ash/app_list/search/search_metrics_util.h
@@ -11,8 +11,9 @@
 
 namespace app_list {
 
-constexpr char kHistogramPrefix[] = "Apps.AppList.Search.";
-constexpr char kSessionHistogramPrefix[] = "Apps.AppList.Search.Session2.";
+inline constexpr char kHistogramPrefix[] = "Apps.AppList.Search.";
+inline constexpr char kSessionHistogramPrefix[] =
+    "Apps.AppList.Search.Session2.";
 
 // Represents possible error states of the metrics observer itself. These
 // values persist to logs. Entries should not be renumbered and numeric
diff --git a/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h b/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h
index 560a4ea1..e05d240 100644
--- a/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h
+++ b/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h
@@ -50,7 +50,7 @@
   }
 };
 
-constexpr char kRestoredAppWindowCountHistogram[] =
+inline constexpr char kRestoredAppWindowCountHistogram[] =
     "Apps.RestoreArcWindowCount";
 
 // The restoration process might be blocked by some issues, e.g. the memory
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service.h b/chrome/browser/ash/arc/auth/arc_auth_service.h
index 0b2f150..37f7705a 100644
--- a/chrome/browser/ash/arc/auth/arc_auth_service.h
+++ b/chrome/browser/ash/arc/auth/arc_auth_service.h
@@ -42,9 +42,9 @@
 class ArcBridgeService;
 class ArcFetcherBase;
 
-constexpr char kArcAuthRequestAccountInfoResultPrimaryHistogramName[] =
+inline constexpr char kArcAuthRequestAccountInfoResultPrimaryHistogramName[] =
     "Arc.Auth.RequestAccountInfoResult.Primary";
-constexpr char kArcAuthRequestAccountInfoResultSecondaryHistogramName[] =
+inline constexpr char kArcAuthRequestAccountInfoResultSecondaryHistogramName[] =
     "Arc.Auth.RequestAccountInfoResult.Secondary";
 
 // Implementation of ARC authorization.
diff --git a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h
index c608580cc..774c78b 100644
--- a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h
+++ b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h
@@ -17,7 +17,7 @@
 // The prefix for device label used in Android paths for removable media.
 // A removable device mounted at /media/removable/UNTITLED is mounted at
 // /storage/removable_UNTITLED in Android.
-constexpr char kRemovableMediaLabelPrefix[] = "removable_";
+inline constexpr char kRemovableMediaLabelPrefix[] = "removable_";
 
 // Appends |cros_path|'s relative path from "/media/removable" to |android_path|
 // with the altered device label which is used in Android removable media paths.
diff --git a/chrome/browser/ash/arc/idle_manager/arc_background_service_observer.h b/chrome/browser/ash/arc/idle_manager/arc_background_service_observer.h
index cdf0437..60d13c3 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_background_service_observer.h
+++ b/chrome/browser/ash/arc/idle_manager/arc_background_service_observer.h
@@ -12,7 +12,7 @@
 
 namespace arc {
 
-constexpr char kArcBackgroundServiceObserverName[] =
+inline constexpr char kArcBackgroundServiceObserverName[] =
     "ArcBackgroundServiceObserver";
 
 // This class observes ARC app background services state and sets the state to
diff --git a/chrome/browser/ash/arc/idle_manager/arc_cpu_throttle_observer.h b/chrome/browser/ash/arc/idle_manager/arc_cpu_throttle_observer.h
index 5acb72c..b2d66e1 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_cpu_throttle_observer.h
+++ b/chrome/browser/ash/arc/idle_manager/arc_cpu_throttle_observer.h
@@ -10,7 +10,7 @@
 
 namespace arc {
 
-constexpr char kArcCpuThrottleObserverName[] = "ArcCpuThrottleObserver";
+inline constexpr char kArcCpuThrottleObserverName[] = "ArcCpuThrottleObserver";
 
 // This class observes ARCVM's instance throttle and sets the state to active
 // whenever ARCVM is NOT being throttled.
diff --git a/chrome/browser/ash/arc/idle_manager/arc_display_power_observer.h b/chrome/browser/ash/arc/idle_manager/arc_display_power_observer.h
index 782ee135..67c0620d 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_display_power_observer.h
+++ b/chrome/browser/ash/arc/idle_manager/arc_display_power_observer.h
@@ -10,7 +10,8 @@
 
 namespace arc {
 
-constexpr char kArcDisplayPowerObserverName[] = "ArcDisplayPowerObserver";
+inline constexpr char kArcDisplayPowerObserverName[] =
+    "ArcDisplayPowerObserver";
 
 // Listens to ARC power events and enforces throttle when display is off.
 // Enforcing throttle leads to idle state, ultimately leading to doze mode.
diff --git a/chrome/browser/ash/arc/idle_manager/arc_on_battery_observer.h b/chrome/browser/ash/arc/idle_manager/arc_on_battery_observer.h
index 46c096f9..8c2ca42 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_on_battery_observer.h
+++ b/chrome/browser/ash/arc/idle_manager/arc_on_battery_observer.h
@@ -10,7 +10,7 @@
 
 namespace arc {
 
-constexpr char kArcOnBatteryObserverName[] = "ArcOnBatteryObserver";
+inline constexpr char kArcOnBatteryObserverName[] = "ArcOnBatteryObserver";
 
 // Listens ARC power events and lifts CPU throttling when needed.
 class ArcOnBatteryObserver : public ash::ThrottleObserver,
diff --git a/chrome/browser/ash/arc/idle_manager/arc_window_observer.h b/chrome/browser/ash/arc/idle_manager/arc_window_observer.h
index daff266f..dee0a39 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_window_observer.h
+++ b/chrome/browser/ash/arc/idle_manager/arc_window_observer.h
@@ -11,7 +11,7 @@
 
 namespace arc {
 
-constexpr char kArcWindowObserverName[] = "ArcWindowObserver";
+inline constexpr char kArcWindowObserverName[] = "ArcWindowObserver";
 
 // Listens to ARC Window count and blocks Doze Mode when windows are present.
 class ArcWindowObserver : public ash::ThrottleObserver,
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action.h b/chrome/browser/ash/arc/input_overlay/actions/action.h
index 1b323b0..4f83876b 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action.h
+++ b/chrome/browser/ash/arc/input_overlay/actions/action.h
@@ -24,8 +24,8 @@
 
 namespace arc::input_overlay {
 
-constexpr char kKeyboard[] = "keyboard";
-constexpr char kMouse[] = "mouse";
+inline constexpr char kKeyboard[] = "keyboard";
+inline constexpr char kMouse[] = "mouse";
 
 class ActionView;
 class DisplayOverlayController;
diff --git a/chrome/browser/ash/arc/input_overlay/constants.h b/chrome/browser/ash/arc/input_overlay/constants.h
index 708b0b7b..0f28439 100644
--- a/chrome/browser/ash/arc/input_overlay/constants.h
+++ b/chrome/browser/ash/arc/input_overlay/constants.h
@@ -10,15 +10,15 @@
 namespace arc::input_overlay {
 
 // About Json strings.
-constexpr char kMouseAction[] = "mouse_action";
-constexpr char kPrimaryClick[] = "primary_click";
-constexpr char kSecondaryClick[] = "secondary_click";
-constexpr char kHoverMove[] = "hover_move";
-constexpr char kPrimaryDragMove[] = "primary_drag_move";
-constexpr char kSecondaryDragMove[] = "secondary_drag_move";
+inline constexpr char kMouseAction[] = "mouse_action";
+inline constexpr char kPrimaryClick[] = "primary_click";
+inline constexpr char kSecondaryClick[] = "secondary_click";
+inline constexpr char kHoverMove[] = "hover_move";
+inline constexpr char kPrimaryDragMove[] = "primary_drag_move";
+inline constexpr char kSecondaryDragMove[] = "secondary_drag_move";
 
 // System version for AlphaV2+.
-constexpr char kSystemVersionAlphaV2Plus[] = "0.2";
+inline constexpr char kSystemVersionAlphaV2Plus[] = "0.2";
 
 // The coordinates number, including Axis x and y.
 constexpr int kAxisSize = 2;
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_active_audio_throttle_observer.h b/chrome/browser/ash/arc/instance_throttle/arc_active_audio_throttle_observer.h
index 75edc69..03ef325 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_active_audio_throttle_observer.h
+++ b/chrome/browser/ash/arc/instance_throttle/arc_active_audio_throttle_observer.h
@@ -10,7 +10,7 @@
 
 namespace arc {
 
-constexpr char kArcActiveAudioThrottleObserverName[] = "ArcActiveAudio";
+inline constexpr char kArcActiveAudioThrottleObserverName[] = "ArcActiveAudio";
 
 // This class observes active audio streams from ARC and sets the state to
 // active if there is an active audio stream.
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_active_window_throttle_observer.h b/chrome/browser/ash/arc/instance_throttle/arc_active_window_throttle_observer.h
index f8420c2..5d179b1c 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_active_window_throttle_observer.h
+++ b/chrome/browser/ash/arc/instance_throttle/arc_active_window_throttle_observer.h
@@ -10,7 +10,7 @@
 namespace arc {
 
 namespace {
-constexpr char kArcActiveWindowThrottleObserverName[] =
+inline constexpr char kArcActiveWindowThrottleObserverName[] =
     "ArcWindowIsActiveWindow";
 }  // namespace
 
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer.h b/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer.h
index ae366d4..7198e194 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer.h
+++ b/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer.h
@@ -21,7 +21,7 @@
 
 namespace arc {
 
-constexpr char kArcBootPhaseThrottleObserverName[] = "ArcIsBooting";
+inline constexpr char kArcBootPhaseThrottleObserverName[] = "ArcIsBooting";
 
 // This class observes phases of ARC boot and unthrottles the container
 // when ARC is booting or restarting.
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h b/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h
index c842273..00fc7df 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h
+++ b/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h
@@ -12,7 +12,7 @@
 
 namespace arc {
 
-constexpr char kArcPowerThrottleObserverName[] = "ArcPower";
+inline constexpr char kArcPowerThrottleObserverName[] = "ArcPower";
 
 // Listens ARC power events and lifts CPU throttling when needed.
 class ArcPowerThrottleObserver : public ash::ThrottleObserver,
diff --git a/chrome/browser/ash/arc/net/cert_manager_impl.h b/chrome/browser/ash/arc/net/cert_manager_impl.h
index 6fc875b..b12457c 100644
--- a/chrome/browser/ash/arc/net/cert_manager_impl.h
+++ b/chrome/browser/ash/arc/net/cert_manager_impl.h
@@ -20,8 +20,8 @@
 
 // Certificate and private key PKCS #8 PEM headers as described in section 5 and
 // 10 respectively of RFC7468.
-constexpr char kCertificatePEMHeader[] = "CERTIFICATE";
-constexpr char kPrivateKeyPEMHeader[] = "PRIVATE KEY";
+inline constexpr char kCertificatePEMHeader[] = "CERTIFICATE";
+inline constexpr char kPrivateKeyPEMHeader[] = "PRIVATE KEY";
 
 // CertManager imports plain-text certificates and private keys into Chrome OS'
 // key store (chaps).
diff --git a/chrome/browser/ash/arc/policy/arc_policy_util.h b/chrome/browser/ash/arc/policy/arc_policy_util.h
index b7d368ff..5d406a34 100644
--- a/chrome/browser/ash/arc/policy/arc_policy_util.h
+++ b/chrome/browser/ash/arc/policy/arc_policy_util.h
@@ -18,50 +18,56 @@
 namespace arc {
 namespace policy_util {
 
-constexpr char kArcPolicyKeyAccountTypesWithManagementDisabled[] =
+inline constexpr char kArcPolicyKeyAccountTypesWithManagementDisabled[] =
     "accountTypesWithManagementDisabled";
-constexpr char kArcPolicyKeyAlwaysOnVpnPackage[] = "alwaysOnVpnPackage";
-constexpr char kArcPolicyKeyApplications[] = "applications";
-constexpr char kArcPolicyKeyAvailableAppSetPolicyDeprecated[] =
+inline constexpr char kArcPolicyKeyAlwaysOnVpnPackage[] = "alwaysOnVpnPackage";
+inline constexpr char kArcPolicyKeyApplications[] = "applications";
+inline constexpr char kArcPolicyKeyAvailableAppSetPolicyDeprecated[] =
     "availableAppSetPolicy";
-constexpr char kArcPolicyKeyComplianceRules[] = "complianceRules";
-constexpr char kArcPolicyKeyInstallUnknownSourcesDisabled[] =
+inline constexpr char kArcPolicyKeyComplianceRules[] = "complianceRules";
+inline constexpr char kArcPolicyKeyInstallUnknownSourcesDisabled[] =
     "installUnknownSourcesDisabled";
-constexpr char kArcPolicyKeyMaintenanceWindow[] = "maintenanceWindow";
-constexpr char kArcPolicyKeyModifyAccountsDisabled[] = "modifyAccountsDisabled";
-constexpr char kArcPolicyKeyPermissionGrants[] = "permissionGrants";
-constexpr char kArcPolicyKeyPermittedAccessibilityServices[] =
+inline constexpr char kArcPolicyKeyMaintenanceWindow[] = "maintenanceWindow";
+inline constexpr char kArcPolicyKeyModifyAccountsDisabled[] =
+    "modifyAccountsDisabled";
+inline constexpr char kArcPolicyKeyPermissionGrants[] = "permissionGrants";
+inline constexpr char kArcPolicyKeyPermittedAccessibilityServices[] =
     "permittedAccessibilityServices";
-constexpr char kArcPolicyKeyPlayStoreMode[] = "playStoreMode";
-constexpr char kArcPolicyKeyShortSupportMessage[] = "shortSupportMessage";
-constexpr char kArcPolicyKeyStatusReportingSettings[] =
+inline constexpr char kArcPolicyKeyPlayStoreMode[] = "playStoreMode";
+inline constexpr char kArcPolicyKeyShortSupportMessage[] =
+    "shortSupportMessage";
+inline constexpr char kArcPolicyKeyStatusReportingSettings[] =
     "statusReportingSettings";
-constexpr char kArcPolicyKeyWorkAccountAppWhitelistDeprecated[] =
+inline constexpr char kArcPolicyKeyWorkAccountAppWhitelistDeprecated[] =
     "workAccountAppWhitelist";
-constexpr char kArcPolicyKeyGuid[] = "guid";
-constexpr char kArcPolicyKeyApkCacheEnabled[] = "apkCacheEnabled";
-constexpr char kArcPolicyKeyMountPhysicalMediaDisabled[] =
+inline constexpr char kArcPolicyKeyGuid[] = "guid";
+inline constexpr char kArcPolicyKeyApkCacheEnabled[] = "apkCacheEnabled";
+inline constexpr char kArcPolicyKeyMountPhysicalMediaDisabled[] =
     "mountPhysicalMediaDisabled";
-constexpr char kArcPolicyKeyDebuggingFeaturesDisabled[] =
+inline constexpr char kArcPolicyKeyDebuggingFeaturesDisabled[] =
     "debuggingFeaturesDisabled";
-constexpr char kArcPolicyKeyCameraDisabled[] = "cameraDisabled";
-constexpr char kArcPolicyKeyPrintingDisabled[] = "printingDisabled";
-constexpr char kArcPolicyKeyScreenCaptureDisabled[] = "screenCaptureDisabled";
-constexpr char kArcPolicyKeyShareLocationDisabled[] = "shareLocationDisabled";
-constexpr char kArcPolicyKeyUnmuteMicrophoneDisabled[] =
+inline constexpr char kArcPolicyKeyCameraDisabled[] = "cameraDisabled";
+inline constexpr char kArcPolicyKeyPrintingDisabled[] = "printingDisabled";
+inline constexpr char kArcPolicyKeyScreenCaptureDisabled[] =
+    "screenCaptureDisabled";
+inline constexpr char kArcPolicyKeyShareLocationDisabled[] =
+    "shareLocationDisabled";
+inline constexpr char kArcPolicyKeyUnmuteMicrophoneDisabled[] =
     "unmuteMicrophoneDisabled";
-constexpr char kArcPolicyKeySetWallpaperDisabled[] = "setWallpaperDisabled";
-constexpr char kArcPolicyKeyVpnConfigDisabled[] = "vpnConfigDisabled";
-constexpr char kArcPolicyKeyPrivateKeySelectionEnabled[] =
+inline constexpr char kArcPolicyKeySetWallpaperDisabled[] =
+    "setWallpaperDisabled";
+inline constexpr char kArcPolicyKeyVpnConfigDisabled[] = "vpnConfigDisabled";
+inline constexpr char kArcPolicyKeyPrivateKeySelectionEnabled[] =
     "privateKeySelectionEnabled";
-constexpr char kArcPolicyKeyChoosePrivateKeyRules[] = "choosePrivateKeyRules";
-constexpr char kArcPolicyKeyCredentialsConfigDisabled[] =
+inline constexpr char kArcPolicyKeyChoosePrivateKeyRules[] =
+    "choosePrivateKeyRules";
+inline constexpr char kArcPolicyKeyCredentialsConfigDisabled[] =
     "credentialsConfigDisabled";
-constexpr char kArcPolicyKeyCaCerts[] = "caCerts";
-constexpr char kArcPolicyKeyRequiredKeyPairs[] = "requiredKeyPairs";
-constexpr char kArcPolicyKeyDpsInteractionsDisabled[] =
+inline constexpr char kArcPolicyKeyCaCerts[] = "caCerts";
+inline constexpr char kArcPolicyKeyRequiredKeyPairs[] = "requiredKeyPairs";
+inline constexpr char kArcPolicyKeyDpsInteractionsDisabled[] =
     "dpsInteractionsDisabled";
-constexpr char kArcPolicyKeyEnabledSystemAppPackageNames[] =
+inline constexpr char kArcPolicyKeyEnabledSystemAppPackageNames[] =
     "enabledSystemAppPackageNames";
 
 // An app's install type specified by the policy.
diff --git a/chrome/browser/ash/arc/session/arc_disk_space_monitor.h b/chrome/browser/ash/arc/session/arc_disk_space_monitor.h
index a70e33f..83528b5e 100644
--- a/chrome/browser/ash/arc/session/arc_disk_space_monitor.h
+++ b/chrome/browser/ash/arc/session/arc_disk_space_monitor.h
@@ -38,13 +38,14 @@
 constexpr base::TimeDelta kPreStopNotificationReshowInterval = base::Minutes(2);
 
 // Notifier ID of ArcDiskSpaceMonitor.
-const char kDiskSpaceMonitorNotifierId[] = "arc_disk_space_monitor";
+inline constexpr char kDiskSpaceMonitorNotifierId[] = "arc_disk_space_monitor";
 
 // Notification ID of the pre-stop warning notification.
-const char kLowDiskSpacePreStopNotificationId[] = "arc_low_disk_space_pre_stop";
+inline constexpr char kLowDiskSpacePreStopNotificationId[] =
+    "arc_low_disk_space_pre_stop";
 
 // Notification ID of the post-stop warning notification.
-const char kLowDiskSpacePostStopNotificationId[] =
+inline constexpr char kLowDiskSpacePostStopNotificationId[] =
     "arc_low_disk_space_post_stop";
 
 // Monitors disk usage. Requests stopping ARC and/or shows a warning
diff --git a/chrome/browser/ash/attestation/OWNERS b/chrome/browser/ash/attestation/OWNERS
index 8d96a3b..99e55ab 100644
--- a/chrome/browser/ash/attestation/OWNERS
+++ b/chrome/browser/ash/attestation/OWNERS
@@ -1,6 +1,5 @@
 asumaneev@google.com
 drcrash@chromium.org
 dkrahn@chromium.org
-bartfab@chromium.org
 
 per-file *tpm_challenge_key*=drcrash@chromium.org
diff --git a/chrome/browser/ash/attestation/tpm_challenge_key.h b/chrome/browser/ash/attestation/tpm_challenge_key.h
index 63bf512..c074ef6 100644
--- a/chrome/browser/ash/attestation/tpm_challenge_key.h
+++ b/chrome/browser/ash/attestation/tpm_challenge_key.h
@@ -25,7 +25,8 @@
 
 // Prefix for naming machine keys used for SignedPublicKeyAndChallenge when
 // challenging the EMK with register=true.
-const char kEnterpriseMachineKeyForSpkacPrefix[] = "attest-ent-machine-";
+inline constexpr char kEnterpriseMachineKeyForSpkacPrefix[] =
+    "attest-ent-machine-";
 
 //========================= TpmChallengeKeyFactory =============================
 
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_common.h b/chrome/browser/ash/cert_provisioning/cert_provisioning_common.h
index a880134..2c79968 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_common.h
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_common.h
@@ -53,7 +53,7 @@
 // Used for both DeleteVaKey and DeleteVaKeysByPrefix
 using DeleteVaKeyCallback = base::OnceCallback<void(bool)>;
 
-const char kKeyNamePrefix[] = "cert-provis-";
+inline constexpr char kKeyNamePrefix[] = "cert-provis-";
 
 // The type for variables containing an error from DM Server response.
 using CertProvisioningResponseErrorType =
@@ -163,13 +163,14 @@
 // Names of CertProfile fields in a base::Value representation. Must be in sync
 // with policy schema definitions in RequiredClientCertificateForDevice.yaml and
 // RequiredClientCertificateForUser.yaml.
-const char kCertProfileIdKey[] = "cert_profile_id";
-const char kCertProfileNameKey[] = "name";
-const char kCertProfileRenewalPeroidSec[] = "renewal_period_seconds";
-const char kCertProfilePolicyVersionKey[] = "policy_version";
-const char kCertProfileProtocolVersion[] = "protocol_version";
-const char kCertProfileIsVaEnabledKey[] = "enable_remote_attestation_check";
-const char kCertProfileKeyType[] = "key_algorithm";
+inline constexpr char kCertProfileIdKey[] = "cert_profile_id";
+inline constexpr char kCertProfileNameKey[] = "name";
+inline constexpr char kCertProfileRenewalPeroidSec[] = "renewal_period_seconds";
+inline constexpr char kCertProfilePolicyVersionKey[] = "policy_version";
+inline constexpr char kCertProfileProtocolVersion[] = "protocol_version";
+inline constexpr char kCertProfileIsVaEnabledKey[] =
+    "enable_remote_attestation_check";
+inline constexpr char kCertProfileKeyType[] = "key_algorithm";
 
 // The version of the certificate provisioning protocol between ChromeOS client
 // and device management server.
diff --git a/chrome/browser/ash/child_accounts/parent_access_code/parent_access_test_utils.h b/chrome/browser/ash/child_accounts/parent_access_code/parent_access_test_utils.h
index 7d12431..820eef3 100644
--- a/chrome/browser/ash/child_accounts/parent_access_code/parent_access_test_utils.h
+++ b/chrome/browser/ash/child_accounts/parent_access_code/parent_access_test_utils.h
@@ -21,7 +21,8 @@
 namespace parent_access {
 
 // Values used in default parent access code configuration for tests.
-constexpr char kTestSharedSecret[] = "AIfVJHITSar8keeq3779V70dWiS1xbPv8g";
+inline constexpr char kTestSharedSecret[] =
+    "AIfVJHITSar8keeq3779V70dWiS1xbPv8g";
 constexpr base::TimeDelta kDefaultCodeValidity = base::Minutes(10);
 constexpr base::TimeDelta kDefaultClockDrift = base::Minutes(5);
 
diff --git a/chrome/browser/ash/crostini/baguette_installer.cc b/chrome/browser/ash/crostini/baguette_installer.cc
index 48b0a8ede..e3e135d 100644
--- a/chrome/browser/ash/crostini/baguette_installer.cc
+++ b/chrome/browser/ash/crostini/baguette_installer.cc
@@ -24,8 +24,10 @@
 #include "chrome/browser/ash/crostini/baguette_download.h"
 #include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/ash/guest_os/guest_os_dlc_helper.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/ash/components/dbus/concierge/concierge_client.h"
+#include "chromeos/ash/components/dbus/vm_applications/apps.pb.h"
 #include "components/prefs/pref_service.h"
 #include "url/origin.h"
 
@@ -99,11 +101,6 @@
     return;
   }
 
-  GetBaguetteImageUrl(std::move(callback));
-}
-
-void BaguetteInstaller::GetBaguetteImageUrl(
-    BaguetteInstallerCallback callback) {
   auto* concierge_client = ash::ConciergeClient::Get();
   concierge_client->WaitForServiceToBeAvailable(
       base::BindOnce(&BaguetteInstaller::OnConciergeAvailable,
@@ -117,6 +114,42 @@
     std::move(callback).Run(InstallResult::Failure, {});
   }
 
+  // We always need to check if tools DLC is present for kernel, but we may
+  // already have a baguette disk image, check for that first.
+  auto* concierge_client = ash::ConciergeClient::Get();
+  vm_tools::concierge::ListVmDisksRequest request;
+  request.set_vm_name(kCrostiniDefaultVmName);
+  request.set_cryptohome_id(
+      ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
+  request.set_storage_location(vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT);
+  concierge_client->ListVmDisks(
+      request,
+      base::BindOnce(&BaguetteInstaller::OnListVmDisks,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void BaguetteInstaller::OnListVmDisks(
+    BaguetteInstallerCallback callback,
+    std::optional<vm_tools::concierge::ListVmDisksResponse> response) {
+  if (!response) {
+    LOG(WARNING) << "Unable to query disk image status, will potentially "
+                    "re-download baguette image needlessly.";
+  }
+  if (!response->success()) {
+    LOG(WARNING) << "Unsuccessful disk image response, will potentially "
+                    "re-download baguette image needlessly.";
+  }
+
+  if (std::any_of(
+          response->images().cbegin(), response->images().cend(),
+          [](auto image) {
+            return image.vm_type() ==
+                   vm_tools::concierge::VmInfo_VmType::VmInfo_VmType_BAGUETTE;
+          })) {
+    std::move(callback).Run(InstallResult::Success, {});
+    return;
+  }
+
   auto* concierge_client = ash::ConciergeClient::Get();
   concierge_client->GetBaguetteImageUrl(
       base::BindOnce(&BaguetteInstaller::DownloadBaguetteImage,
diff --git a/chrome/browser/ash/crostini/baguette_installer.h b/chrome/browser/ash/crostini/baguette_installer.h
index 9a83770..dbe2bc5 100644
--- a/chrome/browser/ash/crostini/baguette_installer.h
+++ b/chrome/browser/ash/crostini/baguette_installer.h
@@ -64,6 +64,9 @@
 
  private:
   void GetBaguetteImageUrl(BaguetteInstallerCallback callback);
+  void OnListVmDisks(
+      BaguetteInstallerCallback callback,
+      std::optional<vm_tools::concierge::ListVmDisksResponse> response);
   void OnInstallDlc(BaguetteInstallerCallback callback,
                     guest_os::GuestOsDlcInstallation::Result result);
   void OnConciergeAvailable(BaguetteInstallerCallback callback,
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc
index c84c4b6..c19eb22 100644
--- a/chrome/browser/ash/crostini/crostini_manager.cc
+++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -1593,23 +1593,26 @@
 
   if (base::FeatureList::IsEnabled(ash::features::kCrostiniContainerless)) {
     if (!disk_image.has_value()) {
-      LOG(ERROR) << "No disk image was provided for baguette installation";
-      std::move(callback).Run(CrostiniResult::UNKNOWN_ERROR, base::FilePath());
+      // CreateDiskImage will still run, as a no-op that provides the location
+      // of the disk image.
+      LOG(WARNING)
+          << "No disk image was provided for baguette installation, this "
+             "should indicate an existing baguette disk image";
+    } else {
+      request.set_copy_baguette_image(true);
+
+      GetConciergeClient()->CreateDiskImageWithFd(
+          std::move(disk_image.value()), std::move(request),
+          base::BindOnce(&CrostiniManager::OnCreateDiskImage,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
       return;
     }
-
-    request.set_copy_baguette_image(true);
-
-    GetConciergeClient()->CreateDiskImageWithFd(
-        std::move(disk_image.value()), std::move(request),
-        base::BindOnce(&CrostiniManager::OnCreateDiskImage,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-  } else {
-    GetConciergeClient()->CreateDiskImage(
-        std::move(request),
-        base::BindOnce(&CrostiniManager::OnCreateDiskImage,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
+
+  GetConciergeClient()->CreateDiskImage(
+      std::move(request),
+      base::BindOnce(&CrostiniManager::OnCreateDiskImage,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void CrostiniManager::StartTerminaVm(std::string name,
diff --git a/chrome/browser/ash/eche_app/app_id.h b/chrome/browser/ash/eche_app/app_id.h
index a59ff8d0..c4ad819 100644
--- a/chrome/browser/ash/eche_app/app_id.h
+++ b/chrome/browser/ash/eche_app/app_id.h
@@ -9,7 +9,7 @@
 namespace eche_app {
 
 // The Eche's app ID.
-const char kEcheAppId[] = "pcmgemncoejjdplpoaekhfgkckffggcb";
+inline constexpr char kEcheAppId[] = "pcmgemncoejjdplpoaekhfgkckffggcb";
 
 }  // namespace eche_app
 }  // namespace ash
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h
index 2c5ad8c..faf7ce23 100644
--- a/chrome/browser/ash/file_manager/file_tasks.h
+++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -125,9 +125,9 @@
 
 namespace file_manager::file_tasks {
 
-constexpr char kActionIdView[] = "view";
-constexpr char kActionIdSend[] = "send";
-constexpr char kActionIdSendMultiple[] = "send_multiple";
+inline constexpr char kActionIdView[] = "view";
+inline constexpr char kActionIdSend[] = "send";
+inline constexpr char kActionIdSendMultiple[] = "send_multiple";
 
 // Task types as explained in the comment above. Search for <task-type>.
 enum TaskType {
diff --git a/chrome/browser/ash/file_manager/office_file_tasks.h b/chrome/browser/ash/file_manager/office_file_tasks.h
index 870cda4..025c1af7 100644
--- a/chrome/browser/ash/file_manager/office_file_tasks.h
+++ b/chrome/browser/ash/file_manager/office_file_tasks.h
@@ -32,16 +32,18 @@
 
 struct TaskDescriptor;
 
-constexpr char kActionIdQuickOffice[] = "/views/app.html";
-constexpr char kActionIdWebDriveOfficeWord[] = "open-web-drive-office-word";
-constexpr char kActionIdWebDriveOfficeExcel[] = "open-web-drive-office-excel";
-constexpr char kActionIdWebDriveOfficePowerPoint[] =
+inline constexpr char kActionIdQuickOffice[] = "/views/app.html";
+inline constexpr char kActionIdWebDriveOfficeWord[] =
+    "open-web-drive-office-word";
+inline constexpr char kActionIdWebDriveOfficeExcel[] =
+    "open-web-drive-office-excel";
+inline constexpr char kActionIdWebDriveOfficePowerPoint[] =
     "open-web-drive-office-powerpoint";
-constexpr char kActionIdOpenInOffice[] = "open-in-office";
+inline constexpr char kActionIdOpenInOffice[] = "open-in-office";
 
 // UMA metric name that tracks the result of using a MS Office file outside
 // of Drive.
-constexpr char kUseOutsideDriveMetricName[] =
+inline constexpr char kUseOutsideDriveMetricName[] =
     "FileBrowser.OfficeFiles.UseOutsideDrive";
 
 // List of UMA enum values for file system operations that let a user use a
@@ -58,12 +60,12 @@
 
 // UMA metric name that tracks the extension of Office files that are being
 // opened with Drive web.
-constexpr char kOfficeOpenExtensionDriveMetricName[] =
+inline constexpr char kOfficeOpenExtensionDriveMetricName[] =
     "FileBrowser.OfficeFiles.Open.FileType.GoogleDrive";
 
 // UMA metric name that tracks the extension of Office files that are being
 // opened with MS365.
-constexpr char kOfficeOpenExtensionOneDriveMetricName[] =
+inline constexpr char kOfficeOpenExtensionOneDriveMetricName[] =
     "FileBrowser.OfficeFiles.Open.FileType.OneDrive";
 
 // List of file extensions that are used when opening a file with the
diff --git a/chrome/browser/ash/file_manager/virtual_tasks/id_constants.h b/chrome/browser/ash/file_manager/virtual_tasks/id_constants.h
index 3affa0c..d6a8b7a 100644
--- a/chrome/browser/ash/file_manager/virtual_tasks/id_constants.h
+++ b/chrome/browser/ash/file_manager/virtual_tasks/id_constants.h
@@ -7,7 +7,8 @@
 
 namespace file_manager::file_tasks {
 
-constexpr char kActionIdInstallIsolatedWebApp[] = "install-isolated-web-app";
+inline constexpr char kActionIdInstallIsolatedWebApp[] =
+    "install-isolated-web-app";
 
 }  // namespace file_manager::file_tasks
 
diff --git a/chrome/browser/ash/fileapi/file_system_backend.h b/chrome/browser/ash/fileapi/file_system_backend.h
index f20e4c6..5d1593d 100644
--- a/chrome/browser/ash/fileapi/file_system_backend.h
+++ b/chrome/browser/ash/fileapi/file_system_backend.h
@@ -35,8 +35,8 @@
 class FileSystemBackendDelegate;
 class FileAccessPermissions;
 
-constexpr char kSystemMountNameArchive[] = "archive";
-constexpr char kSystemMountNameRemovable[] = "removable";
+inline constexpr char kSystemMountNameArchive[] = "archive";
+inline constexpr char kSystemMountNameRemovable[] = "removable";
 
 // Backend Function called.  Used to control access.
 enum class BackendFunction {
diff --git a/chrome/browser/ash/floating_sso/floating_sso_browsertest.cc b/chrome/browser/ash/floating_sso/floating_sso_browsertest.cc
index edf9f39a..6313183 100644
--- a/chrome/browser/ash/floating_sso/floating_sso_browsertest.cc
+++ b/chrome/browser/ash/floating_sso/floating_sso_browsertest.cc
@@ -15,7 +15,6 @@
 #include "base/notreached.h"
 #include "base/test/bind.h"
 #include "base/test/run_until.h"
-#include "base/test/scoped_chromeos_version_info.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/ash/floating_sso/cookie_sync_conversions.h"
@@ -332,15 +331,6 @@
     commit_future.Get();
   }
 
-  // TODO(crbug.com/379092376): remove this once Floating SSO is out of beta.
-  // This will switch the channel to beta for branded builds, but will be a
-  // no-op for non-branded builds which are always set to
-  // `version_info::Channel::UNKNOWN`. CQ/CI builders which use branded Chrome
-  // rely on this field to set the beta channel, builders for non-branded Chrome
-  // rely on Floating SSO being allowed on unknown channel.
-  base::test::ScopedChromeOSVersionInfo scoped_channel_override_{
-      "CHROMEOS_RELEASE_TRACK=beta-channel", base::Time::Now()};
-
   mojo::Remote<network::mojom::CookieManager> cookie_manager_;
   base::test::ScopedFeatureList feature_list_;
   const GURL kNonGoogleURL = GURL("https://example.com:8888");
diff --git a/chrome/browser/ash/floating_sso/floating_sso_service.cc b/chrome/browser/ash/floating_sso/floating_sso_service.cc
index 79785c5..3c9baa3 100644
--- a/chrome/browser/ash/floating_sso/floating_sso_service.cc
+++ b/chrome/browser/ash/floating_sso/floating_sso_service.cc
@@ -11,11 +11,9 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/values.h"
-#include "base/version_info/channel.h"
 #include "chrome/browser/ash/floating_sso/cookie_sync_conversions.h"
 #include "chrome/browser/ash/floating_sso/floating_sso_sync_bridge.h"
 #include "chrome/browser/ash/floating_workspace/floating_workspace_util.h"
-#include "chrome/common/channel_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/google/core/common/google_util.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -127,16 +125,6 @@
 }
 
 bool FloatingSsoService::IsFloatingSsoEnabled() {
-  // The feature is restricted to Beta users for the initial testing
-  // period. Unknown channel is added to support test execution in CQ,
-  // where tests are run on non-branded builds.
-  // TODO(crbug.com/379092376): remove this once Floating SSO is out of beta.
-  version_info::Channel channel = chrome::GetChannel();
-  if (channel != version_info::Channel::BETA &&
-      channel != version_info::Channel::DEV &&
-      channel != version_info::Channel::UNKNOWN) {
-    return false;
-  }
   // Check FloatingSsoEnabled policy.
   if (!prefs_->GetBoolean(::prefs::kFloatingSsoEnabled)) {
     return false;
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_metrics_util.h b/chrome/browser/ash/floating_workspace/floating_workspace_metrics_util.h
index 001aa8e..aa9fe6f 100644
--- a/chrome/browser/ash/floating_workspace/floating_workspace_metrics_util.h
+++ b/chrome/browser/ash/floating_workspace/floating_workspace_metrics_util.h
@@ -40,24 +40,24 @@
   kMaxValue = kDesksCountCheckFailedError,
 };
 
-constexpr char kFloatingWorkspaceV1Initialized[] =
+inline constexpr char kFloatingWorkspaceV1Initialized[] =
     "Ash.FloatingWorkspace.FloatingWorkspaceV1Initialized";
-constexpr char kFloatingWorkspaceV1RestoredSessionType[] =
+inline constexpr char kFloatingWorkspaceV1RestoredSessionType[] =
     "Ash.FloatingWorkspace.FloatingWorkspaceV1RestoredSessionType";
 
-constexpr char kFloatingWorkspaceV2TemplateLaunchFailureStatus[] =
+inline constexpr char kFloatingWorkspaceV2TemplateLaunchFailureStatus[] =
     "Ash.FloatingWorkspace.TemplateLaunchFailureStatus";
-constexpr char kFloatingWorkspaceV2TemplateLaunchTimedOut[] =
+inline constexpr char kFloatingWorkspaceV2TemplateLaunchTimedOut[] =
     "Ash.FloatingWorkspace.TemplateLaunchTimeOut";
-constexpr char kFloatingWorkspaceV2TemplateLoadTime[] =
+inline constexpr char kFloatingWorkspaceV2TemplateLoadTime[] =
     "Ash.FloatingWorkspace.TemplateLoadTime";
-constexpr char kFloatingWorkspaceV2TemplateSize[] =
+inline constexpr char kFloatingWorkspaceV2TemplateSize[] =
     "Ash.FloatingWorkspace.TemplateSize";
-constexpr char kFloatingWorkspaceV2TemplateUploadStatus[] =
+inline constexpr char kFloatingWorkspaceV2TemplateUploadStatus[] =
     "Ash.FloatingWorkspace.TemplateUploadStatus";
-constexpr char kFloatingWorkspaceV2Initialized[] =
+inline constexpr char kFloatingWorkspaceV2Initialized[] =
     "Ash.FloatingWorkspace.FloatingWorkspaceV2Initialized";
-constexpr char kFloatingWorkspaceV2TemplateNotFound[] =
+inline constexpr char kFloatingWorkspaceV2TemplateNotFound[] =
     "Ash.FloatingWorkspace.TemplateNotFound";
 
 void RecordFloatingWorkspaceV1InitializedHistogram();
diff --git a/chrome/browser/ash/kcer/nssdb_migration/kcer_rollback_helper.h b/chrome/browser/ash/kcer/nssdb_migration/kcer_rollback_helper.h
index 273a19e..f1236405 100644
--- a/chrome/browser/ash/kcer/nssdb_migration/kcer_rollback_helper.h
+++ b/chrome/browser/ash/kcer/nssdb_migration/kcer_rollback_helper.h
@@ -11,7 +11,8 @@
 
 namespace kcer::internal {
 
-const char kNssDbClientCertsRollback[] = "Ash.KcerRollbackHelper.Events";
+inline constexpr char kNssDbClientCertsRollback[] =
+    "Ash.KcerRollbackHelper.Events";
 
 // This enum should be kept in sync with the `NssDbClientCertsRollbackEvent`
 // in tools/metrics/histograms/metadata/ash/enums.xml.
diff --git a/chrome/browser/ash/kcer/nssdb_migration/pkcs12_migrator.h b/chrome/browser/ash/kcer/nssdb_migration/pkcs12_migrator.h
index da7653e..17ab6aa 100644
--- a/chrome/browser/ash/kcer/nssdb_migration/pkcs12_migrator.h
+++ b/chrome/browser/ash/kcer/nssdb_migration/pkcs12_migrator.h
@@ -19,7 +19,8 @@
 
 namespace kcer {
 
-const char kKcerPkcs12MigrationUma[] = "Ash.KcerPkcs12Migration.Events";
+inline constexpr char kKcerPkcs12MigrationUma[] =
+    "Ash.KcerPkcs12Migration.Events";
 
 // Used for UMA counters, the entries should not be re-numbered or re-used.
 enum class KcerPkcs12MigrationEvent {
diff --git a/chrome/browser/ash/login/existing_user_controller_base_test.h b/chrome/browser/ash/login/existing_user_controller_base_test.h
index 40a6609..3a82644 100644
--- a/chrome/browser/ash/login/existing_user_controller_base_test.h
+++ b/chrome/browser/ash/login/existing_user_controller_base_test.h
@@ -22,14 +22,14 @@
 namespace {
 
 const GaiaId::Literal kFirstSAMLUserId("12345");
-const char kFirstSAMLUserEmail[] = "bob@corp.example.com";
+inline constexpr char kFirstSAMLUserEmail[] = "bob@corp.example.com";
 const GaiaId::Literal kSecondSAMLUserId("67891");
-const char kSecondSAMLUserEmail[] = "alice@corp.example.com";
+inline constexpr char kSecondSAMLUserEmail[] = "alice@corp.example.com";
 
 const GaiaId::Literal kFirstGaiaUserId("88888");
-const char kFirstGaiaUserEmail[] = "bob@gaia.example.com";
+inline constexpr char kFirstGaiaUserEmail[] = "bob@gaia.example.com";
 const GaiaId::Literal kSecondGaiaUserId("88884");
-const char kSecondGaiaUserEmail[] = "alice@gaia.example.com";
+inline constexpr char kSecondGaiaUserEmail[] = "alice@gaia.example.com";
 
 }  // namespace
 
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/account_transfer_client_data.h b/chrome/browser/ash/login/oobe_quick_start/connectivity/account_transfer_client_data.h
index 3143610..350c15f 100644
--- a/chrome/browser/ash/login/oobe_quick_start/connectivity/account_transfer_client_data.h
+++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/account_transfer_client_data.h
@@ -13,13 +13,13 @@
 
 namespace ash::quick_start {
 
-constexpr char kClientDataTypeKey[] = "type";
-constexpr char kClientDataChallengeKey[] = "challenge";
-constexpr char kClientDataOriginKey[] = "origin";
-constexpr char kClientDataCrossOriginKey[] = "crossOrigin";
-const char kCtapRequestType[] = "webauthn.get";
+inline constexpr char kClientDataTypeKey[] = "type";
+inline constexpr char kClientDataChallengeKey[] = "challenge";
+inline constexpr char kClientDataOriginKey[] = "origin";
+inline constexpr char kClientDataCrossOriginKey[] = "crossOrigin";
+inline constexpr char kCtapRequestType[] = "webauthn.get";
 
-const char kOrigin[] = "https://accounts.google.com";
+inline constexpr char kOrigin[] = "https://accounts.google.com";
 
 // AccountTransferClientData represents the client_data payload sent during the
 // FIDO Assertion flow, and handles encoding/decoding this payload into various
diff --git a/chrome/browser/ash/login/saml/saml_browsertest.cc b/chrome/browser/ash/login/saml/saml_browsertest.cc
index ea906fd..be41fb7 100644
--- a/chrome/browser/ash/login/saml/saml_browsertest.cc
+++ b/chrome/browser/ash/login/saml/saml_browsertest.cc
@@ -26,7 +26,6 @@
 #include "base/test/gmock_callback_support.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/run_until.h"
-#include "base/test/scoped_chromeos_version_info.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "base/time/time.h"
@@ -2108,9 +2107,6 @@
   }
 
  protected:
-  // TODO(crbug.com/379092376): remove this once Floating SSO is out of beta.
-  base::test::ScopedChromeOSVersionInfo scoped_channel_override_{
-      "CHROMEOS_RELEASE_TRACK=beta-channel", base::Time::Now()};
 
   base::test::ScopedFeatureList feature_list_;
 };
diff --git a/chrome/browser/ash/ownership/ownership_histograms.h b/chrome/browser/ash/ownership/ownership_histograms.h
index c7d77f9..aabf2fea 100644
--- a/chrome/browser/ash/ownership/ownership_histograms.h
+++ b/chrome/browser/ash/ownership/ownership_histograms.h
@@ -78,7 +78,8 @@
 
 // The path for the OwnerKeyUmaEvent histogram. Accessible for testing. Prefer
 // using through the  `RecordOwnerKeyEvent` method.
-constexpr char kOwnerKeyHistogramName[] = "ChromeOS.Ownership.OwnerKeyUmaEvent";
+inline constexpr char kOwnerKeyHistogramName[] =
+    "ChromeOS.Ownership.OwnerKeyUmaEvent";
 
 // Events related to owner key loading, generation and usage that are sent to
 // UMA. Produced from the events above by combining with a success/failure
diff --git a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
index 7101f14..08ca786 100644
--- a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
+++ b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
@@ -414,8 +414,7 @@
       UnifiedConsentServiceFactory::GetForProfile(profile);
   if (consent_service) {
     consent_service->SetUrlKeyedAnonymizedDataCollectionEnabled(true);
-    g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(
-        true);
+    g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
   }
 }
 
diff --git a/chrome/browser/ash/policy/dlp/test/files_policy_notification_manager_test_utils.h b/chrome/browser/ash/policy/dlp/test/files_policy_notification_manager_test_utils.h
index d22f6b4..a0f1521 100644
--- a/chrome/browser/ash/policy/dlp/test/files_policy_notification_manager_test_utils.h
+++ b/chrome/browser/ash/policy/dlp/test/files_policy_notification_manager_test_utils.h
@@ -18,7 +18,7 @@
 namespace policy {
 
 // The id of the first notification FPNM shows.
-constexpr char kNotificationId[] = "dlp_files_0";
+inline constexpr char kNotificationId[] = "dlp_files_0";
 
 // Creates a dummy file in `path`. Returns whether it was created successfully.
 bool CreateDummyFile(const base::FilePath& path);
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_prefs.h b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_prefs.h
index 8a0daf3..7ac9935 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_prefs.h
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_prefs.h
@@ -26,29 +26,29 @@
 
 // A list pref that controls app inventory event reporting for the specified app
 // types.
-constexpr char kReportAppInventory[] = "reporting.report_app_inventory";
+inline constexpr char kReportAppInventory[] = "reporting.report_app_inventory";
 
 // A list pref that controls app usage telemetry reporting for the specified app
 // types.
-constexpr char kReportAppUsage[] = "reporting.report_app_usage";
+inline constexpr char kReportAppUsage[] = "reporting.report_app_usage";
 
 // An integer pref that controls the collection frequency of app usage
 // telemetry.
-constexpr char kReportAppUsageCollectionRateMs[] =
+inline constexpr char kReportAppUsageCollectionRateMs[] =
     "reporting.report_app_usage_collection_rate_ms";
 
 // A list pref used to track installed apps for a particular user.
-constexpr char kAppsInstalled[] = "reporting.apps_installed";
+inline constexpr char kAppsInstalled[] = "reporting.apps_installed";
 
 // Application category types tracked by the app metric reporting user policies.
-constexpr char kAppCategoryAndroidApps[] = "android_apps";
-constexpr char kAppCategoryBrowser[] = "browser";
-constexpr char kAppCategoryChromeAppsExtensions[] =
+inline constexpr char kAppCategoryAndroidApps[] = "android_apps";
+inline constexpr char kAppCategoryBrowser[] = "browser";
+inline constexpr char kAppCategoryChromeAppsExtensions[] =
     "chrome_apps_and_extensions";
-constexpr char kAppCategoryGames[] = "games";
-constexpr char kAppCategoryLinuxApps[] = "linux_apps";
-constexpr char kAppCategoryPWA[] = "progressive_web_apps";
-constexpr char kAppCategorySystemApps[] = "system_apps";
+inline constexpr char kAppCategoryGames[] = "games";
+inline constexpr char kAppCategoryLinuxApps[] = "linux_apps";
+inline constexpr char kAppCategoryPWA[] = "progressive_web_apps";
+inline constexpr char kAppCategorySystemApps[] = "system_apps";
 
 void RegisterProfilePrefs(::user_prefs::PrefRegistrySyncable* registry);
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h b/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h
index 6ce2c06..810fe3e 100644
--- a/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h
+++ b/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h
@@ -103,7 +103,7 @@
 namespace update_checker_internal {
 
 // The tag associated to register |update_check_executor_|.
-constexpr char kUpdateCheckTimerTag[] = "DeviceScheduledUpdateChecker";
+inline constexpr char kUpdateCheckTimerTag[] = "DeviceScheduledUpdateChecker";
 
 // The timeout after which an OS and policies update is aborted.
 constexpr base::TimeDelta kOsAndPoliciesUpdateCheckHardTimeout =
diff --git a/chrome/browser/ash/policy/skyvault/migration_notification_manager.h b/chrome/browser/ash/policy/skyvault/migration_notification_manager.h
index caaf04bb..1eb6a6e 100644
--- a/chrome/browser/ash/policy/skyvault/migration_notification_manager.h
+++ b/chrome/browser/ash/policy/skyvault/migration_notification_manager.h
@@ -33,7 +33,7 @@
 
 namespace policy::local_user_files {
 
-constexpr char kSkyVaultMigrationNotificationId[] = "skyvault-migration";
+inline constexpr char kSkyVaultMigrationNotificationId[] = "skyvault-migration";
 
 // Shows notifications and dialogs related to SkyVault migration status.
 class MigrationNotificationManager : public KeyedService {
diff --git a/chrome/browser/ash/policy/skyvault/test/skyvault_test_utils.h b/chrome/browser/ash/policy/skyvault/test/skyvault_test_utils.h
index 3781613..a1b79d79 100644
--- a/chrome/browser/ash/policy/skyvault/test/skyvault_test_utils.h
+++ b/chrome/browser/ash/policy/skyvault/test/skyvault_test_utils.h
@@ -14,7 +14,7 @@
 
 namespace policy::local_user_files {
 namespace {
-constexpr char kEmail[] = "stub-user@example.com";
+inline constexpr char kEmail[] = "stub-user@example.com";
 }
 
 // Matcher for `SetUserDataStorageWriteEnabledRequest`.
diff --git a/chrome/browser/ash/policy/test_support/policy_test_server_constants.h b/chrome/browser/ash/policy/test_support/policy_test_server_constants.h
index 73b35f3a8..e9124d75 100644
--- a/chrome/browser/ash/policy/test_support/policy_test_server_constants.h
+++ b/chrome/browser/ash/policy/test_support/policy_test_server_constants.h
@@ -8,10 +8,10 @@
 namespace ash::test {
 
 // Test constants used during enrollment wherever appropriate.
-constexpr char kTestDomain[] = "test-domain.com";
-constexpr char kTestRlzBrandCodeKey[] = "TEST";
-constexpr char kTestSerialNumber[] = "111111";
-constexpr char kTestHardwareClass[] = "hw";
+inline constexpr char kTestDomain[] = "test-domain.com";
+inline constexpr char kTestRlzBrandCodeKey[] = "TEST";
+inline constexpr char kTestSerialNumber[] = "111111";
+inline constexpr char kTestHardwareClass[] = "hw";
 
 }  // namespace ash::test
 
diff --git a/chrome/browser/ash/power/ml/user_activity_ukm_logger_helpers.h b/chrome/browser/ash/power/ml/user_activity_ukm_logger_helpers.h
index a2ae20f7..187bf28 100644
--- a/chrome/browser/ash/power/ml/user_activity_ukm_logger_helpers.h
+++ b/chrome/browser/ash/power/ml/user_activity_ukm_logger_helpers.h
@@ -17,15 +17,15 @@
 namespace ml {
 
 // Metrics below are bucketized.
-constexpr char kBatteryPercent[] = "BatteryPercent";
-constexpr char kEventLogDuration[] = "EventLogDuration";
-constexpr char kKeyEventsInLastHour[] = "KeyEventsInLastHour";
-constexpr char kLastActivityTime[] = "LastActivityTime";
-constexpr char kLastUserActivityTime[] = "LastUserActivityTime";
-constexpr char kMouseEventsInLastHour[] = "MouseEventsInLastHour";
-constexpr char kRecentVideoPlayingTime[] = "RecentVideoPlayingTime";
-constexpr char kTimeSinceLastVideoEnded[] = "TimeSinceLastVideoEnded";
-constexpr char kTouchEventsInLastHour[] = "TouchEventsInLastHour";
+inline constexpr char kBatteryPercent[] = "BatteryPercent";
+inline constexpr char kEventLogDuration[] = "EventLogDuration";
+inline constexpr char kKeyEventsInLastHour[] = "KeyEventsInLastHour";
+inline constexpr char kLastActivityTime[] = "LastActivityTime";
+inline constexpr char kLastUserActivityTime[] = "LastUserActivityTime";
+inline constexpr char kMouseEventsInLastHour[] = "MouseEventsInLastHour";
+inline constexpr char kRecentVideoPlayingTime[] = "RecentVideoPlayingTime";
+inline constexpr char kTimeSinceLastVideoEnded[] = "TimeSinceLastVideoEnded";
+inline constexpr char kTouchEventsInLastHour[] = "TouchEventsInLastHour";
 
 // TODO(jiameng): both Bucket and Bucketize are meant for user activity logging,
 // but it's currently used by adaptive brightness. Need to refactor by either
diff --git a/chrome/browser/ash/printing/oauth2/constants.h b/chrome/browser/ash/printing/oauth2/constants.h
index 39fb59f..59f09fb 100644
--- a/chrome/browser/ash/printing/oauth2/constants.h
+++ b/chrome/browser/ash/printing/oauth2/constants.h
@@ -12,12 +12,12 @@
 // This is the (internal) URL which the internet browser must be redirected to
 // to complete the authorization procedure. This URI does not point to a real
 // page.
-constexpr char kRedirectURI[] =
+inline constexpr char kRedirectURI[] =
     "https://chromeos.test/printing/oauth2/redirectURI";
 
 // When required, ChromeOS tries to register to Authorization Server with this
 // name.
-constexpr char kClientName[] = "ChromeOS";
+inline constexpr char kClientName[] = "ChromeOS";
 
 // Max number of parallel OAuth2 sessions with one Authorization Server.
 constexpr size_t kMaxNumberOfSessions = 8;
diff --git a/chrome/browser/ash/settings/device_settings_provider.h b/chrome/browser/ash/settings/device_settings_provider.h
index ac78a53..2e024af 100644
--- a/chrome/browser/ash/settings/device_settings_provider.h
+++ b/chrome/browser/ash/settings/device_settings_provider.h
@@ -32,7 +32,7 @@
 
 namespace ash {
 
-constexpr char kAllowlistCOILFallbackHistogram[] =
+inline constexpr char kAllowlistCOILFallbackHistogram[] =
     "Login.AllowlistCOILFallback";
 
 // CrosSettingsProvider implementation that works with device settings.
diff --git a/chrome/browser/ash/system_logs/iwlwifi_dump_log_source.h b/chrome/browser/ash/system_logs/iwlwifi_dump_log_source.h
index ec2e4522..02aafe5 100644
--- a/chrome/browser/ash/system_logs/iwlwifi_dump_log_source.h
+++ b/chrome/browser/ash/system_logs/iwlwifi_dump_log_source.h
@@ -10,7 +10,7 @@
 
 namespace system_logs {
 
-constexpr char kIwlwifiDumpKey[] = "iwlwifi_dump";
+inline constexpr char kIwlwifiDumpKey[] = "iwlwifi_dump";
 
 // The classes here are used to attach debug dump information from
 // Intel Wi-Fi NICs that will be produced when those NICs have issues
diff --git a/chrome/browser/ash/system_web_apps/apps/personalization_app/keyboard_backlight_color_metrics_provider.h b/chrome/browser/ash/system_web_apps/apps/personalization_app/keyboard_backlight_color_metrics_provider.h
index 8d1a7aaa..fe3ed41 100644
--- a/chrome/browser/ash/system_web_apps/apps/personalization_app/keyboard_backlight_color_metrics_provider.h
+++ b/chrome/browser/ash/system_web_apps/apps/personalization_app/keyboard_backlight_color_metrics_provider.h
@@ -9,8 +9,9 @@
 
 namespace {
 
-constexpr char kPersonalizationKeyboardBacklightColorSettledHistogramName[] =
-    "Ash.Personalization.KeyboardBacklight.Color.Settled";
+inline constexpr char
+    kPersonalizationKeyboardBacklightColorSettledHistogramName[] =
+        "Ash.Personalization.KeyboardBacklight.Color.Settled";
 
 constexpr char
     kPersonalizationKeyboardBacklightDisplayTypeSettledHistogramName[] =
diff --git a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_metrics.h b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_metrics.h
index e7292e1..35676fa 100644
--- a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_metrics.h
+++ b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_metrics.h
@@ -35,15 +35,15 @@
   kMaxValue = kError,
 };
 
-constexpr char kAmbientModeAnimationThemeHistogramName[] =
+inline constexpr char kAmbientModeAnimationThemeHistogramName[] =
     "Ash.Personalization.AmbientMode.AnimationTheme2";
-constexpr char kAmbientModeVideoHistogramName[] =
+inline constexpr char kAmbientModeVideoHistogramName[] =
     "Ash.Personalization.AmbientMode.Video2";
-constexpr char kAmbientModeScreenSaverDurationHistogramName[] =
+inline constexpr char kAmbientModeScreenSaverDurationHistogramName[] =
     "Ash.Personalization.AmbientMode.ScreenSaverDuration";
-constexpr char kPersonalizationThemeColorModeHistogramName[] =
+inline constexpr char kPersonalizationThemeColorModeHistogramName[] =
     "Ash.Personalization.Theme.ColorMode";
-constexpr char kPersonalizationKeyboardBacklightColorHistogramName[] =
+inline constexpr char kPersonalizationKeyboardBacklightColorHistogramName[] =
     "Ash.Personalization.KeyboardBacklight.Color";
 
 // -----------------------------------------------------------------------------
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client_browsertest.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client_browsertest.cc
index 89390ed..83c79dd 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client_browsertest.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client_browsertest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/functional/bind.h"
-#include "chrome/browser/ui/lens/lens_overlay_controller.h"
 #include "chrome/browser/ui/lens/test_lens_search_controller.h"
 #include "chrome/browser/ui/tabs/public/tab_features.h"
 #include "chrome/browser/ui/tabs/test_util.h"
@@ -29,51 +28,20 @@
 
 namespace {
 
-class MockLensOverlayController : public LensOverlayController {
- public:
-  MockLensOverlayController(tabs::TabInterface* tab,
-                            LensSearchController* lens_search_controller,
-                            variations::VariationsClient* variations_client,
-                            signin::IdentityManager* identity_manager,
-                            PrefService* pref_service,
-                            syncer::SyncService* sync_service,
-                            ThemeService* theme_service)
-      : LensOverlayController(tab,
-                              lens_search_controller,
-                              variations_client,
-                              identity_manager,
-                              pref_service,
-                              sync_service,
-                              theme_service) {}
-
-  MOCK_METHOD(void,
-              StartContextualizationWithoutOverlay,
-              (lens::LensOverlayInvocationSource invocation_source),
-              (override));
-};
-
 class MockLensSearchController : public lens::TestLensSearchController {
  public:
   explicit MockLensSearchController(tabs::TabInterface* tab)
       : lens::TestLensSearchController(tab) {}
 
-  std::unique_ptr<LensOverlayController> CreateLensOverlayController(
-      tabs::TabInterface* tab,
-      LensSearchController* lens_search_controller,
-      variations::VariationsClient* variations_client,
-      signin::IdentityManager* identity_manager,
-      PrefService* pref_service,
-      syncer::SyncService* sync_service,
-      ThemeService* theme_service) override {
-    return std::make_unique<MockLensOverlayController>(
-        tab, lens_search_controller, variations_client, identity_manager,
-        pref_service, sync_service, theme_service);
-  }
-
   MOCK_METHOD(void,
               OpenLensOverlay,
               (lens::LensOverlayInvocationSource invocation_source),
               (override));
+
+  MOCK_METHOD(void,
+              StartContextualization,
+              (lens::LensOverlayInvocationSource invocation_source),
+              (override));
 };
 
 class TestTabFeatures : public tabs::TabFeatures {
@@ -133,14 +101,6 @@
             ->lens_search_controller());
   }
 
-  MockLensOverlayController* GetLensOverlayController() {
-    return static_cast<MockLensOverlayController*>(
-        browser()
-            ->GetActiveTabInterface()
-            ->GetTabFeatures()
-            ->lens_overlay_controller());
-  }
-
   // Replaces the client with one using an incognito profile. Note that this is
   // a one-way operation. Once a TEST_F calls this, all interactions with
   // |client_| will be off the record.
@@ -172,8 +132,7 @@
 
 IN_PROC_BROWSER_TEST_F(ChromeAutocompleteProviderClientTest,
                        OpenLensOverlay_DontShow) {
-  EXPECT_CALL(*GetLensOverlayController(),
-              StartContextualizationWithoutOverlay(testing::_))
+  EXPECT_CALL(*GetLensSearchController(), StartContextualization(testing::_))
       .Times(1)
       .WillOnce(testing::Invoke(
           [](lens::LensOverlayInvocationSource invocation_source) {
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java
index af6af4a..ae43532 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java
@@ -96,7 +96,6 @@
                                 restartConfirmationModel,
                                 DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
                 return;
-            case ModalDialogProperties.ButtonType.TITLE_ICON:
             case ModalDialogProperties.ButtonType.POSITIVE_EPHEMERAL:
                 assert false : "Unhandled button click!";
         }
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 681fd32..c001bf4c 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -667,7 +667,7 @@
   g_browser_process->metrics_service()->StartUpdatingLastLiveTimestamp();
 #endif
 
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 }
 
 void ChromeBrowserMainParts::RecordBrowserStartupTime() {
diff --git a/chrome/browser/chromeos/extensions/vpn_provider/OWNERS b/chrome/browser/chromeos/extensions/vpn_provider/OWNERS
index 6e09c747..1beb49d1 100644
--- a/chrome/browser/chromeos/extensions/vpn_provider/OWNERS
+++ b/chrome/browser/chromeos/extensions/vpn_provider/OWNERS
@@ -1,2 +1 @@
-bartfab@chromium.org
 greengrape@google.com
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 22453eb..2994ebe 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -35,6 +35,7 @@
 #include "components/services/patch/content/patch_service.h"
 #include "components/services/unzip/content/unzip_service.h"
 #include "components/update_client/activity_data_service.h"
+#include "components/update_client/crx_cache.h"
 #include "components/update_client/crx_downloader_factory.h"
 #include "components/update_client/net/network_chromium.h"
 #include "components/update_client/patch/patch_impl.h"
@@ -88,7 +89,7 @@
   GetProtocolHandlerFactory() const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   update_client::UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<update_client::CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
  private:
@@ -106,6 +107,7 @@
   scoped_refptr<update_client::CrxDownloaderFactory> crx_downloader_factory_;
   scoped_refptr<update_client::UnzipperFactory> unzip_factory_;
   scoped_refptr<update_client::PatcherFactory> patch_factory_;
+  scoped_refptr<update_client::CrxCache> crx_cache_;
 };
 
 // Allows the component updater to use non-encrypted communication with the
@@ -122,6 +124,12 @@
               pref_service),
           nullptr)) {
   CHECK(pref_service_);
+  base::FilePath path;
+  bool result = base::PathService::Get(chrome::DIR_USER_DATA, &path);
+  crx_cache_ = base::MakeRefCounted<update_client::CrxCache>(
+      result ? std::optional<base::FilePath>(
+                   path.AppendASCII("component_crx_cache"))
+             : std::nullopt);
 }
 
 base::TimeDelta ChromeConfigurator::InitialDelay() const {
@@ -291,13 +299,9 @@
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 }
 
-std::optional<base::FilePath> ChromeConfigurator::GetCrxCachePath() const {
+scoped_refptr<update_client::CrxCache> ChromeConfigurator::GetCrxCache() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::FilePath path;
-  bool result = base::PathService::Get(chrome::DIR_USER_DATA, &path);
-  return result ? std::optional<base::FilePath>(
-                      path.AppendASCII("component_crx_cache"))
-                : std::nullopt;
+  return crx_cache_;
 }
 
 std::optional<base::FilePath> ChromeConfigurator::GetBackgroundDownloaderCache()
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc b/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
index 4823242..70c9d7f 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
+#include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "components/component_updater/component_updater_command_line_config_policy.h"
 #include "components/component_updater/component_updater_switches.h"
@@ -32,6 +33,7 @@
   TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
 
  private:
+  base::test::TaskEnvironment environment_;
   std::unique_ptr<TestingPrefServiceSimple> pref_service_;
 };
 
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java
index 2ec14eb..75b22e3 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java
@@ -4,6 +4,9 @@
 
 package org.chromium.chrome.browser.creator;
 
+import static org.chromium.build.NullUtil.assertNonNull;
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -22,6 +25,9 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.supplier.UnownedUserDataSupplier;
 import org.chromium.base.version_info.VersionInfo;
+import org.chromium.build.annotations.MonotonicNonNull;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.feed.FeedActionDelegate;
 import org.chromium.chrome.browser.feed.FeedContentFirstLoadWatcher;
 import org.chromium.chrome.browser.feed.FeedListContentManager;
@@ -77,20 +83,21 @@
  * Sets up the Coordinator for Cormorant Creator surface.  It is based on the doc at
  * https://chromium.googlesource.com/chromium/src/+/HEAD/docs/ui/android/mvc_simple_list_tutorial.md
  */
+@NullMarked
 public class CreatorCoordinator
         implements FeedContentFirstLoadWatcher, View.OnLayoutChangeListener {
     private final ViewGroup mCreatorViewGroup;
     private CreatorMediator mMediator;
-    private CreatorTabMediator mTabMediator;
+    private @MonotonicNonNull CreatorTabMediator mTabMediator;
     private Activity mActivity;
     private FeedListContentManager mContentManager;
     private UiConfig mUiConfig;
     private RecyclerView mRecyclerView;
     private View mProfileView;
     private ViewGroup mLayoutView;
-    private HybridListRenderer mHybridListRenderer;
-    private FeedSurfaceScope mSurfaceScope;
-    private FeedSurfaceScopeDependencyProviderImpl mDependencyProvider;
+    private @Nullable HybridListRenderer mHybridListRenderer;
+    private @Nullable FeedSurfaceScope mSurfaceScope;
+    private @Nullable FeedSurfaceScopeDependencyProviderImpl mDependencyProvider;
     private PropertyModel mCreatorModel;
 
     private final SnackbarManager mSnackbarManager;
@@ -100,20 +107,20 @@
     private ScrimManager mScrimManager;
     private ViewGroup mBottomSheetContainer;
     private Profile mProfile;
-    private Stream mStream;
+    private @MonotonicNonNull Stream mStream;
     private int mHeaderCount;
 
-    private EmptyBottomSheetObserver mSheetObserver;
-    private ContentView mContentView;
-    private WebContents mWebContents;
+    private @Nullable EmptyBottomSheetObserver mSheetObserver;
+    private @Nullable ContentView mContentView;
+    private @Nullable WebContents mWebContents;
     private int mCurrentMaxViewHeight;
-    private CreatorTabSheetContent mSheetContent;
+    private @Nullable CreatorTabSheetContent mSheetContent;
     private boolean mPeeked;
     private boolean mFullyOpened;
     private WebContentsCreator mCreatorWebContents;
     private NewTabCreator mCreatorOpenTab;
     private final UnownedUserDataSupplier<ShareDelegate> mBottomsheetShareDelegateSupplier;
-    private GURL mBottomSheetUrl;
+    private @MonotonicNonNull GURL mBottomSheetUrl;
     private int mEntryPoint;
 
     private static final String CREATOR_PROFILE_ID = "CreatorProfileView";
@@ -152,6 +159,7 @@
         mProfile = profile;
         mSnackbarManager = snackbarManager;
         mWindowAndroid = windowAndroid;
+        mContentManager = new FeedListContentManager();
         mRecyclerView = setUpView();
         mCreatorWebContents = creatorWebContents;
         mCreatorOpenTab = creatorOpenTab;
@@ -273,7 +281,7 @@
                 mContentManager,
                 /* savedInstanceState= */ null,
                 mSurfaceScope,
-                mHybridListRenderer,
+                assertNonNull(mHybridListRenderer),
                 null,
                 mHeaderCount);
     }
@@ -305,7 +313,6 @@
 
     private RecyclerView setUpView() {
         // TODO(crbug.com/40872531): Refactor NTP naming out of the general Feed code.
-        mContentManager = new FeedListContentManager();
         ProcessScope processScope = FeedSurfaceTracker.getInstance().getXSurfaceProcessScope();
 
         if (processScope != null) {
@@ -325,20 +332,20 @@
         }
 
         RecyclerView view;
-        if (mHybridListRenderer != null) {
-            view =
-                    (RecyclerView)
-                            mHybridListRenderer.bind(
-                                    mContentManager,
-                                    /* viewport= */ null,
-                                    /* shouldUseStaggeredLayout= */ false);
-            view.setId(R.id.creator_feed_stream_recycler_view);
-            view.setClipToPadding(false);
-            view.setBackgroundColor(SemanticColorUtils.getDefaultBgColor(mActivity));
-            view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-        } else {
-            view = null;
-        }
+        // The returned RecyclerView cannot be null; otherwise
+        // CreatorCoordinator#setUpToolbarListener will crash.
+        assert mHybridListRenderer != null;
+        view =
+                (RecyclerView)
+                        mHybridListRenderer.bind(
+                                mContentManager,
+                                /* viewport= */ null,
+                                /* shouldUseStaggeredLayout= */ false);
+        assert view != null;
+        view.setId(R.id.creator_feed_stream_recycler_view);
+        view.setClipToPadding(false);
+        view.setBackgroundColor(SemanticColorUtils.getDefaultBgColor(mActivity));
+        view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
 
         return view;
     }
@@ -451,7 +458,7 @@
             mSheetObserver =
                     new EmptyBottomSheetObserver() {
                         @Override
-                        public void onSheetContentChanged(BottomSheetContent newContent) {
+                        public void onSheetContentChanged(@Nullable BottomSheetContent newContent) {
                             if (newContent != mSheetContent) {
                                 mPeeked = false;
                                 destroyWebContents();
@@ -494,7 +501,11 @@
                             getMaxViewHeight(),
                             intentRequestTracker,
                             mBottomsheetShareDelegateSupplier);
-            mTabMediator.init(mWebContents, mContentView, mSheetContent, mProfile);
+            mTabMediator.init(
+                    assertNonNull(mWebContents),
+                    assertNonNull(mContentView),
+                    mSheetContent,
+                    mProfile);
             mLayoutView.addOnLayoutChangeListener(this);
         }
 
@@ -539,7 +550,7 @@
 
     private void openInNewTab() {
         String url =
-                mBottomSheetUrl.isValid()
+                assumeNonNull(mBottomSheetUrl).isValid()
                         ? mBottomSheetUrl.getSpec()
                         : mCreatorModel.get(CreatorProperties.URL_KEY);
         mBottomSheetController.hideContent(
@@ -584,7 +595,7 @@
             mContentView = null;
         }
 
-        if (mMediator != null) mTabMediator.destroyContent();
+        if (mMediator != null) assumeNonNull(mTabMediator).destroyContent();
 
         mLayoutView.removeOnLayoutChangeListener(this);
         if (mSheetObserver != null) mBottomSheetController.removeObserver(mSheetObserver);
@@ -596,8 +607,9 @@
 
     class ContentChangedListener implements Stream.ContentChangedListener {
         @Override
-        public void onContentChanged(List<FeedContent> feedContents) {
+        public void onContentChanged(@Nullable List<FeedContent> feedContents) {
             if (feedContents == null) return;
+            assert mStream != null;
             boolean hasError = false;
             // Assume native cards beyond the header are errors.
             for (int i = mHeaderCount; i < feedContents.size(); i++) {
@@ -660,7 +672,8 @@
          * @param callback The callback to be invoked to display the final image.
          * @param profile The profile for which favicon service is used.
          */
-        public void loadFavicon(final GURL url, Callback<Drawable> callback, Profile profile) {
+        public void loadFavicon(
+                final GURL url, Callback<Drawable> callback, @Nullable Profile profile) {
             assert profile != null;
             FaviconHelper.FaviconImageCallback imageCallback =
                     (bitmap, iconUrl) -> {
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java
index d9cdcf7..b0179d0 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java
@@ -8,6 +8,7 @@
 
 import android.content.Context;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.feed.FeedServiceBridge;
 import org.chromium.chrome.browser.feed.webfeed.WebFeedBridge;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -16,6 +17,7 @@
  * Sets up the Mediator for Cormorant Creator surface. It is based on the doc at
  * https://chromium.googlesource.com/chromium/src/+/HEAD/docs/ui/android/mvc_simple_list_tutorial.md
  */
+@NullMarked
 public class CreatorMediator {
     private PropertyModel mCreatorModel;
     private final CreatorSnackbarController mCreatorSnackbarController;
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileView.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileView.java
index 1117e5a..31d370d 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileView.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileView.java
@@ -14,9 +14,11 @@
 
 import androidx.appcompat.widget.TooltipCompat;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.widget.ButtonCompat;
 
 /** View class for the Creator Profile section */
+@NullMarked
 public class CreatorProfileView extends LinearLayout {
     private static final int FADE_IN_ANIMATION_DURATION_MS = 150;
     private static final int FADE_OUT_ANIMATION_DURATION_MS = 300;
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileViewBinder.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileViewBinder.java
index b7abf8c..ede38f7 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileViewBinder.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProfileViewBinder.java
@@ -4,10 +4,12 @@
 
 package org.chromium.chrome.browser.creator;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** ViewBinder class for the Creator Profile section */
+@NullMarked
 public class CreatorProfileViewBinder {
     public static void bind(PropertyModel model, CreatorProfileView view, PropertyKey propertyKey) {
         if (CreatorProperties.TITLE_KEY == propertyKey) {
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProperties.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProperties.java
index 0553db8..ee87d0c 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProperties.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorProperties.java
@@ -4,10 +4,12 @@
 
 package org.chromium.chrome.browser.creator;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
 
 /** Properties used for the CreatorModel */
+@NullMarked
 public class CreatorProperties {
     public static final WritableObjectPropertyKey<byte[]> WEB_FEED_ID_KEY =
             new WritableObjectPropertyKey<>();
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorSnackbarController.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorSnackbarController.java
index 4b64758..8340e3f9 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorSnackbarController.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorSnackbarController.java
@@ -9,10 +9,13 @@
 
 import android.content.Context;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 
 /** Controller for showing Creator snackbars */
+@NullMarked
 public class CreatorSnackbarController {
     static final int SNACKBAR_DURATION_MS = 8000;
 
@@ -32,7 +35,7 @@
         mSnackbarController =
                 new SnackbarManager.SnackbarController() {
                     @Override
-                    public void onAction(Object actionData) {
+                    public void onAction(@Nullable Object actionData) {
                         mSnackbarManager.dismissAllSnackbars();
                     }
                 };
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java
index 3585bf8..bfda474 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java
@@ -4,12 +4,16 @@
 
 package org.chromium.chrome.browser.creator;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 
 import androidx.annotation.DrawableRes;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid;
@@ -29,6 +33,7 @@
  * Mediator class for preview tab, responsible for communicating with other objects.
  * This is based on the implementation of bottombar/ephemeraltab/EphemeralTabMediator.java.
  */
+@NullMarked
 public class CreatorTabMediator {
     /** The delay (four video frames) after which the hide progress will be hidden. */
     private static final long HIDE_PROGRESS_BAR_DELAY_MS = (1000 / 60) * 4;
@@ -37,11 +42,11 @@
     private final CreatorCoordinator.FaviconLoader mFaviconLoader;
     private final int mTopControlsHeightDp;
 
-    private WebContents mWebContents;
-    private CreatorTabSheetContent mSheetContent;
-    private WebContentsObserver mWebContentsObserver;
-    private WebContentsDelegateAndroid mWebContentsDelegate;
-    private Profile mProfile;
+    private @Nullable WebContents mWebContents;
+    private @Nullable CreatorTabSheetContent mSheetContent;
+    private @Nullable WebContentsObserver mWebContentsObserver;
+    private @Nullable WebContentsDelegateAndroid mWebContentsDelegate;
+    private @Nullable Profile mProfile;
 
     /** Constructor. */
     public CreatorTabMediator(
@@ -73,11 +78,12 @@
     /** Loads a new URL into the tab and makes it visible. */
     void requestShowContent(GURL url, String title) {
         loadUrl(url);
-        mSheetContent.updateTitle(title);
+        assumeNonNull(mSheetContent).updateTitle(title);
         mBottomSheetController.requestShowContent(mSheetContent, true);
     }
 
     private void loadUrl(GURL url) {
+        assert mWebContents != null && mWebContents.getNavigationController() != null;
         mWebContents.getNavigationController().loadUrl(new LoadUrlParams(url.getSpec()));
     }
 
@@ -88,7 +94,7 @@
                     /** Whether the currently loaded page is an error (interstitial) page. */
                     private boolean mIsOnErrorPage;
 
-                    private GURL mCurrentUrl;
+                    private @Nullable GURL mCurrentUrl;
 
                     @Override
                     public void loadProgressChanged(float progress) {
@@ -119,14 +125,15 @@
 
                     @Override
                     public void titleWasSet(String title) {
-                        mSheetContent.updateTitle(title);
+                        assumeNonNull(mSheetContent).updateTitle(title);
                     }
 
                     @Override
                     public void didFinishNavigationInPrimaryMainFrame(NavigationHandle navigation) {
                         if (navigation.hasCommitted()) {
                             mIsOnErrorPage = navigation.isErrorPage();
-                            mSheetContent.updateURL(getWebContents().getVisibleUrl());
+                            assumeNonNull(mSheetContent)
+                                    .updateURL(assumeNonNull(getWebContents()).getVisibleUrl());
                         } else {
                             // Not viewable contents such as download. Show a toast and close the
                             // tab.
@@ -152,6 +159,7 @@
                     @Override
                     public void visibleSSLStateChanged() {
                         if (mSheetContent == null) return;
+                        assert mWebContents != null;
                         int securityLevel =
                                 SecurityStateModel.getSecurityLevelForWebContents(mWebContents);
                         mSheetContent.setSecurityIcon(getSecurityIconResource(securityLevel));
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
index 1ea1381..f053ebed 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
@@ -16,12 +16,12 @@
 import android.widget.TextView;
 
 import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.UnownedUserDataSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.share.ShareDelegate;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.widget.ChromeTransitionDrawable;
@@ -45,6 +45,7 @@
  * Represents creator tab content and the toolbar, which can be included inside the bottom sheet.
  * This is based on the implementation of bottombar/ephemeraltab/EphemeralTabSheetContent.java.
  */
+@NullMarked
 public class CreatorTabSheetContent implements BottomSheetContent {
     /**
      * The base duration of the settling animation of the sheet. 218 ms is a spec for material
@@ -66,11 +67,11 @@
     private ViewGroup mToolbarView;
     private ViewGroup mSheetContentView;
 
-    private WebContents mWebContents;
-    private ContentView mWebContentView;
+    private @Nullable WebContents mWebContents;
+    private @Nullable ContentView mWebContentView;
     private ThinWebView mThinWebView;
     private FadingShadowView mShadow;
-    private Drawable mCurrentFavicon;
+    private @Nullable Drawable mCurrentFavicon;
     private ImageView mFaviconView;
 
     /**
@@ -109,7 +110,9 @@
      * @param delegate The {@link WebContentsDelegateAndroid} that handles requests on WebContents.
      */
     public void attachWebContents(
-            WebContents webContents, ContentView contentView, WebContentsDelegateAndroid delegate) {
+            WebContents webContents,
+            ContentView contentView,
+            @Nullable WebContentsDelegateAndroid delegate) {
         mWebContents = webContents;
         mWebContentView = contentView;
         if (mWebContentView.getParent() != null) {
@@ -275,13 +278,12 @@
     }
 
     @Override
-    public Integer getBackgroundColor() {
+    public @Nullable Integer getBackgroundColor() {
         return null;
     }
 
-    @Nullable
     @Override
-    public View getToolbarView() {
+    public @Nullable View getToolbarView() {
         return mToolbarView;
     }
 
@@ -339,7 +341,7 @@
     }
 
     @Override
-    public @NonNull String getSheetContentDescription(Context context) {
+    public String getSheetContentDescription(Context context) {
         return context.getString(R.string.ephemeral_tab_sheet_description);
     }
 
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarView.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarView.java
index 22b0b034..8dea4ce 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarView.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarView.java
@@ -18,6 +18,7 @@
 
 import androidx.appcompat.widget.TooltipCompat;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener;
 import org.chromium.ui.widget.ButtonCompat;
 
@@ -25,6 +26,7 @@
 import java.util.Collection;
 
 /** View class for the Creator Toolbar section */
+@NullMarked
 public class CreatorToolbarView extends LinearLayout {
     private static final int ANIMATION_DURATION_MS = 300;
     private TextView mCreatorTitleToolbar;
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarViewBinder.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarViewBinder.java
index e921e21e..9638a93 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarViewBinder.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorToolbarViewBinder.java
@@ -4,10 +4,12 @@
 
 package org.chromium.chrome.browser.creator;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** ViewBinder class for the Creator Toolbar section */
+@NullMarked
 public class CreatorToolbarViewBinder {
     public static void bind(PropertyModel model, CreatorToolbarView view, PropertyKey propertyKey) {
         if (CreatorProperties.TITLE_KEY == propertyKey) {
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/NewTabCreator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/NewTabCreator.java
index f533c68..e1a043e 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/NewTabCreator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/NewTabCreator.java
@@ -4,9 +4,11 @@
 
 package org.chromium.chrome.browser.creator;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.content_public.browser.LoadUrlParams;
 
 /** Interface for opening URLS in a new tab.*/
+@NullMarked
 public interface NewTabCreator {
     /**
      * Creates a new tab with the given params.
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/SignInInterstitialInitiator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/SignInInterstitialInitiator.java
index 7b4d283..d949b1b 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/SignInInterstitialInitiator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/SignInInterstitialInitiator.java
@@ -4,7 +4,10 @@
 
 package org.chromium.chrome.browser.creator;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Interface for showing sign-in insterstitial. */
+@NullMarked
 public interface SignInInterstitialInitiator {
     /** Shows a sign-in interstitial. */
     void showSignInInterstitial();
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/WebContentsCreator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/WebContentsCreator.java
index f319d0e..9989d8b 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/WebContentsCreator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/WebContentsCreator.java
@@ -4,9 +4,11 @@
 
 package org.chromium.chrome.browser.creator;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.content_public.browser.WebContents;
 
 /** Interface to create a web contents*/
+@NullMarked
 public interface WebContentsCreator {
     // create a web contents;
     WebContents createWebContents();
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java
index 0d199d4..9bab51f 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java
@@ -758,6 +758,9 @@
                                 DataSharingStringConfig.StringKey
                                         .LET_ANYONE_JOIN_GROUP_WHEN_FULL_DESCRIPTION,
                                 R.string.collaboration_group_is_full_description)
+                        .setResourceId(
+                                DataSharingStringConfig.StringKey.ACTIVITY_LOGS_TITLE,
+                                R.string.data_sharing_shared_tab_group_activity)
                         .build();
 
         DataSharingManageUiConfig.ManageCallback manageCallback =
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityListCoordinator.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityListCoordinator.java
index 910b2be..edff4551 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityListCoordinator.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityListCoordinator.java
@@ -159,14 +159,14 @@
             ModelList modelList = new ModelList();
             modelList.add(
                     BrowserUiListMenuUtils.buildMenuListItem(
-                            R.string.data_sharing_recent_activity_show_all,
+                            R.string.data_sharing_shared_tab_group_activity,
                             R.id.see_full_activity,
                             0,
                             /* enabled= */ true));
             ListMenu.Delegate delegate =
                     (model) -> {
                         int textId = model.get(ListMenuItemProperties.TITLE_ID);
-                        if (textId == R.string.data_sharing_recent_activity_show_all) {
+                        if (textId == R.string.data_sharing_shared_tab_group_activity) {
                             mShowFullActivityRunnable.run();
                         }
                     };
diff --git a/chrome/browser/devtools/devtools_browsertest.cc b/chrome/browser/devtools/devtools_browsertest.cc
index b1a1010e..fe959fa 100644
--- a/chrome/browser/devtools/devtools_browsertest.cc
+++ b/chrome/browser/devtools/devtools_browsertest.cc
@@ -316,6 +316,12 @@
     host_resolver()->AddRule("*", "127.0.0.1");
   }
 
+  void TearDownOnMainThread() override {
+    if (window_) {
+      CloseDevToolsWindow();
+    }
+  }
+
  protected:
   static std::unique_ptr<net::test_server::HttpResponse> HandleFaviconRequest(
       const net::test_server::HttpRequest& request) {
@@ -375,7 +381,7 @@
   }
 
   void CloseDevToolsWindow() {
-    DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
+    DevToolsWindowTesting::CloseDevToolsWindowSync(window_.ExtractAsDangling());
   }
 
   WebContents* main_web_contents() {
@@ -386,7 +392,7 @@
     return DevToolsWindowTesting::Get(window_)->toolbox_web_contents();
   }
 
-  raw_ptr<DevToolsWindow, DanglingUntriaged> window_;
+  raw_ptr<DevToolsWindow> window_;
 };
 
 class SitePerProcessDevToolsTest : public DevToolsTest {
@@ -472,7 +478,10 @@
     OpenDevToolsWindow(kDebuggerTestPage, is_docked);
     auto runner = base::MakeRefCounted<content::MessageLoopRunner>();
     DevToolsWindowTesting::Get(window_)->SetCloseCallback(
-        runner->QuitClosure());
+        base::BindLambdaForTesting([this, runner]() {
+          window_ = nullptr;
+          runner->Quit();
+        }));
     InjectBeforeUnloadListener(main_web_contents());
     {
       DevToolsWindowBeforeUnloadObserver before_unload_observer(window_);
@@ -780,10 +789,10 @@
   }
 
   void CloseDevToolsWindow() {
-    DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
+    DevToolsWindowTesting::CloseDevToolsWindowSync(window_.ExtractAsDangling());
   }
 
-  raw_ptr<DevToolsWindow, DanglingUntriaged> window_ = nullptr;
+  raw_ptr<DevToolsWindow> window_ = nullptr;
   raw_ptr<extensions::ExtensionRegistrar, DanglingUntriaged>
       extension_registrar_ = nullptr;
   raw_ptr<extensions::ExtensionRegistry, DanglingUntriaged>
@@ -878,10 +887,10 @@
   }
 
   void CloseDevToolsWindow() {
-    DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
+    DevToolsWindowTesting::CloseDevToolsWindowSync(window_.ExtractAsDangling());
   }
 
-  raw_ptr<DevToolsWindow, DanglingUntriaged> window_;
+  raw_ptr<DevToolsWindow> window_;
 };
 
 // Tests that BeforeUnload event gets called on docked devtools if
@@ -2576,12 +2585,16 @@
 IN_PROC_BROWSER_TEST_F(DevToolsTest, MAYBE_AutoAttachToWindowOpen) {
   OpenDevToolsWindow(kWindowOpenTestPage, false);
   DevToolsWindowTesting::Get(window_)->SetOpenNewWindowForPopups(true);
-  DevToolsWindowCreationObserver observer;
-  ASSERT_TRUE(content::ExecJs(GetInspectedTab(),
-                              "window.open('window_open.html', '_blank');"));
-  observer.WaitForLoad();
-  DispatchOnTestSuite(observer.devtools_window(), "waitForDebuggerPaused");
-  DevToolsWindowTesting::CloseDevToolsWindowSync(observer.devtools_window());
+  DevToolsWindow* devtools_window = nullptr;
+  {
+    DevToolsWindowCreationObserver observer;
+    ASSERT_TRUE(content::ExecJs(GetInspectedTab(),
+                                "window.open('window_open.html', '_blank');"));
+    observer.WaitForLoad();
+    devtools_window = observer.devtools_window();
+  }
+  DispatchOnTestSuite(devtools_window, "waitForDebuggerPaused");
+  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
   CloseDevToolsWindow();
 }
 
@@ -3227,7 +3240,7 @@
   LoadLegacyFilesInFrontend(window_);
   RunTestMethod("testLoadResourceForFrontend", url.spec().c_str(),
                 file_url.c_str());
-  DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
+  CloseDevToolsWindow();
 }
 
 // TODO(crbug.com/41435439) Disabled for flakiness.
@@ -3236,7 +3249,7 @@
   window_ = DevToolsWindowTesting::OpenDiscoveryDevToolsWindowSync(
       browser()->profile());
   RunTestMethod("testCreateBrowserContext", url.spec().c_str());
-  DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
+  CloseDevToolsWindow();
 }
 
 // TODO(crbug.com/40708597): Flaky.
@@ -3244,7 +3257,7 @@
   window_ = DevToolsWindowTesting::OpenDiscoveryDevToolsWindowSync(
       browser()->profile());
   RunTestMethod("testDisposeEmptyBrowserContext");
-  DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
+  CloseDevToolsWindow();
 }
 
 // TODO(crbug.com/40689291): Find a better strategy for testing protocol methods
@@ -3254,7 +3267,7 @@
       browser()->profile());
   LoadLegacyFilesInFrontend(window_);
   RunTestMethod("testNewWindowFromBrowserContext");
-  DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
+  CloseDevToolsWindow();
 }
 
 IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsTest, InspectElement) {
@@ -3944,6 +3957,8 @@
   EXPECT_TRUE(*result.value.GetDict().FindBool("arePreferencesSynced"));
   EXPECT_EQ(*result.value.GetDict().FindString("accountEmail"),
             "user@gmail.com");
+
+  DevToolsWindowTesting::CloseDevToolsWindowSync(window);
 }
 
 // Regression test for https://crbug.com/1270184.
@@ -4127,6 +4142,8 @@
                               blink::WebMouseEvent::Button::kLeft);
   active_tab_observer.Wait();
   ASSERT_EQ(0, tab_strip_model->active_index());
+
+  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
 }
 
 class DevToolsConsoleInsightsTest : public DevToolsTest {
@@ -4465,6 +4482,6 @@
   EXPECT_TRUE(WaitForLoadStop(main_web_contents));
   EXPECT_FALSE(called);
   EXPECT_EQ(window_, DevToolsWindow::FindDevToolsWindow(agent_host.get()));
-  DevToolsWindowTesting::Get(window_)->CloseDevToolsWindowSync(window_);
+  CloseDevToolsWindow();
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 720839e..0e6085b 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -487,6 +487,9 @@
 
   capture_handle_.RunAndReset();
   owned_toolbox_web_contents_.reset();
+#if !BUILDFLAG(IS_ANDROID)
+  browser_list_observation_.Reset();
+#endif
 
   DevToolsWindows* instances = g_devtools_window_instances.Pointer();
   auto it = std::ranges::find(*instances, this);
@@ -1974,6 +1977,19 @@
   }
 }
 
+#if !BUILDFLAG(IS_ANDROID)
+void DevToolsWindow::OnBrowserRemoved(Browser* browser) {
+  // If the modal dialog manager has this browser as its delegate, clear the
+  // reference.
+  web_modal::WebContentsModalDialogManager* dialog_manager =
+      web_modal::WebContentsModalDialogManager::FromWebContents(
+          main_web_contents_);
+  if (dialog_manager && dialog_manager->delegate() == browser) {
+    dialog_manager->SetDelegate(nullptr);
+  }
+}
+#endif
+
 void DevToolsWindow::OnInfoBarRemoved(infobars::InfoBar* infobar,
                                       bool animate) {
   if (sharing_infobar_ == infobar) {
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index de65bb09..cd4b042 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
 #include "chrome/browser/devtools/devtools_toggle_action.h"
@@ -17,7 +18,13 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_list_observer.h"
+#endif
+
 class Browser;
+class BrowserList;
 class BrowserWindow;
 class DevToolsWindowTesting;
 class DevToolsEventForwarder;
@@ -82,6 +89,9 @@
 class DevToolsWindow : public DevToolsUIBindings::Delegate,
                        public content::WebContentsDelegate,
                        public content::WebContentsObserver,
+#if !BUILDFLAG(IS_ANDROID)
+                       public BrowserListObserver,
+#endif
                        public infobars::InfoBarManager::Observer {
  public:
   static const char kDevToolsApp[];
@@ -451,6 +461,11 @@
   using content::WebContentsObserver::BeforeUnloadFired;
   void PrimaryPageChanged(content::Page& page) override;
 
+#if !BUILDFLAG(IS_ANDROID)
+  // BrowserListObserver:
+  void OnBrowserRemoved(Browser* browser) override;
+#endif
+
   // infobars::InfoBarManager::Observer
   void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override;
 
@@ -545,6 +560,11 @@
   raw_ptr<infobars::InfoBar> sharing_infobar_ = nullptr;
   int checked_sharing_process_id_ = content::ChildProcessHost::kInvalidUniqueID;
 
+#if !BUILDFLAG(IS_ANDROID)
+  base::ScopedObservation<BrowserList, BrowserListObserver>
+      browser_list_observation_{this};
+#endif
+
   PrefChangeRegistrar pref_change_registrar_;
 
   base::ScopedClosureRunner capture_handle_;
diff --git a/chrome/browser/devtools/devtools_window_views.cc b/chrome/browser/devtools/devtools_window_views.cc
index 778b783..9ba6dcc 100644
--- a/chrome/browser/devtools/devtools_window_views.cc
+++ b/chrome/browser/devtools/devtools_window_views.cc
@@ -116,4 +116,10 @@
       main_web_contents_);
   web_modal::WebContentsModalDialogManager::FromWebContents(main_web_contents_)
       ->SetDelegate(browser);
+
+  // Observer `browser` destruction/removal to reset `SetDelegate(nullptr)`
+  // before the dialog manager's `raw_ptr` becomes dangling.
+  if (!browser_list_observation_.IsObserving()) {
+    browser_list_observation_.Observe(BrowserList::GetInstance());
+  }
 }
diff --git a/chrome/browser/download/download_danger_prompt.h b/chrome/browser/download/download_danger_prompt.h
index d8545a9..70128bc 100644
--- a/chrome/browser/download/download_danger_prompt.h
+++ b/chrome/browser/download/download_danger_prompt.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DANGER_PROMPT_H_
 
 #include "base/functional/callback_forward.h"
-#include "components/safe_browsing/core/common/proto/csd.pb.h"
 
 namespace content {
 class WebContents;
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
index 20e00a2..bcd95d3 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
@@ -417,6 +417,8 @@
                 glic::GlicProfileManager::GetInstance()->GetLastActiveGlic()) {
           std::u16string label = l10n_util::GetPluralStringFUTF16(
               IDS_DEEP_SCANNING_DIALOG_UPLOAD_WARNING_MESSAGE, 1);
+          base::UmaHistogramEnumeration("Glic.Modal.DeepScanAccessPoint",
+                                        access_point);
           glic_keyed_service->window_controller().ShowGlicModal(label);
         }
       }
diff --git a/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc b/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
index b842e14..f03377b4 100644
--- a/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
+++ b/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
@@ -15,6 +15,7 @@
 #include "components/enterprise/connectors/core/reporting_constants.h"
 #include "components/enterprise/connectors/core/reporting_test_utils.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
+#include "components/safe_browsing/core/common/features.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h b/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h
index 9c4b3da6..5d4f8f50 100644
--- a/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h
+++ b/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h
@@ -5,22 +5,22 @@
 #ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_TEST_DEEP_SCANNING_TEST_UTILS_H_
 #define CHROME_BROWSER_ENTERPRISE_CONNECTORS_TEST_DEEP_SCANNING_TEST_UTILS_H_
 
+#include <memory>
 #include <optional>
 #include <set>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "base/containers/flat_map.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
 #include "components/enterprise/buildflags/buildflags.h"
 #include "components/enterprise/common/proto/connectors.pb.h"
 #include "components/enterprise/connectors/core/reporting_test_utils.h"
 #include "components/enterprise/data_controls/core/browser/verdict.h"
-#include "components/safe_browsing/core/common/proto/realtimeapi.pb.h"
-#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "extensions/buildflags/buildflags.h"
 
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
index 30dc598eb..25c3411c 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
@@ -1,5 +1,4 @@
 file://chrome/browser/chromeos/platform_keys/OWNERS
 
 drcrash@chromium.org
-bartfab@chromium.org
 dkrahn@chromium.org
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_api.cc b/chrome/browser/extensions/api/instance_id/instance_id_api.cc
index 591e999..061c30d 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_api.cc
+++ b/chrome/browser/extensions/api/instance_id/instance_id_api.cc
@@ -95,7 +95,7 @@
 
 void InstanceIDGetCreationTimeFunction::GetCreationTimeCompleted(
     const base::Time& creation_time) {
-  Respond(WithArguments(creation_time.InSecondsFSinceUnixEpoch()));
+  Respond(WithArguments(creation_time.InMillisecondsFSinceUnixEpoch()));
 }
 
 InstanceIDGetTokenFunction::InstanceIDGetTokenFunction() = default;
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
index 70dae945..f8ae2f7 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
+++ b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
@@ -48,6 +48,10 @@
   ASSERT_TRUE(RunExtensionTest("instance_id/get_creation_time"));
 }
 
+IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetCreationTimeFormat) {
+  ASSERT_TRUE(RunExtensionTest("instance_id/get_creation_time_format"));
+}
+
 IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, DeleteID) {
   ASSERT_TRUE(RunExtensionTest("instance_id/delete_id"));
 }
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.cc b/chrome/browser/extensions/updater/chrome_update_client_config.cc
index de3e7a54..75449b1 100644
--- a/chrome/browser/extensions/updater/chrome_update_client_config.cc
+++ b/chrome/browser/extensions/updater/chrome_update_client_config.cc
@@ -34,6 +34,7 @@
 #include "components/services/patch/content/patch_service.h"
 #include "components/services/unzip/content/unzip_service.h"
 #include "components/update_client/activity_data_service.h"
+#include "components/update_client/crx_cache.h"
 #include "components/update_client/crx_downloader_factory.h"
 #include "components/update_client/net/network_chromium.h"
 #include "components/update_client/patch/patch_impl.h"
@@ -183,7 +184,14 @@
           base::BindRepeating(&extensions::GetPrefService, context_),
           std::make_unique<ExtensionActivityDataService>(
               ExtensionPrefs::Get(context)))),
-      url_override_(url_override) {}
+      url_override_(url_override) {
+  base::FilePath path;
+  bool result = base::PathService::Get(chrome::DIR_USER_DATA, &path);
+  crx_cache_ = base::MakeRefCounted<update_client::CrxCache>(
+      result ? std::optional<base::FilePath>(
+                   path.AppendASCII("extensions_crx_cache"))
+             : std::nullopt);
+}
 
 ChromeUpdateClientConfig::~ChromeUpdateClientConfig() = default;
 
@@ -380,13 +388,9 @@
   GetFactoryCallback() = factory;
 }
 
-std::optional<base::FilePath> ChromeUpdateClientConfig::GetCrxCachePath()
+scoped_refptr<update_client::CrxCache> ChromeUpdateClientConfig::GetCrxCache()
     const {
-  base::FilePath path;
-  bool result = base::PathService::Get(chrome::DIR_USER_DATA, &path);
-  return result ? std::optional<base::FilePath>(
-                      path.AppendASCII("extensions_crx_cache"))
-                : std::nullopt;
+  return crx_cache_;
 }
 
 bool ChromeUpdateClientConfig::IsConnectionMetered() const {
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.h b/chrome/browser/extensions/updater/chrome_update_client_config.h
index 78ba7e6..2018c66 100644
--- a/chrome/browser/extensions/updater/chrome_update_client_config.h
+++ b/chrome/browser/extensions/updater/chrome_update_client_config.h
@@ -25,15 +25,12 @@
 
 class GURL;
 
-namespace base {
-class FilePath;
-}  // namespace base
-
 namespace content {
 class BrowserContext;
 }
 
 namespace update_client {
+class CrxCache;
 class CrxDownloaderFactory;
 class NetworkFetcherFactory;
 class ProtocolHandlerFactory;
@@ -87,7 +84,7 @@
   GetProtocolHandlerFactory() const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   update_client::UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<update_client::CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
  protected:
@@ -112,6 +109,7 @@
   scoped_refptr<update_client::UnzipperFactory> unzip_factory_;
   scoped_refptr<update_client::PatcherFactory> patch_factory_;
   std::optional<GURL> url_override_;
+  scoped_refptr<update_client::CrxCache> crx_cache_;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/feed/android/BUILD.gn b/chrome/browser/feed/android/BUILD.gn
index 5a03c30..e86c6376 100644
--- a/chrome/browser/feed/android/BUILD.gn
+++ b/chrome/browser/feed/android/BUILD.gn
@@ -106,7 +106,6 @@
     "//chrome/browser/ui/android/native_page:java",
     "//chrome/browser/ui/android/omnibox:java",
     "//chrome/browser/ui/android/signin:java",
-    "//chrome/browser/ui/android/toolbar:java",
     "//chrome/browser/ui/android/toolbar:java_resources",
     "//chrome/browser/ui/messages/android:java",
     "//chrome/browser/user_education:java",
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
index 2fe16ff3..656ff604 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
@@ -832,8 +832,8 @@
     public void bind(
             RecyclerView rootView,
             FeedListContentManager manager,
-            FeedScrollState savedInstanceState,
-            FeedSurfaceScope surfaceScope,
+            @Nullable FeedScrollState savedInstanceState,
+            @Nullable FeedSurfaceScope surfaceScope,
             HybridListRenderer renderer,
             @Nullable FeedReliabilityLogger reliabilityLogger,
             int headerCount) {
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/Stream.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/Stream.java
index f34aa9a..88dcc0b 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/Stream.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/Stream.java
@@ -108,8 +108,8 @@
     void bind(
             RecyclerView view,
             FeedListContentManager manager,
-            FeedScrollState savedInstanceState,
-            FeedSurfaceScope surfaceScope,
+            @Nullable FeedScrollState savedInstanceState,
+            @Nullable FeedSurfaceScope surfaceScope,
             HybridListRenderer renderer,
             @Nullable FeedReliabilityLogger reliabilityLogger,
             int headerCount);
diff --git a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
index 9dfa655..03ca417 100644
--- a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
+++ b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
@@ -43,7 +43,7 @@
 }
 
 void ScopedMockFirstPartySetsHandler::GetContextConfigForPolicy(
-    const base::Value::Dict* policy,
+    base::optional_ref<const base::Value::Dict> policy,
     base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
   if (invoke_callbacks_asynchronously_) {
     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
diff --git a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
index 0956fe86..a3cce76 100644
--- a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
+++ b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
@@ -48,7 +48,7 @@
       const net::SchemefulSite& site,
       const net::FirstPartySetsContextConfig& config) const override;
   void GetContextConfigForPolicy(
-      const base::Value::Dict* policy,
+      base::optional_ref<const base::Value::Dict> policy,
       base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback)
       override;
   void ClearSiteDataOnChangedSetsForContext(
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index ca9345d..9613d8b 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -301,6 +301,11 @@
     "expiry_milestone": 138
   },
   {
+    "name": "android-progress-bar-visual-update",
+    "owners": ["agazal@google.com", "peilinwang@google.com", "clank-app-team@google.com"],
+    "expiry_milestone": 170
+  },
+  {
     "name": "android-surface-color-update",
     "owners": [ "jtanaristy@google.com", "wenyufu@google.com" ],
     "expiry_milestone": 140
@@ -5308,6 +5313,11 @@
     "expiry_milestone": 126
   },
   {
+    "name": "hdr-agtm",
+    "owners": [ "ccameron@chromium.org", "fgalligan@chromium.org" ],
+    "expiry_milestone": 170
+  },
+  {
     "name": "headless-tab-model",
     "owners": [ "skym@chromium.org", "ckitagawa@chromium.org" ],
     "expiry_milestone": 145
@@ -5665,6 +5675,11 @@
     "expiry_milestone": 137
   },
   {
+    "name": "ios-expanded-tips",
+    "owners": ["scottyoder@google.com", "bwwilliams@google.com", "bling-get-set-up@google.com"],
+    "expiry_milestone": 142
+  },
+  {
     "name": "ios-interruptible-coordinator-always-dismissed",
     "owners": [
       "arthurmilchior@google.com",
@@ -9205,6 +9220,14 @@
     "expiry_milestone": 135
   },
   {
+    "name": "three-button-password-save-dialog",
+    "owners": [
+      "cjgrant@chromium.org",
+      "dfried@chromium.org"
+    ],
+    "expiry_milestone": 145
+  },
+  {
     "name": "throttle-main-thread-to-60hz",
     "owners": [ "lizeb@google.com", "clank-performance-team@google.com" ],
     "expiry_milestone": 137
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index de1013c..d8f227c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -205,6 +205,13 @@
     "existing tab";
 #endif  // BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(IS_ANDROID)
+const char kAndroidProgressBarVisualUpdateName[] =
+    "Enable updated progress bar";
+const char kAndroidProgressBarVisualUpdateDescription[] =
+    "Enable the new updated progress bar";
+#endif  // BUILDFLAG(IS_ANDROID)
+
 #if BUILDFLAG(IS_CHROMEOS)
 const char kIgnoreDeviceFlexArcEnabledPolicyName[] =
     "Ignore VPN Apps Enabling on ChromeOS Flex";
@@ -409,6 +416,11 @@
     "payments, so that merchants that are not on the allowlist can also be "
     "tested for the supported features.";
 
+const char kHdrAgtmName[] = "Adaptive global tone mapping";
+const char kHdrAgtmDescription[] =
+    "Enables parsing and rendering of adaptive global tone mapping (AGTM) aka "
+    "SMTPE ST 2094-50 HDR metadata";
+
 const char kHistorySyncAlternativeIllustrationName[] =
     "History Sync Alternative Illustration";
 const char kHistorySyncAlternativeIllustrationDescription[] =
@@ -3936,6 +3948,14 @@
     "Enables querying the third party autofill mode state from the Chrome app.";
 #endif
 
+#if !BUILDFLAG(IS_ANDROID)
+const char kThreeButtonPasswordSaveDialogName[] =
+    "Three Button Password Save Dialog";
+const char kThreeButtonPasswordSaveDialogDescription[] =
+    "Provides a 'not now' button alongside the 'never' button on the save "
+    "password dialog.";
+#endif
+
 const char kThrottleMainTo60HzName[] = "throttle-main-thread-to-60hz";
 const char kThrottleMainTo60HzDescription[] =
     "Throttle main thread updates to 60fps, even when VSync rate is higher.";
@@ -4834,10 +4854,6 @@
 const char kFeedDiscoFeedEndpointDescription[] =
     "Uses the DiscoFeed endpoint for serving the feed instead of GWS.";
 
-const char kFeedDynamicColorsName[] = "Enable dynamic colors in the feed";
-const char kFeedDynamicColorsDescription[] =
-    "Allows feed to fully respect dynamic colors if supported by the client.";
-
 const char kFeedHeaderRemovalName[] = "Removing feed header";
 const char kFeedHeaderRemovalDescription[] = "Stops showing the feed header.";
 
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 1d552534..97080e12 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -141,6 +141,11 @@
 extern const char kAndroidNativePagesInNewTabDescription[];
 #endif  // BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(IS_ANDROID)
+extern const char kAndroidProgressBarVisualUpdateName[];
+extern const char kAndroidProgressBarVisualUpdateDescription[];
+#endif  // BUILDFLAG(IS_ANDROID)
+
 #if BUILDFLAG(IS_CHROMEOS)
 extern const char kIgnoreDeviceFlexArcEnabledPolicyName[];
 extern const char kIgnoreDeviceFlexArcEnabledPolicyDescription[];
@@ -267,6 +272,9 @@
 extern const char kDisableFacilitatedPaymentsMerchantAllowlistName[];
 extern const char kDisableFacilitatedPaymentsMerchantAllowlistDescription[];
 
+extern const char kHdrAgtmName[];
+extern const char kHdrAgtmDescription[];
+
 extern const char kHistorySyncAlternativeIllustrationName[];
 extern const char kHistorySyncAlternativeIllustrationDescription[];
 
@@ -2268,6 +2276,11 @@
 extern const char kAutofillThirdPartyModeContentProviderDescription[];
 #endif
 
+#if !BUILDFLAG(IS_ANDROID)
+extern const char kThreeButtonPasswordSaveDialogName[];
+extern const char kThreeButtonPasswordSaveDialogDescription[];
+#endif
+
 extern const char kThrottleMainTo60HzName[];
 extern const char kThrottleMainTo60HzDescription[];
 
@@ -2826,9 +2839,6 @@
 extern const char kFeedContainmentName[];
 extern const char kFeedContainmentDescription[];
 
-extern const char kFeedDynamicColorsName[];
-extern const char kFeedDynamicColorsDescription[];
-
 extern const char kFeedDiscoFeedEndpointName[];
 extern const char kFeedDiscoFeedEndpointDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index cb14e0a..6f270ca 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -160,7 +160,6 @@
     &feature_engagement::kIPHTabSwitcherButtonFeature,
     &feature_engagement::kIPHRtlGestureNavigationFeature,
     &feed::kFeedContainment,
-    &feed::kFeedDynamicColors,
     &feed::kFeedFollowUiUpdate,
     &feed::kFeedHeaderRemoval,
     &feed::kFeedImageMemoryCacheSizePercentage,
@@ -195,6 +194,7 @@
     &kAndroidKeyboardA11y,
     &kAndroidMetaClickHistoryNavigation,
     &kAndroidNativePagesInNewTab,
+    &kAndroidProgressBarVisualUpdate,
     &kAndroidNoVisibleHintForDifferentTLD,
     &kAndroidOmniboxFocusedNewTabPage,
     &kAndroidOpenPdfInlineBackport,
@@ -480,7 +480,7 @@
 
 BASE_FEATURE(kDisableListTabSwitcher,
              "DisableListTabSwitcher",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Long-term flag for debugging only.
 BASE_FEATURE(kForceListTabSwitcher,
@@ -539,6 +539,10 @@
              "AndroidNativePagesInNewTab",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kAndroidProgressBarVisualUpdate,
+             "AndroidProgressBarVisualUpdate",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kAndroidNoVisibleHintForDifferentTLD,
              "AndroidNoVisibleHintForDifferentTLD",
              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 f86772c..f41d050 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -32,6 +32,7 @@
 BASE_DECLARE_FEATURE(kAndroidKeyboardA11y);
 BASE_DECLARE_FEATURE(kAndroidMetaClickHistoryNavigation);
 BASE_DECLARE_FEATURE(kAndroidNativePagesInNewTab);
+BASE_DECLARE_FEATURE(kAndroidProgressBarVisualUpdate);
 BASE_DECLARE_FEATURE(kAndroidNoVisibleHintForDifferentTLD);
 BASE_DECLARE_FEATURE(kAndroidOmniboxFocusedNewTabPage);
 BASE_DECLARE_FEATURE(kAndroidOpenPdfInlineBackport);
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 376d6d2..90fcf99 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
@@ -186,6 +186,7 @@
             "AndroidOmniboxFocusedNewTabPage";
     public static final String ANDROID_OPEN_PDF_INLINE_BACKPORT = "AndroidOpenPdfInlineBackport";
     public static final String ANDROID_PDF_ASSIST_CONTENT = "AndroidPdfAssistContent";
+    public static final String ANDROID_PROGRESS_BAR_VISUAL_UPDATE = "AndroidProgressBarVisualUpdate";
     public static final String ANDROID_SURFACE_COLOR_UPDATE = "AndroidSurfaceColorUpdate";
     public static final String ANDROID_TAB_DECLUTTER = "AndroidTabDeclutter";
     public static final String ANDROID_TAB_DECLUTTER_ARCHIVE_ALL_BUT_ACTIVE =
@@ -634,6 +635,8 @@
             newCachedFlag(ANDROID_ELEGANT_TEXT_HEIGHT, true);
     public static final CachedFlag sAndroidMinimalUiLargeScreen =
             newCachedFlag(ANDROID_MINIMAL_UI_LARGE_SCREEN, false);
+    public static final CachedFlag sAndroidProgressBarVisualUpdate =
+            newCachedFlag(ANDROID_PROGRESS_BAR_VISUAL_UPDATE, false);
     public static final CachedFlag sAndroidSurfaceColorUpdate =
             newCachedFlag(ANDROID_SURFACE_COLOR_UPDATE, /* defaultValue= */ false);
     public static final CachedFlag sAndroidTabDeclutterDedupeTabIdsKillSwitch =
@@ -869,6 +872,7 @@
                     sAndroidBottomToolbar,
                     sAndroidElegantTextHeight,
                     sAndroidMinimalUiLargeScreen,
+                    sAndroidProgressBarVisualUpdate,
                     sAndroidSurfaceColorUpdate,
                     sAndroidTabDeclutterDedupeTabIdsKillSwitch,
                     sAndroidTabSkipSaveTabsKillswitch,
diff --git a/chrome/browser/glic/host/glic_api_uitest.cc b/chrome/browser/glic/host/glic_api_uitest.cc
index 776726d..020f4a8f 100644
--- a/chrome/browser/glic/host/glic_api_uitest.cc
+++ b/chrome/browser/glic/host/glic_api_uitest.cc
@@ -24,6 +24,7 @@
 #include "base/test/test_timeouts.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "base/version_info/version_info.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/contextual_cueing/contextual_cueing_features.h"
@@ -45,6 +46,7 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/profiles/profile_picker.h"
+#include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
@@ -72,6 +74,10 @@
 
 namespace glic {
 namespace {
+using testing::_;
+using testing::Contains;
+using testing::Pair;
+
 DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kFirstTab);
 DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSecondTab);
 DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSettingsTab);
@@ -86,8 +92,6 @@
   };
 }
 
-using testing::_;
-
 // Observes the state of the WebUI hosted in the glic window.
 class WebUIStateListener : public Host::Observer {
  public:
@@ -622,13 +626,19 @@
                                  GlicInstrumentMode::kHostAndContents));
   ExecuteJsTest();
 
-  ASSERT_THAT(base::ToVector(embedded_test_server_requests_,
-                             [](const auto& request) {
-                               return std::make_pair(
-                                   request.GetURL().path(),
-                                   request.headers.contains("X-Glic"));
-                             }),
-              testing::Contains(testing::Pair(GetGuestURL().path(), true)));
+  auto main_request = std::ranges::find_if(
+      embedded_test_server_requests_, [&](const auto& request) {
+        return request.GetURL().path() == GetGuestURL().path();
+      });
+  ASSERT_NE(main_request, embedded_test_server_requests_.end());
+  ASSERT_THAT(
+      main_request->headers,
+      testing::AllOf(Contains(Pair("x-glic", "1")),
+                     Contains(Pair("x-glic-chrome-channel",
+                                   testing::AnyOf("unknown", "canary", "dev",
+                                                  "beta", "stable"))),
+                     Contains(Pair("x-glic-chrome-version",
+                                   version_info::GetVersionNumber()))));
 }
 
 IN_PROC_BROWSER_TEST_F(GlicApiTest, testCreateTab) {
diff --git a/chrome/browser/glic/host/glic_ui.cc b/chrome/browser/glic/host/glic_ui.cc
index 112078e..7c2bebf 100644
--- a/chrome/browser/glic/host/glic_ui.cc
+++ b/chrome/browser/glic/host/glic_ui.cc
@@ -7,11 +7,13 @@
 #include <string>
 
 #include "base/command_line.h"
+#include "base/version_info/version_info.h"
 #include "chrome/browser/glic/glic_enabling.h"
 #include "chrome/browser/glic/host/glic_page_handler.h"
 #include "chrome/browser/glic/host/guest_util.h"
 #include "chrome/browser/glic/resources/grit/glic_browser_resources.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/webui_url_constants.h"
@@ -76,6 +78,9 @@
   auto* command_line = base::CommandLine::ForCurrentProcess();
   const bool is_glic_dev = command_line->HasSwitch(::switches::kGlicDev);
 
+  source->AddString("chromeVersion", version_info::GetVersionNumber());
+  source->AddString("chromeChannel",
+                    version_info::GetChannelString(chrome::GetChannel()));
   source->AddBoolean("loggingEnabled",
                      command_line->HasSwitch(::switches::kGlicHostLogging));
   // Set up guest URL via cli flag or default to finch param value.
diff --git a/chrome/browser/headless/headless_mode_protocol_browsertest.cc b/chrome/browser/headless/headless_mode_protocol_browsertest.cc
index 2ccaec9..b8ef6dd 100644
--- a/chrome/browser/headless/headless_mode_protocol_browsertest.cc
+++ b/chrome/browser/headless/headless_mode_protocol_browsertest.cc
@@ -348,8 +348,6 @@
     "--ozone-override-screen-size=1234,5678")
 #endif
 
-// --screen-info switch is only supported on Linux and Windows at this time.
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
 // This currently results in an unexpected screen orientation type,
 // see http://crbug.com/398150465.
 HEADLESS_MODE_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS(
@@ -372,6 +370,4 @@
     "sanity/create-target-secondary-screen.js",
     "--screen-info={label='#1'}{label='#2'}")
 
-#endif
-
 }  // namespace headless
diff --git a/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc b/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc
index 69e26047..9f338fc 100644
--- a/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc
+++ b/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/android/autofill/autofill_fallback_surface_launcher.h"
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/core/browser/data_manager/addresses/address_data_manager.h"
diff --git a/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl_unittest.cc b/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl_unittest.cc
index 8954c763..c16d314 100644
--- a/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl_unittest.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/keyboard_accessory/test_utils/android/mock_affiliated_plus_profiles_provider.h"
 #include "chrome/browser/keyboard_accessory/test_utils/android/mock_manual_filling_controller.h"
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.cc b/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.cc
index f235630..86a141a7 100644
--- a/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.cc
+++ b/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.cc
@@ -40,8 +40,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ssl/chrome_security_state_tab_helper.h"
 #include "chrome/browser/ui/android/autofill/autofill_fallback_surface_launcher.h"
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h"
 #include "chrome/browser/ui/passwords/ui_utils.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h"
 #include "chrome/browser/webauthn/android/webauthn_request_delegate_android.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
diff --git a/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl_unittest.cc b/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl_unittest.cc
index c7b9630e..54a69087 100644
--- a/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl_unittest.cc
@@ -32,7 +32,7 @@
 #include "chrome/browser/password_manager/android/password_generation_controller_impl.h"
 #include "chrome/browser/password_manager/password_manager_test_util.h"
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/autofill/content/browser/test_autofill_client_injector.h"
diff --git a/chrome/browser/media/offscreen_tab.cc b/chrome/browser/media/offscreen_tab.cc
index bfcdf050..7a9effee 100644
--- a/chrome/browser/media/offscreen_tab.cc
+++ b/chrome/browser/media/offscreen_tab.cc
@@ -283,6 +283,7 @@
 }
 
 bool OffscreenTab::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/chrome/browser/media/offscreen_tab.h b/chrome/browser/media/offscreen_tab.h
index 2fa0d6e1..231e3595 100644
--- a/chrome/browser/media/offscreen_tab.h
+++ b/chrome/browser/media/offscreen_tab.h
@@ -104,6 +104,7 @@
                     const content::DropData& data,
                     blink::DragOperationsMask operations_allowed) final;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 744d6221..60932d11 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -481,7 +481,7 @@
   g_browser_process->local_state()->SetBoolean(
       metrics::prefs::kMetricsReportingEnabled, enabled);
 
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 }
 #endif
 
diff --git a/chrome/browser/metrics/cros_pre_consent_metrics_manager.cc b/chrome/browser/metrics/cros_pre_consent_metrics_manager.cc
index 965120a9..a32b7851 100644
--- a/chrome/browser/metrics/cros_pre_consent_metrics_manager.cc
+++ b/chrome/browser/metrics/cros_pre_consent_metrics_manager.cc
@@ -98,8 +98,7 @@
   // Propagate the change to metrics services. This will create the Client ID
   // that will be used if the user consents to metrics. If pre-consent is being
   // disabled do not update the permissions as it should not be changed.
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(
-      is_enabled_);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 
   // Register CrOSPreConsentMetricsManager as the observer for policy change to
   // get notified when device is enrolled.
diff --git a/chrome/browser/metrics/metrics_reporting_state.cc b/chrome/browser/metrics/metrics_reporting_state.cc
index ed11e51..fe9a8a2 100644
--- a/chrome/browser/metrics/metrics_reporting_state.cc
+++ b/chrome/browser/metrics/metrics_reporting_state.cc
@@ -77,7 +77,7 @@
   UpdateMetricsPrefsOnPermissionChange(updated_pref, called_from);
 
   // Uses the current state of whether reporting is enabled to enable services.
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 
   if (to_update_pref == updated_pref) {
     RecordMetricsReportingHistogramValue(updated_pref ?
@@ -85,8 +85,9 @@
   } else {
     RecordMetricsReportingHistogramValue(METRICS_REPORTING_ERROR);
   }
-  if (!callback_fn.is_null())
+  if (!callback_fn.is_null()) {
     std::move(callback_fn).Run(updated_pref);
+  }
 }
 
 }  // namespace
diff --git a/chrome/browser/metrics/structured/test/structured_metrics_mixin.cc b/chrome/browser/metrics/structured/test/structured_metrics_mixin.cc
index ba9a307..2992bcf3 100644
--- a/chrome/browser/metrics/structured/test/structured_metrics_mixin.cc
+++ b/chrome/browser/metrics/structured/test/structured_metrics_mixin.cc
@@ -169,8 +169,7 @@
   recording_state_ = state;
 
   // Triggers rechecking of metrics state.
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(
-      /*may_upload=*/true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 }
 
 std::unique_ptr<ChromeUserMetricsExtension>
diff --git a/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc b/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
index 8a178ea..d2f7e95 100644
--- a/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
+++ b/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
@@ -308,7 +308,9 @@
     tracker_->OnTabStripNewTabCount(CHECK_DEREF(tab_model).GetTabCount());
   }
 
-  void WillCloseTab(TabAndroid* tab) final {
+  void TabRemoved(TabAndroid* tab) final {
+    // The tab was removed from the model, either because it closed or moved to
+    // a different model. Either way stop watching for the WebContents.
     if (tab_android_observations_.IsObservingSource(tab)) {
       tab_android_observations_.RemoveObservation(tab);
     }
@@ -326,9 +328,12 @@
   void OnTabAdded(TabAndroid* tab) {
     if (content::WebContents* web_contents = tab->web_contents()) {
       tracker_->OnInitialOrInsertedTab(web_contents);
-    } else {
+    } else if (!tab_android_observations_.IsObservingSource(tab)) {
       // The WebContents hasn't been attached to the tab yet. Start tracking it
-      // when TabAndroid::Observer::OnInitWebContents is called.
+      // when TabAndroid::Observer::OnInitWebContents is called. Note OnTabAdded
+      // can be called while the tab is already being observed, if it's called
+      // from the TabModel constructor while an async DidAddTab notification is
+      // in flight.
       tab_android_observations_.AddObservation(tab);
     }
   }
diff --git a/chrome/browser/metrics/testing/metrics_consent_override.cc b/chrome/browser/metrics/testing/metrics_consent_override.cc
index b72dd2be..bf1eba2 100644
--- a/chrome/browser/metrics/testing/metrics_consent_override.cc
+++ b/chrome/browser/metrics/testing/metrics_consent_override.cc
@@ -24,8 +24,7 @@
 void MetricsConsentOverride::Update(bool state) {
   state_ = state;
   // Trigger rechecking of metrics state.
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(
-      /*may_upload=*/true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 }
 
 }  // namespace metrics::test
diff --git a/chrome/browser/metrics/ukm_browsertest.cc b/chrome/browser/metrics/ukm_browsertest.cc
index 5befc10..33f9f8c8 100644
--- a/chrome/browser/metrics/ukm_browsertest.cc
+++ b/chrome/browser/metrics/ukm_browsertest.cc
@@ -806,7 +806,7 @@
 
   std::unique_ptr<SyncServiceImplHarness> harness =
       EnableSyncForProfile(profile);
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
   EXPECT_TRUE(ukm_test_helper.IsRecordingEnabled());
 
   ClosePlatformBrowser(browser);
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetDelegate.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetDelegate.java
index 0f1beab..623057ff 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetDelegate.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetDelegate.java
@@ -6,10 +6,13 @@
 
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * This delegate interface is responsible for recording the position of the bottom sheet layout in
  * the view flipper view, as well as handling back button clicks on the bottom sheet.
  */
+@NullMarked
 public interface BottomSheetDelegate {
     /**
      * Records the position of the bottom sheet layout in the view flipper view. The position index
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java
index fe9eaa2..4b95728 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java
@@ -12,9 +12,12 @@
 import android.view.View;
 import android.widget.LinearLayout;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.util.List;
 
 /** The view holding {@link BottomSheetListItemView} in a bottom sheet. */
+@NullMarked
 public class BottomSheetListContainerView extends LinearLayout {
     protected final Context mContext;
 
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerViewBinder.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerViewBinder.java
index 84fb849..c8217e6 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerViewBinder.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerViewBinder.java
@@ -9,6 +9,7 @@
 
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -16,6 +17,7 @@
  * Class responsible for binding a delegate to a {@link BottomSheetListContainerView}. The delegate
  * provides list content and event handlers to the list container view.
  */
+@NullMarked
 public class BottomSheetListContainerViewBinder {
     public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
         if (propertyKey == LIST_CONTAINER_VIEW_DELEGATE) {
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java
index f6f6014..ba04410 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java
@@ -14,9 +14,11 @@
 
 import androidx.appcompat.content.res.AppCompatResources;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.widget.TextViewWithLeading;
 
 /** The list item view within a {@link BottomSheetListContainerView} of a bottom sheet. */
+@NullMarked
 public class BottomSheetListItemView extends LinearLayout {
     private TextViewWithLeading mTitleView;
     private TextViewWithLeading mSubtitleView;
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetViewBinder.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetViewBinder.java
index f1f33d2..a96b93c 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetViewBinder.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetViewBinder.java
@@ -8,10 +8,12 @@
 
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Class responsible for binding a back press handler to the back button in a bottom sheet. */
+@NullMarked
 public class BottomSheetViewBinder {
     public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
         if (propertyKey == BACK_PRESS_HANDLER) {
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java
index 71b41ece..765f07f3 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java
@@ -6,14 +6,17 @@
 
 import android.content.Context;
 import android.support.annotation.DrawableRes;
-import android.support.annotation.Nullable;
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.util.List;
 
 /**
  * This delegate provides list content and event handlers to {@link BottomSheetListContainerView}.
  */
+@NullMarked
 public interface ListContainerViewDelegate {
     /**
      * Returns the types of items to be added to the container view. The size of the returned list
@@ -50,8 +53,7 @@
      *
      * @param type The type of the list item.
      */
-    @Nullable
-    View.OnClickListener getListener(int type);
+    View.@Nullable OnClickListener getListener(int type);
 
     /**
      * Returns the resource id of the trailing icon in the list item for the given type.
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
index 717cd6b..8db2a90b 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
@@ -10,14 +10,14 @@
 import android.content.res.Resources;
 import android.view.View;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.Supplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 
 /** Bottom sheet content of the NTP customization. */
+@NullMarked
 public class NtpCustomizationBottomSheetContent implements BottomSheetContent {
     private final View mContentView;
     private final Runnable mBackPressRunnable;
@@ -94,7 +94,7 @@
     }
 
     @Override
-    public String getSheetContentDescription(@NonNull Context context) {
+    public @Nullable String getSheetContentDescription(Context context) {
         // Returns null when the current sheet is the main bottom sheet. This ensures TalkBack reads
         // the full content of the main bottom sheet in a top-to-bottom, left-to-right order.
         if (mCurrentBottomSheetTypeSupplier.get() == MAIN) {
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationCoordinator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationCoordinator.java
index a77f6d3..5fabde8 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationCoordinator.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationCoordinator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp_customization;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.FEED;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.MAIN;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.NTP_CARDS;
@@ -19,6 +20,9 @@
 import android.widget.ViewFlipper;
 
 import org.chromium.base.supplier.Supplier;
+import org.chromium.build.annotations.MonotonicNonNull;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.ntp_customization.feed.FeedSettingsCoordinator;
 import org.chromium.chrome.browser.ntp_customization.ntp_cards.NtpCardsCoordinator;
 import org.chromium.chrome.browser.profiles.ProfileProvider;
@@ -31,6 +35,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /** Coordinator of the NTP customization main bottom sheet. */
+@NullMarked
 public class NtpCustomizationCoordinator {
     /**
      * mDelegate will be passed to every bottom sheet coordinator created by {@link
@@ -41,8 +46,8 @@
     private final Context mContext;
     private final Supplier<ProfileProvider> mProfileSupplier;
     private NtpCustomizationMediator mMediator;
-    private NtpCardsCoordinator mNtpCardsCoordinator;
-    private FeedSettingsCoordinator mFeedSettingsCoordinator;
+    private @MonotonicNonNull NtpCardsCoordinator mNtpCardsCoordinator;
+    private @Nullable FeedSettingsCoordinator mFeedSettingsCoordinator;
     private ViewFlipper mViewFlipperView;
 
     @IntDef({BottomSheetType.MAIN, BottomSheetType.NTP_CARDS, BottomSheetType.FEED})
@@ -152,7 +157,7 @@
                 };
             default:
                 assert false : "Bottom sheet type not supported!";
-                return null;
+                return assumeNonNull(null);
         }
     }
 
@@ -205,7 +210,7 @@
         return mDelegate;
     }
 
-    NtpCardsCoordinator getNtpCardsCoordinatorForTesting() {
+    @Nullable NtpCardsCoordinator getNtpCardsCoordinatorForTesting() {
         return mNtpCardsCoordinator;
     }
 
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java
index bec76eb..a1bf46b 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp_customization;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.FEED;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.MAIN;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.NTP_CARDS;
@@ -12,13 +13,14 @@
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.MAIN_BOTTOM_SHEET_FEED_SECTION_SUBTITLE;
 
 import android.content.Context;
-import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.view.View;
 import android.widget.ViewFlipper;
 
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.supplier.Supplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.feed.FeedFeatures;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -40,6 +42,7 @@
  * A mediator class that manages the view flipper and {@link BottomSheetContent} of NTP
  * customization bottom sheets.
  */
+@NullMarked
 public class NtpCustomizationMediator {
     /**
      * A map of <{@link NtpCustomizationCoordinator.BottomSheetType}, view's position index in the
@@ -55,9 +58,9 @@
     private List<Integer> mListContent;
     private final PropertyModel mContainerPropertyModel;
     private final Supplier<ProfileProvider> mProfileSupplier;
-    private Profile mProfile;
-    private Integer mCurrentBottomSheet;
-    private static PrefService sPrefServiceForTest;
+    private @Nullable Profile mProfile;
+    private @Nullable Integer mCurrentBottomSheet;
+    private static @Nullable PrefService sPrefServiceForTest;
 
     public NtpCustomizationMediator(
             BottomSheetController bottomSheetController,
@@ -167,13 +170,12 @@
                         return context.getString(R.string.ntp_customization_feed_settings_title);
                     default:
                         assert false : "Bottom sheet type not supported!";
-                        return null;
+                        return assumeNonNull(null);
                 }
             }
 
             @Override
-            @Nullable
-            public String getListItemSubtitle(int type, Context context) {
+            public @Nullable String getListItemSubtitle(int type, Context context) {
                 if (type == FEED) {
                     return context.getString(getFeedSectionSubtitleId());
                 }
@@ -181,13 +183,12 @@
             }
 
             @Override
-            public View.OnClickListener getListener(int type) {
+            public View.@Nullable OnClickListener getListener(int type) {
                 return mTypeToListenersMap.get(type);
             }
 
             @Override
-            @Nullable
-            public Integer getTrailingIcon(int type) {
+            public @Nullable Integer getTrailingIcon(int type) {
                 return R.drawable.forward_arrow_icon;
             }
         };
@@ -272,6 +273,7 @@
         return mViewFlipperMap;
     }
 
+    @SuppressWarnings("NullAway") // The call sites require non-null but the value is nullable.
     @NtpCustomizationCoordinator.BottomSheetType
     Integer getCurrentBottomSheetType() {
         return mCurrentBottomSheet;
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMetricsUtils.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMetricsUtils.java
index 1d80d86..4076fd1 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMetricsUtils.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMetricsUtils.java
@@ -7,9 +7,11 @@
 import android.support.annotation.VisibleForTesting;
 
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 
 /** The utility class for logging the NTP customization bottom sheet's metrics. */
+@NullMarked
 public class NtpCustomizationMetricsUtils {
     @VisibleForTesting
     static final String HISTOGRAM_NTP_CUSTOMIZATION_PREFIX = "NewTabPage.Customization";
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationUtils.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationUtils.java
index 3216ce9..58b4283 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationUtils.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationUtils.java
@@ -8,7 +8,10 @@
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.MAIN;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationCoordinator.BottomSheetType.NTP_CARDS;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Utility class of the NTP customization. */
+@NullMarked
 public class NtpCustomizationUtils {
 
     /**
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java
index 6e2a830..1f5e48f 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java
@@ -7,10 +7,12 @@
 import android.view.View;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** The properties associated with rendering NTP customization bottom sheets. */
+@NullMarked
 public class NtpCustomizationViewProperties {
     // Properties for the general bottom sheet:
 
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java
index 6a6a1195..9a337d2 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java
@@ -18,6 +18,7 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetDelegate;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetListContainerViewBinder;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetViewBinder;
@@ -33,6 +34,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /** Coordinator for the feed settings bottom sheet in the NTP customization. */
+@NullMarked
 public class FeedSettingsCoordinator {
     private FeedSettingsMediator mMediator;
 
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java
index 350694f5..1de2abf 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp_customization.feed;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.BACK_PRESS_HANDLER;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.FEED_SWITCH_ON_CHECKED_CHANGE_LISTENER;
 import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.IS_FEED_LIST_ITEMS_TITLE_VISIBLE;
@@ -26,10 +27,11 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 
-import androidx.annotation.Nullable;
 import androidx.browser.customtabs.CustomTabsIntent;
 
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.feed.FeedServiceBridge;
 import org.chromium.chrome.browser.feed.FeedUma;
 import org.chromium.chrome.browser.feed.v2.FeedUserActionType;
@@ -51,6 +53,7 @@
 import java.util.List;
 
 /** Mediator for the feed settings bottom sheet in the NTP customization. */
+@NullMarked
 public class FeedSettingsMediator {
     private static final String TRUSTED_APPLICATION_CODE_EXTRA = "trusted_application_code_extra";
     private static final String ACTIVITY_CLICK_URL =
@@ -69,8 +72,8 @@
     private final BottomSheetDelegate mBottomSheetDelegate;
     private final Profile mProfile;
     private final PrefChangeRegistrar mPrefChangeRegistrar;
-    private static PrefService sPrefServiceForTest;
-    private static PrefChangeRegistrar sPrefChangeRegistarForTest;
+    private static @Nullable PrefService sPrefServiceForTest;
+    private static @Nullable PrefChangeRegistrar sPrefChangeRegistarForTest;
     private List<Integer> mListItemsContent;
 
     public FeedSettingsMediator(
@@ -165,7 +168,7 @@
             }
 
             @Override
-            public Integer getTrailingIcon(int type) {
+            public @Nullable Integer getTrailingIcon(int type) {
                 return null;
             }
         };
@@ -206,7 +209,7 @@
                 return resources.getString(R.string.feed_manage_interests);
             default:
                 assert false : "Section type not supported!";
-                return null;
+                return assumeNonNull(null);
         }
     }
 
@@ -228,7 +231,7 @@
                 return resources.getString(R.string.feed_manage_interests_description);
             default:
                 assert false : "Section type not supported!";
-                return null;
+                return assumeNonNull(null);
         }
     }
 
@@ -236,7 +239,7 @@
      * @param sectionType Type of the feed bottom sheet section.
      * @return The on click listener for the feed bottom sheet section type.
      */
-    private static OnClickListener getListenerForSectionType(
+    private static @Nullable OnClickListener getListenerForSectionType(
             @FeedSettingsBottomSheetSection int sectionType) {
         switch (sectionType) {
             case ACTIVITY:
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsCoordinator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsCoordinator.java
index d3dfba2..84f415a 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsCoordinator.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsCoordinator.java
@@ -10,6 +10,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetDelegate;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetListContainerViewBinder;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetViewBinder;
@@ -19,6 +20,7 @@
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 /** Coordinator for the NTP cards bottom sheet. */
+@NullMarked
 public class NtpCardsCoordinator {
     private NtpCardsMediator mMediator;
 
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java
index 3e6d99f..4c6ec328 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java
@@ -11,9 +11,10 @@
 import android.view.View;
 import android.widget.CompoundButton;
 
-import androidx.annotation.Nullable;
 import androidx.appcompat.content.res.AppCompatResources;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.magic_stack.HomeModulesConfigManager;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetListContainerView;
 import org.chromium.chrome.browser.ntp_customization.ListContainerViewDelegate;
@@ -24,6 +25,7 @@
 import java.util.List;
 
 /** The view holding {@link NtpCardsListItemView} in the "New tab page cards" bottom sheet. */
+@NullMarked
 public class NtpCardsListContainerView extends BottomSheetListContainerView {
     public NtpCardsListContainerView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java
index 95f3d9f8..d8a0704 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java
@@ -9,8 +9,8 @@
 import android.widget.CompoundButton;
 import android.widget.LinearLayout;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.ntp_customization.R;
 import org.chromium.components.browser_ui.widget.MaterialSwitchWithText;
 
@@ -18,6 +18,7 @@
  * The list item view within a {@link NtpCardsListContainerView} in the "New tab page cards" bottom
  * sheet.
  */
+@NullMarked
 public class NtpCardsListItemView extends LinearLayout {
     private MaterialSwitchWithText mMaterialSwitchWithText;
 
@@ -54,7 +55,8 @@
      *
      * @see CompoundButton#setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener).
      */
-    public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener listener) {
+    public void setOnCheckedChangeListener(
+            CompoundButton.@Nullable OnCheckedChangeListener listener) {
         mMaterialSwitchWithText.setOnCheckedChangeListener(listener);
     }
 
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java
index d936b95..0504ce2 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java
@@ -14,6 +14,7 @@
 
 import org.jni_zero.internal.Nullable;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.magic_stack.HomeModulesConfigManager;
 import org.chromium.chrome.browser.ntp_customization.BottomSheetDelegate;
 import org.chromium.chrome.browser.ntp_customization.ListContainerViewDelegate;
@@ -25,6 +26,7 @@
  * A mediator class that manages navigation between bottom sheets and manages the container view on
  * the NTP cards bottom sheet.
  */
+@NullMarked
 public class NtpCardsMediator {
 
     private final PropertyModel mContainerPropertyModel;
@@ -59,7 +61,7 @@
             }
 
             @Override
-            public String getListItemSubtitle(int type, Context context) {
+            public @Nullable String getListItemSubtitle(int type, Context context) {
                 return null;
             }
 
@@ -69,7 +71,7 @@
             }
 
             @Override
-            public Integer getTrailingIcon(int type) {
+            public @Nullable Integer getTrailingIcon(int type) {
                 return null;
             }
         };
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 5c348bb..e7897fc 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -2487,43 +2487,6 @@
   }
 };
 
-class SessionRestorePaintWaiter : public SessionRestoreObserver {
- public:
-  SessionRestorePaintWaiter() { SessionRestore::AddObserver(this); }
-
-  SessionRestorePaintWaiter(const SessionRestorePaintWaiter&) = delete;
-  SessionRestorePaintWaiter& operator=(const SessionRestorePaintWaiter&) =
-      delete;
-
-  ~SessionRestorePaintWaiter() { SessionRestore::RemoveObserver(this); }
-
-  // SessionRestoreObserver implementation:
-  void OnWillRestoreTab(content::WebContents* contents) override {
-    InitializePageLoadMetricsForWebContents(contents);
-    auto waiter = std::make_unique<PageLoadMetricsTestWaiter>(contents);
-    waiter->AddPageExpectation(TimingField::kFirstPaint);
-    waiter->AddPageExpectation(TimingField::kFirstContentfulPaint);
-    waiters_[contents] = std::move(waiter);
-  }
-
-  // First meaningful paints occur only on foreground tabs.
-  void WaitForForegroundTabs(size_t num_expected_foreground_tabs) {
-    size_t num_actual_foreground_tabs = 0;
-    for (auto iter = waiters_.begin(); iter != waiters_.end(); ++iter) {
-      if (iter->first->GetVisibility() == content::Visibility::HIDDEN)
-        continue;
-      iter->second->Wait();
-      ++num_actual_foreground_tabs;
-    }
-    EXPECT_EQ(num_expected_foreground_tabs, num_actual_foreground_tabs);
-  }
-
- private:
-  std::unordered_map<content::WebContents*,
-                     std::unique_ptr<PageLoadMetricsTestWaiter>>
-      waiters_;
-};
-
 IN_PROC_BROWSER_TEST_F(SessionRestorePageLoadMetricsBrowserTest,
                        InitialVisibilityOfSingleRestoredTab) {
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestURL()));
diff --git a/chrome/browser/password_manager/android/BUILD.gn b/chrome/browser/password_manager/android/BUILD.gn
index 769dcdb..0af05157 100644
--- a/chrome/browser/password_manager/android/BUILD.gn
+++ b/chrome/browser/password_manager/android/BUILD.gn
@@ -472,6 +472,18 @@
   ]
 }
 
+android_library("sms_otp_fetching_interface_java") {
+  deps = [
+    "//base:base_java",
+    "//base:service_loader_java",
+  ]
+  sources = [
+    "java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcher.java",
+    "java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactory.java",
+    "java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactoryUpstreamImpl.java",
+  ]
+}
+
 generate_jni("test_support_jni_headers") {
   testonly = true
   sources = [ "test_support/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerTestUtilsBridge.java" ]
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcher.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcher.java
new file mode 100644
index 0000000..6a29757
--- /dev/null
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcher.java
@@ -0,0 +1,19 @@
+// Copyright 2025 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.password_manager;
+
+import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+
+/** Interface for sending one time passwords requests to a downstream implementation. */
+@NullMarked
+public interface AndroidSmsOtpFetcher {
+    /**
+     * Triggers a SMS code retrieval request.
+     *
+     * @param otpValueCallback Callback that is called on success with the fetched OTP value string.
+     * @param failureCallback A callback that is called on failure for any reason.
+     */
+    void retrieveSmsOtp(Callback<String> otpValueCallback, Callback<Exception> failureCallback);
+}
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactory.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactory.java
new file mode 100644
index 0000000..f084a4e
--- /dev/null
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactory.java
@@ -0,0 +1,42 @@
+// Copyright 2025 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.password_manager;
+
+import org.chromium.base.ServiceLoaderUtil;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
+/**
+ * This factory returns an implementation for the otp fetcher. The factory itself is also
+ * implemented downstream.
+ */
+@NullMarked
+public abstract class AndroidSmsOtpFetcherFactory {
+    private static @Nullable AndroidSmsOtpFetcherFactory sInstance;
+
+    /**
+     * Returns a factory to be invoked whenever {@link #createSmsOtpFetcher()} is called. If no
+     * factory was used yet, it is created.
+     *
+     * @return The shared {@link AndroidSmsOtpFetcherFactory} instance.
+     */
+    public static AndroidSmsOtpFetcherFactory getInstance() {
+        if (sInstance == null) {
+            sInstance = ServiceLoaderUtil.maybeCreate(AndroidSmsOtpFetcherFactory.class);
+        }
+        if (sInstance == null) {
+            sInstance = new AndroidSmsOtpFetcherFactoryUpstreamImpl();
+        }
+        return sInstance;
+    }
+
+    /**
+     * Returns the downstream implementation provided by subclasses.
+     *
+     * @return An implementation of the {@link AndroidSmsOtpFetcher} if one exists.
+     */
+    public @Nullable AndroidSmsOtpFetcher createSmsOtpFetcher() {
+        return null;
+    }
+}
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactoryUpstreamImpl.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactoryUpstreamImpl.java
new file mode 100644
index 0000000..f2f6a3fd
--- /dev/null
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/AndroidSmsOtpFetcherFactoryUpstreamImpl.java
@@ -0,0 +1,13 @@
+// Copyright 2025 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.password_manager;
+
+import org.chromium.build.annotations.NullMarked;
+
+/**
+ * Instantiable version of {@link AndroidSmsOtpFetcherFactory}, don't add anything to this class.
+ * Downstream provides an actual implementation via ServiceLoader/@ServiceImpl.
+ */
+@NullMarked
+class AndroidSmsOtpFetcherFactoryUpstreamImpl extends AndroidSmsOtpFetcherFactory {}
diff --git a/chrome/browser/policy/BUILD.gn b/chrome/browser/policy/BUILD.gn
index 58d92c0..4f592ff 100644
--- a/chrome/browser/policy/BUILD.gn
+++ b/chrome/browser/policy/BUILD.gn
@@ -454,6 +454,7 @@
       "//chrome/browser/ash/policy/handlers",
       "//chrome/browser/ash/system_web_apps/apps/personalization_app",
       "//chrome/browser/ash/system_web_apps/test_support",
+      "//chrome/browser/ash/test:test_support",
       "//chrome/browser/ui/ash/keyboard",
       "//chromeos/ash/components/audio",
       "//chromeos/ash/components/cryptohome",
diff --git a/chrome/browser/policy/test/system_features_policy_browsertest.cc b/chrome/browser/policy/test/system_features_policy_browsertest.cc
index bce1ab7..7a47ab2 100644
--- a/chrome/browser/policy/test/system_features_policy_browsertest.cc
+++ b/chrome/browser/policy/test/system_features_policy_browsertest.cc
@@ -13,6 +13,8 @@
 #include "chrome/browser/ash/crostini/fake_crostini_features.h"
 #include "chrome/browser/ash/guest_os/guest_os_terminal.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/ash/test/public_account_logged_in_browser_test_mixin.h"
+#include "chrome/browser/ash/test/regular_logged_in_browser_test_mixin.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/policy/policy_test_utils.h"
 #include "chrome/browser/policy/system_features_disable_list_policy_handler.h"
@@ -22,8 +24,10 @@
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
+#include "chrome/test/base/mixin_based_in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/constants/chromeos_features.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/policy/core/common/system_features_disable_list_constants.h"
 #include "components/policy/policy_constants.h"
@@ -44,6 +48,10 @@
 const char kWebStoreExtensionURL[] = "https://chrome.google.com/webstore/";
 const char kWebStoreExtensionTitle[] = "chrome.google.com";
 
+constexpr GaiaId::Literal kFakeGaiaId("1234567890");
+constexpr char kUserEmail[] = "test@example.com";
+constexpr char kPublicAccountId[] = "public-account";
+
 struct VisibilityFlags {
   bool show_in_search;
   bool show_in_launcher;
@@ -52,19 +60,33 @@
 
 }  // namespace
 
-// TODO(413350575): Add/update tests cases to use MGS and not just regular user
-// sessions.
-class SystemFeaturesPolicyTest : public PolicyTest {
+class SystemFeaturesPolicyTestBase : public MixinBasedInProcessBrowserTest {
  public:
-  SystemFeaturesPolicyTest() {
+  SystemFeaturesPolicyTestBase() {
     scoped_feature_list_.InitWithFeatures(
         /*enabled_features=*/{ash::features::kEcheSWA, ash::features::kConch,
                               chromeos::features::
                                   kSystemFeaturesDisableListHidden},
         /*disabled_features=*/{});
+
     fake_crostini_features_.set_is_allowed_now(true);
   }
 
+  SystemFeaturesPolicyTestBase(const SystemFeaturesPolicyTestBase&) = delete;
+  SystemFeaturesPolicyTestBase& operator=(const SystemFeaturesPolicyTestBase&) =
+      delete;
+
+  ~SystemFeaturesPolicyTestBase() override = default;
+
+  void SetUpInProcessBrowserTestFixture() override {
+    MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+    provider_.SetDefaultReturns(
+        /*is_initialization_complete_return=*/true,
+        /*is_first_policy_load_complete_return=*/true);
+
+    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
+  }
+
  protected:
   std::u16string GetWebUITitle(const GURL& url,
                                bool using_navigation_throttle) {
@@ -100,12 +122,12 @@
                    POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
                    base::Value(disabled_mode), nullptr);
     }
-    // TODO(b/280518509): Remove this workaround once multidevice code
+    // TODO(280518509): Remove this workaround once multidevice code
     // supports runtime policy updates.
     policies.Set(key::kPhoneHubAllowed, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(true),
                  nullptr);
-    UpdateProviderPolicy(policies);
+    provider_.UpdateChromePolicy(policies);
   }
 
   // Convenience overload of UpdateSystemFeaturesDisableList() that allows
@@ -182,7 +204,58 @@
     return flags;
   }
 
-  void VerifyAppDisableMode(const char* app_id, const char* feature) {
+  virtual void VerifyAppDisableMode(const char* app_id,
+                                    const char* feature) = 0;
+
+  // Used for non-link-capturing PWAs.
+  void VerifyIsAppURLDisabled(const char* app_id,
+                              const char* feature,
+                              const char* url,
+                              const char* app_title) {
+    const GURL& app_url = GURL(url);
+
+    // The URL navigation is still allowed because the app is not installed,
+    // though it is disabled by policy.
+    base::Value::List system_features;
+    system_features.Append(feature);
+    UpdateSystemFeaturesDisableList(std::move(system_features), nullptr);
+    EXPECT_EQ(base::UTF8ToUTF16(app_title), GetWebUITitle(app_url, true));
+
+    // Install the app.
+    InstallPWA(app_url, app_id);
+    EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CHROME_URLS_DISABLED_PAGE_HEADER),
+              GetWebUITitle(app_url, true));
+
+    // Enable the app by removing it from the policy of disabled apps.
+    UpdateSystemFeaturesDisableList(base::Value(), nullptr);
+    EXPECT_EQ(base::UTF8ToUTF16(app_title), GetWebUITitle(app_url, true));
+  }
+
+  void VerifyIsExtensionAppURLAccessible(const char* url,
+                                         const char* app_title) {
+    const GURL& app_url = GURL(url);
+    EXPECT_EQ(base::UTF8ToUTF16(app_title), GetWebUITitle(app_url, true));
+  }
+
+ private:
+  testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  // Fake the Crostini feature to have the Terminal app icon show in the
+  // launcher when installed.
+  crostini::FakeCrostiniFeatures fake_crostini_features_;
+};
+
+// Tests the behavior of SystemFeaturesDisableList and SystemFeaturesDisableMode
+// policies in regular user sessions.
+class SystemFeaturesPolicyTest : public SystemFeaturesPolicyTestBase {
+ public:
+  SystemFeaturesPolicyTest()
+      : account_id_(AccountId::FromUserEmailGaiaId(kUserEmail, kFakeGaiaId)) {}
+
+ protected:
+  void VerifyAppDisableMode(const char* app_id, const char* feature) override {
     base::Value::List system_features;
     system_features.Append(feature);
     VisibilityFlags expected_visibility =
@@ -233,17 +306,9 @@
     EXPECT_EQ(base::UTF8ToUTF16(app_title), GetWebUITitle(app_url, true));
   }
 
-  void VerifyIsExtensionAppURLAccessible(const char* url,
-                                         const char* app_title) {
-    const GURL& app_url = GURL(url);
-    EXPECT_EQ(base::UTF8ToUTF16(app_title), GetWebUITitle(app_url, true));
-  }
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  // Fake the Crostini feature to have the Terminal app icon show in the
-  // launcher when installed.
-  crostini::FakeCrostiniFeatures fake_crostini_features_;
+  const AccountId account_id_;
+  ash::RegularLoggedInBrowserTestMixin logged_in_mixin_{&mixin_host_,
+                                                        account_id_};
 };
 
 IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, DisableWebStoreBeforeInstall) {
@@ -269,30 +334,6 @@
                                     kWebStoreExtensionTitle);
 }
 
-IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, DisableWebStoreAfterInstall) {
-  EnableExtensions(false);
-  base::Value::List system_features;
-  system_features.Append(kWebStoreFeature);
-  VisibilityFlags expected_visibility =
-      GetVisibilityFlags(true /* is_hidden */);
-  UpdateSystemFeaturesDisableList(std::move(system_features), nullptr);
-
-  VerifyExtensionAppState(extensions::kWebStoreAppId,
-                          apps::Readiness::kDisabledByPolicy, true,
-                          expected_visibility);
-  // The URL navigation should still be possible
-  // even if the app is disabled by policy.
-  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
-                                    kWebStoreExtensionTitle);
-
-  UpdateSystemFeaturesDisableList(base::Value(), nullptr);
-  expected_visibility = GetVisibilityFlags(false /* is_hidden */);
-  VerifyExtensionAppState(extensions::kWebStoreAppId, apps::Readiness::kReady,
-                          false, expected_visibility);
-  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
-                                    kWebStoreExtensionTitle);
-}
-
 IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest,
                        DisableWebStoreAfterInstallWithModes) {
   EnableExtensions(false);
@@ -363,7 +404,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest,
-                       DisableMultipleAppsWithHiddenModeAfterInstall) {
+                       DisableMultipleAppsWithBlockedModeAfterInstall) {
   InstallSWAs();
   InstallPWA(GURL(kCanvasAppURL), ash::kCanvasAppId);
 
@@ -461,7 +502,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest,
-                       DisableMultipleAppsWithHiddenModeBeforeInstall) {
+                       DisableMultipleAppsWithBlockedModeBeforeInstall) {
   const base::Value::List system_features = base::Value::List()
                                                 .Append(kCameraFeature)
                                                 .Append(kScanningFeature)
@@ -541,4 +582,285 @@
   VerifyAppDisableMode(ash::kCanvasAppId, kCanvasFeature);
 }
 
+// Tests the behavior of SystemFeaturesDisableList and SystemFeaturesDisableMode
+// policies in MGS sessions.
+class MgsSystemFeaturesPolicyTest : public SystemFeaturesPolicyTestBase {
+ public:
+  MgsSystemFeaturesPolicyTest() = default;
+
+  MgsSystemFeaturesPolicyTest(const MgsSystemFeaturesPolicyTest&) = delete;
+  MgsSystemFeaturesPolicyTest& operator=(const MgsSystemFeaturesPolicyTest&) =
+      delete;
+
+  ~MgsSystemFeaturesPolicyTest() override = default;
+
+  void VerifyAppDisableMode(const char* app_id, const char* feature) override {
+    base::Value::List system_features;
+    system_features.Append(feature);
+    VisibilityFlags expected_visibility =
+        GetVisibilityFlags(false /* is_hidden */);
+    // Disable app with default mode (hidden).
+    UpdateSystemFeaturesDisableList(system_features.Clone(), nullptr);
+    VerifyAppState(app_id, apps::Readiness::kDisabledByPolicy, true,
+                   expected_visibility);
+    // Disable and hide app.
+    expected_visibility = GetVisibilityFlags(true /* is_hidden */);
+    UpdateSystemFeaturesDisableList(system_features.Clone(),
+                                    kSystemFeaturesDisableModeHidden);
+    VerifyAppState(app_id, apps::Readiness::kDisabledByPolicy, true,
+                   expected_visibility);
+    // Disable and block app.
+    expected_visibility = GetVisibilityFlags(false /* is_hidden */);
+    UpdateSystemFeaturesDisableList(system_features.Clone(),
+                                    kSystemFeaturesDisableModeBlocked);
+    VerifyAppState(app_id, apps::Readiness::kDisabledByPolicy, true,
+                   expected_visibility);
+    // Enable app.
+    UpdateSystemFeaturesDisableList(base::Value(), nullptr);
+    VerifyAppState(app_id, apps::Readiness::kReady, false, expected_visibility);
+  }
+
+ private:
+  ash::PublicAccountLoggedInBrowserTestMixin logged_in_mixin_{&mixin_host_,
+                                                              kPublicAccountId};
+};
+
+IN_PROC_BROWSER_TEST_F(MgsSystemFeaturesPolicyTest,
+                       DisableWebStoreBeforeInstall) {
+  base::Value::List system_features;
+  system_features.Append(kWebStoreFeature);
+  VisibilityFlags expected_visibility =
+      GetVisibilityFlags(false /* is_hidden */);
+  UpdateSystemFeaturesDisableList(std::move(system_features), nullptr);
+  EnableExtensions(true);
+  VerifyExtensionAppState(extensions::kWebStoreAppId,
+                          apps::Readiness::kDisabledByPolicy, true,
+                          expected_visibility);
+  // The URL navigation should still be possible
+  // even if the app is disabled by policy.
+  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
+                                    kWebStoreExtensionTitle);
+
+  UpdateSystemFeaturesDisableList(base::Value(), nullptr);
+  // expected_visibility = GetVisibilityFlags(false /* is_hidden */);
+  VerifyExtensionAppState(extensions::kWebStoreAppId, apps::Readiness::kReady,
+                          false, expected_visibility);
+  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
+                                    kWebStoreExtensionTitle);
+}
+
+IN_PROC_BROWSER_TEST_F(MgsSystemFeaturesPolicyTest,
+                       DisableWebStoreAfterInstallWithModes) {
+  EnableExtensions(false);
+  base::Value::List system_features;
+  system_features.Append(kWebStoreFeature);
+  VisibilityFlags expected_visibility =
+      GetVisibilityFlags(false /* is_hidden */);
+  // Disable app with default mode (blocked).
+  // The URL navigation should still be possible
+  // even if the app is disabled by policy.
+  UpdateSystemFeaturesDisableList(system_features.Clone(), nullptr);
+  VerifyExtensionAppState(extensions::kWebStoreAppId,
+                          apps::Readiness::kDisabledByPolicy, true,
+                          expected_visibility);
+  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
+                                    kWebStoreExtensionTitle);
+
+  // Disable and hide app.
+  expected_visibility = GetVisibilityFlags(true /* is_hidden */);
+  UpdateSystemFeaturesDisableList(system_features.Clone(),
+                                  kSystemFeaturesDisableModeHidden);
+  VerifyExtensionAppState(extensions::kWebStoreAppId,
+                          apps::Readiness::kDisabledByPolicy, true,
+                          expected_visibility);
+  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
+                                    kWebStoreExtensionTitle);
+
+  // Disable and block app.
+  expected_visibility = GetVisibilityFlags(false /* is_hidden */);
+  UpdateSystemFeaturesDisableList(system_features.Clone(),
+                                  kSystemFeaturesDisableModeBlocked);
+  VerifyExtensionAppState(extensions::kWebStoreAppId,
+                          apps::Readiness::kDisabledByPolicy, true,
+                          expected_visibility);
+  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
+                                    kWebStoreExtensionTitle);
+
+  // Enable app
+  UpdateSystemFeaturesDisableList(base::Value(), nullptr);
+  VerifyExtensionAppState(extensions::kWebStoreAppId, apps::Readiness::kReady,
+                          false, expected_visibility);
+  VerifyIsExtensionAppURLAccessible(kWebStoreExtensionURL,
+                                    kWebStoreExtensionTitle);
+}
+
+IN_PROC_BROWSER_TEST_F(MgsSystemFeaturesPolicyTest, DisableSWAs) {
+  InstallSWAs();
+
+  // Disable Camera app.
+  VerifyAppDisableMode(ash::kCameraAppId, kCameraFeature);
+
+  // Disable Explore app.
+  VerifyAppDisableMode(ash::kHelpAppId, kExploreFeature);
+
+  // Disable Gallery app.
+  VerifyAppDisableMode(ash::kMediaAppId, kGalleryFeature);
+
+  // Disable Terminal app.
+  VerifyAppDisableMode(guest_os::kTerminalSystemAppId, kTerminalFeature);
+
+  // Disable Print Jobs app.
+  VerifyAppDisableMode(ash::kPrintManagementAppId, kPrintJobsFeature);
+
+  // Disable Key Shortcuts app.
+  VerifyAppDisableMode(ash::kShortcutCustomizationAppId, kKeyShortcutsFeature);
+
+  // Disable Recorder app.
+  VerifyAppDisableMode(ash::kRecorderAppId, kRecorderFeature);
+}
+
+IN_PROC_BROWSER_TEST_F(MgsSystemFeaturesPolicyTest,
+                       DisableMultipleAppsWithHiddenModeAfterInstall) {
+  InstallSWAs();
+  InstallPWA(GURL(kCanvasAppURL), ash::kCanvasAppId);
+
+  // Disable app with hidden mode.
+  const base::Value::List system_features = base::Value::List()
+                                                .Append(kCameraFeature)
+                                                .Append(kScanningFeature)
+                                                .Append(kWebStoreFeature)
+                                                .Append(kCanvasFeature)
+                                                .Append(kCroshFeature)
+                                                .Append(kGalleryFeature)
+                                                .Append(kTerminalFeature)
+                                                .Append(kPrintJobsFeature)
+                                                .Append(kKeyShortcutsFeature)
+                                                .Append(kRecorderFeature);
+  UpdateSystemFeaturesDisableList(system_features.Clone(),
+                                  kSystemFeaturesDisableModeHidden);
+
+  VisibilityFlags expected_visibility =
+      GetVisibilityFlags(true /* is_hidden */);
+  VerifyAppState(ash::kCameraAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kScanningAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyExtensionAppState(extensions::kWebStoreAppId,
+                          apps::Readiness::kDisabledByPolicy, true,
+                          expected_visibility);
+  VerifyAppState(ash::kCanvasAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kCroshAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kMediaAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(guest_os::kTerminalSystemAppId,
+                 apps::Readiness::kDisabledByPolicy, true, expected_visibility);
+  VerifyAppState(ash::kPrintManagementAppId, apps::Readiness::kDisabledByPolicy,
+                 true, expected_visibility);
+  VerifyAppState(ash::kShortcutCustomizationAppId,
+                 apps::Readiness::kDisabledByPolicy, true, expected_visibility);
+  VerifyAppState(ash::kRecorderAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+
+  // Disable and block apps.
+  expected_visibility = GetVisibilityFlags(false /* is_hidden */);
+  // Crosh is never shown.
+  VisibilityFlags crosh_expected_visibility =
+      GetVisibilityFlags(true /* is_hidden */);
+  UpdateSystemFeaturesDisableList(system_features.Clone(),
+                                  kSystemFeaturesDisableModeBlocked);
+
+  VerifyAppState(ash::kCameraAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kScanningAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyExtensionAppState(extensions::kWebStoreAppId,
+                          apps::Readiness::kDisabledByPolicy, true,
+                          expected_visibility);
+  VerifyAppState(ash::kCanvasAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kCroshAppId, apps::Readiness::kDisabledByPolicy, true,
+                 crosh_expected_visibility);
+  VerifyAppState(ash::kMediaAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(guest_os::kTerminalSystemAppId,
+                 apps::Readiness::kDisabledByPolicy, true, expected_visibility);
+  VerifyAppState(ash::kPrintManagementAppId, apps::Readiness::kDisabledByPolicy,
+                 true, expected_visibility);
+  VerifyAppState(ash::kShortcutCustomizationAppId,
+                 apps::Readiness::kDisabledByPolicy, true, expected_visibility);
+  VerifyAppState(ash::kRecorderAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+
+  // Enable apps.
+  UpdateSystemFeaturesDisableList(base::Value(), nullptr);
+  VerifyAppState(ash::kCameraAppId, apps::Readiness::kReady, false,
+                 expected_visibility);
+  VerifyAppState(ash::kScanningAppId, apps::Readiness::kReady, false,
+                 expected_visibility);
+  VerifyExtensionAppState(extensions::kWebStoreAppId, apps::Readiness::kReady,
+                          false, expected_visibility);
+  VerifyAppState(ash::kCanvasAppId, apps::Readiness::kReady, false,
+                 expected_visibility);
+  VerifyAppState(ash::kCroshAppId, apps::Readiness::kReady, false,
+                 crosh_expected_visibility);
+  VerifyAppState(ash::kMediaAppId, apps::Readiness::kReady, false,
+                 expected_visibility);
+  VerifyAppState(guest_os::kTerminalSystemAppId, apps::Readiness::kReady, false,
+                 expected_visibility);
+  VerifyAppState(ash::kPrintManagementAppId, apps::Readiness::kReady, false,
+                 expected_visibility);
+  VerifyAppState(ash::kShortcutCustomizationAppId, apps::Readiness::kReady,
+                 false, expected_visibility);
+  VerifyAppState(ash::kRecorderAppId, apps::Readiness::kReady, false,
+                 expected_visibility);
+}
+
+IN_PROC_BROWSER_TEST_F(MgsSystemFeaturesPolicyTest,
+                       DisableMultipleAppsWithHiddenModeBeforeInstall) {
+  const base::Value::List system_features = base::Value::List()
+                                                .Append(kCameraFeature)
+                                                .Append(kScanningFeature)
+                                                .Append(kWebStoreFeature)
+                                                .Append(kCanvasFeature)
+                                                .Append(kCroshFeature)
+                                                .Append(kGalleryFeature)
+                                                .Append(kTerminalFeature)
+                                                .Append(kPrintJobsFeature)
+                                                .Append(kKeyShortcutsFeature)
+                                                .Append(kRecorderFeature);
+  UpdateSystemFeaturesDisableList(system_features.Clone(),
+                                  kSystemFeaturesDisableModeHidden);
+
+  InstallSWAs();
+  InstallPWA(GURL(kCanvasAppURL), ash::kCanvasAppId);
+
+  VisibilityFlags expected_visibility =
+      GetVisibilityFlags(true /* is_hidden */);
+
+  // Disable app with hidden mode.
+  VerifyAppState(ash::kCameraAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kScanningAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyExtensionAppState(extensions::kWebStoreAppId,
+                          apps::Readiness::kDisabledByPolicy, true,
+                          expected_visibility);
+  VerifyAppState(ash::kCanvasAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kCroshAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(ash::kMediaAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+  VerifyAppState(guest_os::kTerminalSystemAppId,
+                 apps::Readiness::kDisabledByPolicy, true, expected_visibility);
+  VerifyAppState(ash::kPrintManagementAppId, apps::Readiness::kDisabledByPolicy,
+                 true, expected_visibility);
+  VerifyAppState(ash::kShortcutCustomizationAppId,
+                 apps::Readiness::kDisabledByPolicy, true, expected_visibility);
+  VerifyAppState(ash::kRecorderAppId, apps::Readiness::kDisabledByPolicy, true,
+                 expected_visibility);
+}
+
 }  // namespace policy
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index b95b24b..93d3420d 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -558,12 +558,6 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS)
-// Deprecated 04/2024
-constexpr char kLastUploadedEuiccStatusPrefLegacy[] =
-    "esim.last_upload_euicc_status";
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-#if BUILDFLAG(IS_CHROMEOS)
 // Deprecated 05/2024.
 // A preference to keep track of the device registered time.
 constexpr char kDeviceRegisteredTime[] = "DeviceRegisteredTime";
@@ -1119,9 +1113,6 @@
   // Deprecated 05/2024.
   registry->RegisterTimePref(kDeviceRegisteredTime, base::Time());
   registry->RegisterDictionaryPref(kArcKioskDictionaryName);
-
-  // Deprecated 04/2024.
-  registry->RegisterDictionaryPref(kLastUploadedEuiccStatusPrefLegacy);
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if !BUILDFLAG(IS_ANDROID)
@@ -2366,9 +2357,6 @@
   // Added 05/2024.
   local_state->ClearPref(kDeviceRegisteredTime);
   local_state->ClearPref(kArcKioskDictionaryName);
-
-  // Added 04/2024.
-  local_state->ClearPref(kLastUploadedEuiccStatusPrefLegacy);
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/privacy_budget/privacy_budget_browsertest_util.cc b/chrome/browser/privacy_budget/privacy_budget_browsertest_util.cc
index 81f4bbe..470b180 100644
--- a/chrome/browser/privacy_budget/privacy_budget_browsertest_util.cc
+++ b/chrome/browser/privacy_budget/privacy_budget_browsertest_util.cc
@@ -107,7 +107,7 @@
 
   // UpdateUploadPermissions causes the MetricsServicesManager to look at the
   // consent signals and re-evaluate whether reporting should be enabled.
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
 
   // The following sequence synchronously completes UkmService initialization
   // (if it wasn't initialized yet) and flushes any accumulated metrics.
@@ -125,7 +125,7 @@
       << "DisableUkmRecording() should only be called after "
          "EnableUkmRecording()";
   is_metrics_reporting_enabled_ = false;
-  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
+  g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions();
   ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(nullptr);
   return !ukm::UkmTestHelper(ukm_service()).IsRecordingEnabled();
 }
diff --git a/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_done.xml b/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_done.xml
index 63dded2..8a7a17a 100644
--- a/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_done.xml
+++ b/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_done.xml
@@ -28,6 +28,7 @@
             app:srcCompat="@drawable/privacy_guide_done_image" />
 
         <TextView
+            android:id="@+id/done_step_header"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/privacy_guide_done_title"
diff --git a/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_sb_step.xml b/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_sb_step.xml
index b4bb42d..c3fdaf4 100644
--- a/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_sb_step.xml
+++ b/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_sb_step.xml
@@ -31,6 +31,7 @@
             android:importantForAccessibility="no" />
 
         <TextView
+            android:id="@+id/sb_step_header"
             android:drawablePadding="16dp"
             android:layout_marginHorizontal="@dimen/all_content_marginHorizontal"
             android:layout_marginVertical="8dp"
diff --git a/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_welcome.xml b/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_welcome.xml
index 1ae34a15..1effa2d 100644
--- a/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_welcome.xml
+++ b/chrome/browser/privacy_guide/android/java/res/layout/privacy_guide_welcome.xml
@@ -29,6 +29,7 @@
             app:srcCompat="@drawable/privacy_guide_welcome_image" />
 
         <TextView
+            android:id="@+id/welcome_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginBottom="16dp"
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 80ffcbd..716ded7 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
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.privacy_guide;
 
 import static org.chromium.build.NullUtil.assumeNonNull;
+import static org.chromium.chrome.browser.privacy_guide.PrivacyGuideUtils.getFragmentFocusViewId;
 
 import android.os.Bundle;
 import android.view.LayoutInflater;
@@ -13,6 +14,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 
 import androidx.annotation.IntDef;
 import androidx.appcompat.app.AppCompatActivity;
@@ -97,6 +99,7 @@
     private PrivacyGuideMetricsDelegate mPrivacyGuideMetricsDelegate;
     private NavbarVisibilityDelegate mNavbarVisibilityDelegate;
     private Profile mProfile;
+    private ViewPager2.OnPageChangeCallback mOnPageChangeCallback;
 
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -126,6 +129,30 @@
         mViewPager.setPageTransformer(new PrivacyGuidePageTransformer());
         mViewPager.setUserInputEnabled(false);
 
+        mOnPageChangeCallback =
+                new ViewPager2.OnPageChangeCallback() {
+                    @Override
+                    public void onPageScrollStateChanged(int state) {
+                        super.onPageScrollStateChanged(state);
+
+                        // We only want to send the accessibility event when the view pager
+                        // transition is complete.
+                        if (state != ViewPager2.SCROLL_STATE_IDLE) {
+                            return;
+                        }
+
+                        View targetView =
+                                mView.findViewById(
+                                        getFragmentFocusViewId(
+                                                mPagerAdapter.getFragmentType(
+                                                        mViewPager.getCurrentItem())));
+                        if (targetView != null) {
+                            targetView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+                        }
+                    }
+                };
+        mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback);
+
         mTabLayout = mView.findViewById(R.id.tab_layout);
         new TabLayoutMediator(
                         mTabLayout,
@@ -174,6 +201,14 @@
         mHandleBackPressChangedSupplier.set(shouldHandleBackPress());
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mOnPageChangeCallback != null) {
+            mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback);
+        }
+    }
+
     private void modifyAppBar() {
         AppCompatActivity settingsActivity = (AppCompatActivity) getActivity();
         settingsActivity.setTitle(R.string.privacy_guide_fragment_title);
diff --git a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideUtils.java b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideUtils.java
index 5c0ddb7..6f26e86aa 100644
--- a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideUtils.java
+++ b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideUtils.java
@@ -9,6 +9,7 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
+import org.chromium.chrome.browser.privacy_guide.PrivacyGuideFragment.FragmentType;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.safe_browsing.SafeBrowsingBridge;
 import org.chromium.chrome.browser.safe_browsing.SafeBrowsingState;
@@ -94,4 +95,26 @@
         }
         return true;
     }
+
+    static int getFragmentFocusViewId(@FragmentType int fragmentType) {
+        switch (fragmentType) {
+            case FragmentType.WELCOME:
+                return R.id.welcome_view;
+            case FragmentType.MSBB:
+                return R.id.msbb_switch;
+            case FragmentType.HISTORY_SYNC:
+                return R.id.history_sync_switch;
+            case FragmentType.SAFE_BROWSING:
+                return R.id.sb_step_header;
+            case FragmentType.COOKIES:
+                return R.id.cookies_step_header;
+            case FragmentType.AD_TOPICS:
+                return R.id.ad_topics_switch;
+            case FragmentType.DONE:
+                return R.id.done_step_header;
+            default:
+                assert false : "Unexpected fragment type: " + fragmentType;
+                return -1;
+        }
+    }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
index ff53c69..003e456 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
@@ -62,10 +62,10 @@
 import org.chromium.chrome.browser.translate.TranslateBridge;
 import org.chromium.chrome.browser.translate.TranslationObserver;
 import org.chromium.chrome.browser.user_education.UserEducationHelper;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
+import org.chromium.chrome.modules.readaloud.Feedback.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.Playback;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackModeSelectionEnablementStatus;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/InteractionHandler.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/InteractionHandler.java
index e5987a7..35867ad 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/InteractionHandler.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/InteractionHandler.java
@@ -7,8 +7,8 @@
 import android.widget.SeekBar;
 
 import org.chromium.build.annotations.NullMarked;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.NegativeFeedbackReason;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
+import org.chromium.chrome.modules.readaloud.Feedback.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
 
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
index 3988c74..a42e954 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
@@ -40,8 +40,8 @@
 import org.chromium.chrome.browser.readaloud.player.mini.MiniPlayerCoordinator;
 import org.chromium.chrome.browser.readaloud.player.mini.MiniPlayerLayout;
 import org.chromium.chrome.browser.readaloud.testing.MockPrefServiceHelper;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
 import org.chromium.chrome.modules.readaloud.Playback;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
 import org.chromium.chrome.modules.readaloud.Player;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java
index 328aaaa9..e59c74b71 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java
@@ -19,9 +19,9 @@
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.readaloud.ReadAloudMetrics;
 import org.chromium.chrome.browser.readaloud.ReadAloudPrefs;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
+import org.chromium.chrome.modules.readaloud.Feedback.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.Playback;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackModeSelectionEnablementStatus;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java
index 5f0cbdf..c48eef3 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java
@@ -52,9 +52,9 @@
 import org.chromium.chrome.browser.readaloud.ReadAloudPrefs;
 import org.chromium.chrome.browser.readaloud.ReadAloudPrefsJni;
 import org.chromium.chrome.browser.readaloud.testing.MockPrefServiceHelper;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
+import org.chromium.chrome.modules.readaloud.Feedback.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.Playback;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.NegativeFeedbackReason;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackModeSelectionEnablementStatus;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
index ebc9be27..2068909 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
@@ -28,7 +28,7 @@
 import org.chromium.chrome.browser.readaloud.player.PlayerProperties;
 import org.chromium.chrome.browser.readaloud.player.R;
 import org.chromium.chrome.browser.readaloud.player.TouchDelegateUtil;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackModeSelectionEnablementStatus;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java
index 1e88d48..67e583a 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java
@@ -7,7 +7,7 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.readaloud.player.PlayerProperties;
 import org.chromium.chrome.browser.readaloud.player.VisibilityState;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.FeedbackType;
+import org.chromium.chrome.modules.readaloud.Feedback.FeedbackType;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackModeSelectionEnablementStatus;
 import org.chromium.ui.modelutil.PropertyKey;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java
index 89944b47..05b5b38 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java
@@ -20,7 +20,7 @@
 import org.chromium.chrome.browser.readaloud.player.Colors;
 import org.chromium.chrome.browser.readaloud.player.InteractionHandler;
 import org.chromium.chrome.browser.readaloud.player.R;
-import org.chromium.chrome.modules.readaloud.PlaybackArgs.NegativeFeedbackReason;
+import org.chromium.chrome.modules.readaloud.Feedback.NegativeFeedbackReason;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 4b265410..14bacc2 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -531,7 +531,7 @@
        //     from the line below this comment block.
        //   - Increment the UMA value in that latter line.
        //   - Add the new item to the RenderViewContextMenuItem enum in
-       //     tools/metrics/histograms/enums.xml.
+       //     tools/metrics/histograms/metadata/ui/enums.xml.
        {0, 156}});
 
   // These UMA values are for the ContextMenuOptionDesktop enum, used for
@@ -1066,7 +1066,6 @@
 }
 
 std::u16string RenderViewContextMenu::FormatURLForClipboard(const GURL& url) {
-  DCHECK(!url.is_empty());
   DCHECK(url.is_valid());
 
   GURL url_to_format = url;
@@ -1089,8 +1088,8 @@
                                   nullptr, nullptr, nullptr);
 }
 
-void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
-  if (url.is_empty() || !url.is_valid()) {
+void RenderViewContextMenu::WriteURLToClipboard(const GURL& url, int id) {
+  if (!url.is_valid()) {
     return;
   }
 
@@ -1099,6 +1098,16 @@
       CreateDataEndpoint(/*notify_if_restricted=*/true));
   scw.SetDataSourceURL(main_frame_url_, current_url_);
   scw.WriteText(FormatURLForClipboard(url));
+
+#if !BUILDFLAG(IS_ANDROID)
+  if (id == IDC_CONTENT_CONTEXT_COPYLINKLOCATION &&
+      toast_features::IsEnabled(toast_features::kLinkCopiedToast)) {
+    auto* const toast_controller = GetToastController();
+    if (toast_controller) {
+      toast_controller->MaybeShowToast(ToastParams(ToastId::kLinkCopied));
+    }
+  }
+#endif
 }
 
 void RenderViewContextMenu::IssuePreconnectionToUrl(
@@ -3268,15 +3277,7 @@
       break;
 
     case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
-      WriteURLToClipboard(params_.unfiltered_link_url);
-#if !BUILDFLAG(IS_ANDROID)
-      if (toast_features::IsEnabled(toast_features::kLinkCopiedToast)) {
-        auto* const toast_controller = GetToastController();
-        if (toast_controller) {
-          toast_controller->MaybeShowToast(ToastParams(ToastId::kLinkCopied));
-        }
-      }
-#endif
+      WriteURLToClipboard(params_.unfiltered_link_url, id);
       break;
 
     case IDC_CONTENT_CONTEXT_COPYLINKTEXT:
@@ -3285,19 +3286,11 @@
 
     case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
     case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
-      WriteURLToClipboard(params_.src_url);
+      WriteURLToClipboard(params_.src_url, id);
       break;
 
     case IDC_CONTENT_CONTEXT_COPYIMAGE:
       ExecCopyImageAt();
-#if !BUILDFLAG(IS_ANDROID)
-      if (toast_features::IsEnabled(toast_features::kImageCopiedToast)) {
-        auto* const toast_controller = GetToastController();
-        if (toast_controller) {
-          toast_controller->MaybeShowToast(ToastParams(ToastId::kImageCopied));
-        }
-      }
-#endif
       break;
 
     case IDC_CONTENT_CONTEXT_SAVEVIDEOFRAMEAS:
@@ -4322,9 +4315,20 @@
 
 void RenderViewContextMenu::ExecCopyImageAt() {
   RenderFrameHost* frame_host = GetRenderFrameHost();
-  if (frame_host) {
-    frame_host->CopyImageAt(params_.x, params_.y);
+  if (!frame_host) {
+    return;
   }
+
+  frame_host->CopyImageAt(params_.x, params_.y);
+
+#if !BUILDFLAG(IS_ANDROID)
+  if (toast_features::IsEnabled(toast_features::kImageCopiedToast)) {
+    auto* const toast_controller = GetToastController();
+    if (toast_controller) {
+      toast_controller->MaybeShowToast(ToastParams(ToastId::kImageCopied));
+    }
+  }
+#endif
 }
 
 void RenderViewContextMenu::ExecSearchLensForImage(int event_flags) {
@@ -4513,6 +4517,14 @@
   MediaPlayerAction(blink::mojom::MediaPlayerAction(
       blink::mojom::MediaPlayerActionType::kCopyVideoFrame,
       /*enable=*/true));
+#if !BUILDFLAG(IS_ANDROID)
+  if (toast_features::IsEnabled(toast_features::kVideoFrameCopiedToast)) {
+    auto* const toast_controller = GetToastController();
+    if (toast_controller) {
+      toast_controller->MaybeShowToast(ToastParams(ToastId::kVideoFrameCopied));
+    }
+  }
+#endif
 }
 
 void RenderViewContextMenu::ExecSearchForVideoFrame(int event_flags,
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index 9bf603d..ef71da5 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -250,8 +250,8 @@
   // clipboard. |url| must be valid and non-empty.
   static std::u16string FormatURLForClipboard(const GURL& url);
 
-  // Writes the specified text/url to the system clipboard.
-  void WriteURLToClipboard(const GURL& url);
+  // Writes the specified url to the system clipboard.
+  void WriteURLToClipboard(const GURL& url, int id);
 
   // Issues a preconnection request to the given url.
   void IssuePreconnectionToUrl(const std::string& anonymization_key_url,
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index 1d765118..4241131e 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -214,7 +214,8 @@
         {media::kContextMenuSaveVideoFrameAs,
          media::kContextMenuSearchForVideoFrame,
          toast_features::kLinkCopiedToast, toast_features::kImageCopiedToast,
-         toast_features::kToastFramework},
+         toast_features::kToastFramework,
+         toast_features::kVideoFrameCopiedToast},
         {});
   }
 
@@ -1365,6 +1366,15 @@
   EXPECT_TRUE(browser()->GetFeatures().toast_controller()->IsShowingToast());
 }
 
+IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, ShowsToastOnVideoFrameCopied) {
+  content::ContextMenuParams params;
+  params.media_type = blink::mojom::ContextMenuDataMediaType::kCanvas;
+
+  auto menu = CreateContextMenuFromParams(params);
+  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_COPYVIDEOFRAME, /*event_flags=*/0);
+  EXPECT_TRUE(browser()->GetFeatures().toast_controller()->IsShowingToast());
+}
+
 IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                        ShowToastOnSidePanelContextMenus) {
   auto* const side_panel_ui = browser()->GetFeatures().side_panel_ui();
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 2a89fabb..f5f79d9a 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -45,7 +45,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
-#include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/common/chrome_constants.h"
@@ -81,30 +80,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // TabManager
 
-class TabManager::TabManagerSessionRestoreObserver final
-    : public SessionRestoreObserver {
- public:
-  explicit TabManagerSessionRestoreObserver(TabManager* tab_manager)
-      : tab_manager_(tab_manager) {
-    SessionRestore::AddObserver(this);
-  }
-
-  ~TabManagerSessionRestoreObserver() { SessionRestore::RemoveObserver(this); }
-
-  // SessionRestoreObserver implementation:
-  void OnWillRestoreTab(WebContents* web_contents) override {
-    tab_manager_->OnWillRestoreTab(web_contents);
-  }
-
- private:
-  raw_ptr<TabManager> tab_manager_;
-};
-
-TabManager::TabManager() {
-  session_restore_observer_ =
-      std::make_unique<TabManagerSessionRestoreObserver>(this);
-}
-
+TabManager::TabManager() = default;
 TabManager::~TabManager() = default;
 
 void TabManager::Start() {
@@ -196,14 +172,6 @@
   return nullptr;
 }
 
-void TabManager::OnWillRestoreTab(WebContents* contents) {
-  // TabUIHelper is initialized in TabHelpers::AttachTabHelpers. But this place
-  // gets called earlier than that. So for restored tabs, also initialize their
-  // TabUIHelper here.
-  TabUIHelper::CreateForWebContents(contents);
-  TabUIHelper::FromWebContents(contents)->set_created_by_session_restore(true);
-}
-
 void TabManager::OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) {
   lifecycle_units_.erase(lifecycle_unit);
 }
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 95c6d43..d92881f 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -116,7 +116,6 @@
 
   void OnSessionRestoreStartedLoadingTabs();
   void OnSessionRestoreFinishedLoadingTabs();
-  void OnWillRestoreTab(content::WebContents* contents);
 
   // Returns the number of tabs that are not pending load or discarded.
   int GetNumAliveTabs() const;
@@ -133,9 +132,6 @@
   // A listener to global memory pressure events.
   std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
 
-  class TabManagerSessionRestoreObserver;
-  std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_;
-
   // Weak pointer factory used for posting delayed tasks.
   base::WeakPtrFactory<TabManager> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn
index c908868..ad0fec9 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn
@@ -37,6 +37,7 @@
   "dictation/earcons/audio_end.wav",
   "dictation/earcons/audio_initiate.wav",
   "dictation/earcons/null_selection.wav",
+  "dictation/offscreen.html",
 ]
 
 # TS files to build.
@@ -51,6 +52,7 @@
   "dictation/metrics_utils.ts",
   "dictation/ui_controller.ts",
   "dictation/macros/list_commands_macro.ts",
+  "dictation/offscreen_audio.ts",
   "dictation/parse/input_text_strategy.ts",
   "dictation/parse/parse_strategy.ts",
   "dictation/parse/pumpkin_parse_strategy.ts",
@@ -72,6 +74,7 @@
   "facegaze/macros/mouse_scroll_macro.ts",
   "facegaze/macros/reset_cursor_macro.ts",
   "magnifier/magnifier.ts",
+  "offscreen_command_type.ts",
 ]
 
 # The relative path in the staging directory of TS modules that need to be copied from another directory.
@@ -91,6 +94,7 @@
   "../../definitions/input_method_private.d.ts",
   "../../definitions/language_settings_private.d.ts",
   "../../definitions/metrics_private.d.ts",
+  "../../definitions/offscreen.d.ts",
   "../../definitions/runtime.d.ts",
   "../../definitions/settings_private_mv2.d.ts",
   "../../definitions/speech_recognition_private.d.ts",
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts
index 36e927b95..95b94779 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts
@@ -22,6 +22,9 @@
  * are enabled.
  */
 export class AccessibilityCommon {
+  private static offscreenDocumentPromises_: Map<string, Promise<void>> =
+      new Map();
+
   private autoclick_: Autoclick|null = null;
   private magnifier_: Magnifier|null = null;
   private dictation_: Dictation|null = null;
@@ -45,6 +48,32 @@
   static async init(): Promise<void> {
     await Flags.init();
     globalThis.accessibilityCommon = new AccessibilityCommon();
+    return AccessibilityCommon.initializeOffscreenDocuments();
+  }
+
+  static async initializeOffscreenDocuments(): Promise<void> {
+    await Promise.all([this.maybeCreateOffscreenDocument(
+        'accessibility_common/mv3/dictation/offscreen.html')]);
+  }
+
+  static async maybeCreateOffscreenDocument(url: string): Promise<void> {
+    const offscreenUrl = chrome.runtime.getURL(url);
+    const existingContexts = await chrome.runtime.getContexts({
+      contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT],
+      documentUrls: [offscreenUrl]
+    });
+    if (existingContexts.length > 0) {
+      return;
+    }
+    if (!this.offscreenDocumentPromises_.has(url)) {
+      const promise = chrome.offscreen.createDocument({
+        url: offscreenUrl,
+        reasons: [chrome.offscreen.Reason.WORKERS],
+        justification: 'Audio web API and web assembly execution',
+      });
+      await promise;
+      this.offscreenDocumentPromises_.set(url, promise);
+    }
   }
 
   getAutoclickForTest(): Autoclick|null {
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/dictation.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/dictation.ts
index 1ec0053..87a7c2d 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/dictation.ts
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/dictation.ts
@@ -7,6 +7,8 @@
 import {MacroName} from '/common/action_fulfillment/macros/macro_names.js';
 import {TestImportManager} from '/common/testing/test_import_manager.js';
 
+import {OffscreenCommandType} from '../offscreen_command_type.js';
+
 import {FocusHandler} from './focus_handler.js';
 import {InputControllerImpl} from './input_controller_impl.js';
 import {LocaleInfo} from './locale_info.js';
@@ -33,12 +35,6 @@
   private speechParser_: SpeechParser|null = null;
   /** Whether or not Dictation is active. */
   private active_ = false;
-  private cancelTone_: HTMLAudioElement|null =
-      new Audio('dictation/earcons/null_selection.wav');
-  private startTone_: HTMLAudioElement|null =
-      new Audio('dictation/earcons/audio_initiate.wav');
-  private endTone_: HTMLAudioElement|null =
-      new Audio('dictation/earcons/audio_end.wav');
   private noSpeechTimeoutMs_: number = Dictation.Timeouts.NO_SPEECH_NETWORK_MS;
   private stopTimeoutId_: number|null = null;
   private interimText_ = '';
@@ -231,13 +227,10 @@
     this.active_ = false;
     // Stop speech recognition.
     chrome.speechRecognitionPrivate.stop({}, () => {});
-    if (this.interimText_) {
-      // TODO(b/314203187): Determine if not null assertion is acceptable.
-      this.endTone_!.play();
-    } else {
-      // TODO(b/314203187): Determine if not null assertion is acceptable.
-      this.cancelTone_!.play();
-    }
+
+    this.sendToOffscreen_(
+        this.interimText_ ? OffscreenCommandType.DICTATION_PLAY_END :
+                            OffscreenCommandType.DICTATION_PLAY_CANCEL);
 
     // Clear any timeouts.
     this.clearStopTimeout_();
@@ -355,8 +348,7 @@
         Dictation.Timeouts.NO_SPEECH_ONDEVICE_MS;
     this.setStopTimeout_(this.noSpeechTimeoutMs_);
 
-    // TODO(b/314203187): Determine if not null assertion is acceptable.
-    this.startTone_!.play();
+    this.sendToOffscreen_(OffscreenCommandType.DICTATION_PLAY_START);
     this.clearInterimText_();
 
     // Record metrics.
@@ -539,6 +531,10 @@
     return this.prevMacro_;
   }
 
+  private sendToOffscreen_(command: OffscreenCommandType): void {
+    chrome.runtime.sendMessage(undefined, {command});
+  }
+
   /** Disables Pumpkin for tests that use regex-based command parsing. */
   disablePumpkinForTesting(): void {
     // TODO(b/314203187): Determine if not null assertion is acceptable.
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen.html b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen.html
new file mode 100644
index 0000000..cb6ee3a8
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen.html
@@ -0,0 +1,9 @@
+<!--
+Copyright 2025 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<body>
+  <script type="module" src="offscreen_audio.js"></script>
+</body>
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen_audio.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen_audio.ts
new file mode 100644
index 0000000..32a8417
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen_audio.ts
@@ -0,0 +1,49 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {OffscreenCommandType} from '../offscreen_command_type.js';
+
+/**
+ * Offscreen way to play sounds for dictaiton.
+ */
+class OffscreenAudio {
+  static instance?: OffscreenAudio;
+
+  private cancelTone_: HTMLAudioElement =
+      new Audio('earcons/null_selection.wav');
+  private startTone_: HTMLAudioElement =
+      new Audio('earcons/audio_initiate.wav');
+  private endTone_: HTMLAudioElement = new Audio('earcons/audio_end.wav');
+
+  constructor() {
+    chrome.runtime.onMessage.addListener(
+        (message: any|undefined, _sender: chrome.runtime.MessageSender) =>
+            this.handleMessageFromServiceWorker_(message));
+  }
+
+  static init(): void {
+    if (OffscreenAudio.instance) {
+      throw 'Error: trying to create two instances of singleton ' +
+          'OffscreenAudio.';
+    }
+    OffscreenAudio.instance = new OffscreenAudio();
+  }
+
+  private handleMessageFromServiceWorker_(message: any|undefined): boolean {
+    switch (message['command']) {
+      case OffscreenCommandType.DICTATION_PLAY_CANCEL:
+        this.cancelTone_.play();
+        break;
+      case OffscreenCommandType.DICTATION_PLAY_START:
+        this.startTone_.play();
+        break;
+      case OffscreenCommandType.DICTATION_PLAY_END:
+        this.endTone_.play();
+        break;
+    }
+    return false;
+  }
+}
+
+OffscreenAudio.init();
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/facegaze/facegaze_test_base.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/facegaze/facegaze_test_base.js
index 23b47d7..5819269 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/facegaze/facegaze_test_base.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/facegaze/facegaze_test_base.js
@@ -219,27 +219,27 @@
 
       // Save the original set and clear interval functions so they can be used
       // in this file.
-      window.setIntervalOriginal = window.setInterval;
-      window.clearIntervalOriginal = window.clearInterval;
+      globalThis.setIntervalOriginal = globalThis.setInterval;
+      globalThis.clearIntervalOriginal = globalThis.clearInterval;
 
-      window.setTimeout = (callback, timeout) => {
+      globalThis.setTimeout = (callback, timeout) => {
         const id = this.nextTimeoutId_;
         ++this.nextTimeoutId_;
         this.timeoutCallbacks_[id] = callback;
         return id;
       };
-      window.clearTimeout = (id) => {
+      globalThis.clearTimeout = (id) => {
         delete this.timeoutCallbacks_[id];
       };
 
-      window.setInterval = (callback, timeout) => {
+      globalThis.setInterval = (callback, timeout) => {
         // push() will return the new length of the array, which should be the
         // next interval id. For the current callback, return nextIntervalId_ -
         // 1, which should be the id for the current callback.
         this.nextIntervalId_ = this.intervalCallbacks_.push(callback);
         return this.nextIntervalId_ - 1;
       };
-      window.clearInterval = (id) => {
+      globalThis.clearInterval = (id) => {
         delete this.intervalCallbacks_[id];
       };
     }
@@ -558,9 +558,9 @@
     }
 
     await new Promise((resolve) => {
-      const intervalId = setIntervalOriginal(() => {
+      const intervalId = globalThis.setIntervalOriginal(() => {
         if (this.getFaceGaze().mouseController_.mouseInterval_ !== -1) {
-          clearIntervalOriginal(intervalId);
+          globalThis.clearIntervalOriginal(intervalId);
           resolve();
         }
       }, 300);
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js
index 529f34f..6f5c4d77 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js
@@ -11,7 +11,7 @@
 MagnifierE2ETest = class extends E2ETestBase {
   constructor() {
     super();
-    window.RoleType = chrome.automation.RoleType;
+    globalThis.RoleType = chrome.automation.RoleType;
   }
 
   async getNextMagnifierBounds() {
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/offscreen_command_type.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/offscreen_command_type.ts
new file mode 100644
index 0000000..415eaa2
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/offscreen_command_type.ts
@@ -0,0 +1,13 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * The types of commands that can be sent between the offscreen document and the
+ * Accessibility Common service workers.
+ */
+export enum OffscreenCommandType {
+  DICTATION_PLAY_CANCEL = 'DictationPlayCancel',
+  DICTATION_PLAY_START = 'DictationPlayStart',
+  DICTATION_PLAY_END = 'DictationPlayEnd',
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2
index 37b946a..74b6277 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2
@@ -36,6 +36,9 @@
     "metricsPrivate",
     "settingsPrivate",
     "languageSettingsPrivate",
+{% if is_manifest_v3 == '1' %}
+    "offscreen",
+{% endif %}
     "speechRecognitionPrivate",
     "tabs",
     "videoCapture"
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/panel_command.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/panel_command.ts
index 175dd9a4..a1df606 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/panel_command.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/panel_command.ts
@@ -12,45 +12,46 @@
  * Create one command to pass to the ChromeVox Panel.
  */
 export class PanelCommand {
+  private static panelIsInitialized_: Promise<void>|null = null;
+
   type: PanelCommandType;
   data?: string|Object;
 
   constructor(type: PanelCommandType, data?: string|Object) {
     this.type = type;
     this.data = data;
-  }
 
-  getPanelWindow(): Window {
-    const views = chrome.extension.getViews();
-    for (let i = 0; i < views.length; i++) {
-      if (views[i]['location'].href.indexOf('panel/panel.html') > 0) {
-        return views[i] as Window;
-      }
-    }
-    throw new Error('Could not find the panel window');
-  }
-
-  waitForPanel(): Promise<void> {
-    return new Promise<void>(resolve => {
-      const panelWindow = this.getPanelWindow();
-      if (panelWindow.document.readyState === 'complete') {
-        // The panel may already have loaded. In this case, resolve() and
-        // do not wait for a load event that has already fired.
-        resolve();
-      }
-      panelWindow.addEventListener('load', () => {
-        resolve();
+    if (!PanelCommand.panelIsInitialized_) {
+      PanelCommand.panelIsInitialized_ = new Promise(resolve => {
+        this.waitForPanel(resolve);
       });
-    });
+    }
+  }
+
+  waitForPanel(resolve: () => void) {
+    chrome.runtime.sendMessage(
+        undefined, {type: PanelCommandType.IS_PANEL_INITIALIZED}, undefined,
+        (initialized: any) => {
+          // Panel is not yet initialized
+          if (chrome.runtime.lastError) {
+            setTimeout(() => this.waitForPanel(resolve), 500);
+            return;
+          }
+
+          // Panel is initialized.
+          if (initialized as boolean) {
+            resolve();
+          }
+        });
   }
 
   /** Send this command to the ChromeVox Panel window. */
   async send(): Promise<void> {
     // Do not send commands to the ChromeVox Panel window until it has finished
     // loading and is ready to receive commands.
-    await this.waitForPanel();
-    const panelWindow = this.getPanelWindow();
-    panelWindow.postMessage(JSON.stringify(this), window.location.origin);
+    await PanelCommand.panelIsInitialized_;
+
+    chrome.runtime.sendMessage(undefined, {type: this.type, data: this.data});
   }
 }
 
@@ -65,6 +66,7 @@
   SEARCH = 'search',
   TUTORIAL = 'tutorial',
   ENABLE_TEST_HOOKS = 'enable_test_hooks',
+  IS_PANEL_INITIALIZED = 'IsPanelInitialized',
 }
 
 TestImportManager.exportForTesting(
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel.ts
index e23e3df..09a4982f 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel.ts
@@ -30,6 +30,9 @@
 type AsyncCallback = () => Promise<void>;
 type SessionState = chrome.loginState.SessionState;
 
+type MessageSender = chrome.runtime.MessageSender;
+type SendResponse = (value: any) => void;
+
 /** Class to manage the panel. */
 export class Panel implements PanelInterface {
   private menuManager_ = new MenuManager();
@@ -57,6 +60,11 @@
   }
 
   private initListeners_(): void {
+    chrome.runtime.onMessage.addListener(
+        (message: any|undefined, _sender: MessageSender,
+         sendResponse: SendResponse) =>
+            this.handleMessageFromServiceWorker_(message, sendResponse));
+
     chrome.loginState.getSessionState(
         (state: SessionState) => this.updateSessionState_(state));
     chrome.loginState.onSessionStateChanged.addListener(
@@ -81,8 +89,7 @@
     window.addEventListener(
         'storage', (event: StorageEvent) => this.onStorageChanged_(event),
         false);
-    window.addEventListener(
-        'message', (message: MessageEvent) => this.onMessage_(message), false);
+
     window.addEventListener('blur', event => this.onBlur_(event), false);
     window.addEventListener('hashchange', () => this.onHashChange_(), false);
 
@@ -162,6 +169,16 @@
     }
   }
 
+  private handleMessageFromServiceWorker_(
+      message: any|undefined, sendResponse: SendResponse): boolean {
+    if (message.type == PanelCommandType.IS_PANEL_INITIALIZED) {
+      sendResponse(true);
+    } else {
+      this.exec_({type: message.type, data: message.data} as PanelCommand)
+    }
+    return false;
+  }
+
   /**
    * Execute a command to update the panel.
    * TODO(b/314203187): Not nulls asserted, check that this is correct.
@@ -593,11 +610,6 @@
     }
   }
 
-  private onMessage_(message: MessageEvent): void {
-    const command = JSON.parse(message.data) as PanelCommand;
-    this.exec_(command);
-  }
-
   private async onPanLeft_(): Promise<void> {
     await BackgroundBridge.Braille.panLeft();
   }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test.js
index 620a5c9..1fe8440c 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test.js
@@ -22,6 +22,8 @@
     globalThis.Gesture = chrome.accessibilityPrivate.Gesture;
     globalThis.RoleType = chrome.automation.RoleType;
 
+    // TODO(crbug.com/388867840): Replace with chrome.runtime.sendMessage to
+    // panel.html
     const panel = this.getPanel().instance;
     const original = panel.exec_.bind(panel);
     panel.exec_ = (command) => {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test_base.js
index f344486c..d316515 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test_base.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/panel_test_base.js
@@ -36,6 +36,9 @@
     return this.getPanelWindow().Panel;
   }
 
+
+  // TODO(crbug.com/388867840): Replace with chrome.runtime.sendMessage to
+  // panel.html
   async waitForMenu(menuMsg) {
     const menuManager = this.getPanel().instance.menuManager_;
 
diff --git a/chrome/browser/resources/glic/webview.ts b/chrome/browser/resources/glic/webview.ts
index 48b9a53c..ba735d8 100644
--- a/chrome/browser/resources/glic/webview.ts
+++ b/chrome/browser/resources/glic/webview.ts
@@ -306,7 +306,10 @@
             return {cancel: !urlMatchesAllowedOrigin(details.url)};
           };
 
-  // Attaches the X-Glic header to all main-frame requests.
+  // Attaches the X-Glic headers to all main-frame requests.
+  // X-Glic: 1
+  // X-Glic-Chrome-Channel: stable
+  // X-Glic-Chrome-Version: 137.0.1234.0
   private onBeforeSendHeaders:
       ChromeEventFunctionType<typeof chrome.webRequest.onBeforeSendHeaders> =
           (details) => {
@@ -319,6 +322,14 @@
               name: 'X-Glic',
               value: '1',
             });
+            requestHeaders.push({
+              name: 'X-Glic-Chrome-Version',
+              value: loadTimeData.getString('chromeVersion'),
+            });
+            requestHeaders.push({
+              name: 'X-Glic-Chrome-Channel',
+              value: loadTimeData.getString('chromeChannel'),
+            });
             return {requestHeaders};
           };
 }
diff --git a/chrome/browser/resources/new_tab_page/lazy_load.ts b/chrome/browser/resources/new_tab_page/lazy_load.ts
index eeb91963..a4baca4 100644
--- a/chrome/browser/resources/new_tab_page/lazy_load.ts
+++ b/chrome/browser/resources/new_tab_page/lazy_load.ts
@@ -45,7 +45,7 @@
 export {microsoftFilesModuleDescriptor, MicrosoftFilesModuleElement} from './modules/v2/file_suggestion/microsoft_files_module.js';
 export {MicrosoftFilesProxyImpl} from './modules/v2/file_suggestion/microsoft_files_proxy.js';
 export {ModuleHeaderElement as ModuleHeaderElementV2} from './modules/v2/module_header.js';
-export {DisableModuleEvent, DismissModuleElementEvent, DismissModuleInstanceEvent, MODULE_CUSTOMIZE_ELEMENT_ID, ModulesV2Element, NamedWidth, SUPPORTED_MODULE_WIDTHS} from './modules/v2/modules.js';
+export {DisableModuleEvent, DismissModuleElementEvent, DismissModuleInstanceEvent, ModulesV2Element, NamedWidth, SUPPORTED_MODULE_WIDTHS} from './modules/v2/modules.js';
 export {ModuleElement as MostRelevantTabResumptionModuleElement, mostRelevantTabResumptionDescriptor} from './modules/v2/most_relevant_tab_resumption/module.js';
 export {MostRelevantTabResumptionProxyImpl} from './modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption_proxy.js';
 export {VoiceSearchOverlayElement} from './voice_search_overlay.js';
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/modules.ts b/chrome/browser/resources/new_tab_page/modules/v2/modules.ts
index 2ef872e036..1987678 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/modules.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/modules.ts
@@ -6,8 +6,6 @@
 import 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
 import 'chrome://resources/cr_elements/cr_button/cr_button.js';
 
-import type {HelpBubbleMixinInterface} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js';
-import {HelpBubbleMixin} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js';
 import type {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {EventTracker} from 'chrome://resources/js/event_tracker.js';
@@ -17,7 +15,6 @@
 import {loadTimeData} from '../../i18n_setup.js';
 import {recordOccurence as recordOccurrence} from '../../metrics_utils.js';
 import type {PageCallbackRouter, PageHandlerRemote} from '../../new_tab_page.mojom-webui.js';
-import {IphFeature} from '../../new_tab_page.mojom-webui.js';
 import type {ModuleIdName} from '../../new_tab_page.mojom-webui.js';
 import {NewTabPageProxy} from '../../new_tab_page_proxy.js';
 import {WindowProxy} from '../../window_proxy.js';
@@ -78,9 +75,6 @@
   };
 }
 
-export const MODULE_CUSTOMIZE_ELEMENT_ID =
-    'NewTabPageUI::kModulesCustomizeIPHAnchorElement';
-
 /**
  * Creates template instances for a list of modules.
  *
@@ -101,11 +95,8 @@
   }));
 }
 
-const AppElementBase = HelpBubbleMixin(PolymerElement) as
-    {new (): PolymerElement & HelpBubbleMixinInterface};
-
 /** Container for the NTP modules. */
-export class ModulesV2Element extends AppElementBase {
+export class ModulesV2Element extends PolymerElement {
   static get is() {
     return 'ntp-modules-v2';
   }
@@ -395,24 +386,6 @@
 
       this.recordInitialLoadMetrics_(modules, modulesIdNames);
       this.dispatchEvent(new Event('modules-loaded'));
-
-
-      if (this.templateInstances_.length > 0) {
-        this.registerHelpBubble(
-            MODULE_CUSTOMIZE_ELEMENT_ID,
-            [
-              '#container',
-              'ntp-module-wrapper',
-              '#moduleElement',
-            ],
-            {fixed: true});
-        // TODO(crbug.com/40075330): Currently, a period of time must elapse
-        // between the registration of the anchor element and the promo
-        // invocation, else the anchor element will not be ready for use.
-        setTimeout(() => {
-          this.handler_.maybeShowFeaturePromo(IphFeature.kCustomizeModules);
-        }, 1000);
-      }
     }
 
     this.moduleLoadPromise_ = null;
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
index 8b61856..f9cf40f 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
@@ -14,6 +14,7 @@
 // Keep in sync with the respective enum in
 // components/browsing_data/core/browsing_data_utils.h, and leave out values
 // that are not available on Desktop.
+// LINT.IfChange(TimePeriod)
 export enum TimePeriod {
   LAST_HOUR = 0,
   LAST_DAY = 1,
@@ -24,6 +25,26 @@
   LAST_15_MINUTES = 6,
   TIME_PERIOD_LAST = LAST_15_MINUTES
 }
+// LINT.ThenChange(/components/browsing_data/core/browsing_data_utils.h:TimePeriod)
+
+// Keep in sync with the respective enum in
+// components/browsing_data/core/browsing_data_utils.h, and leave out values
+// that are not available on Desktop.
+// This enum represents ClearBrowsingDataDialogV2 and does not match the
+// datatypes in the old dialog.
+// LINT.IfChange(BrowsingDataType)
+export enum BrowsingDataType {
+  HISTORY = 0,
+  CACHE = 1,
+  SITE_DATA = 2,
+  // PASSWORDS = 3, Not used on Desktop.
+  FORM_DATA = 4,
+  SITE_SETTINGS = 5,
+  DOWNLOADS = 6,
+  HOSTED_APPS_DATA = 7,
+  // TABS = 8, Not used on Desktop.
+}
+// LINT.ThenChange(/components/browsing_data/core/browsing_data_utils.h:BrowsingDataType)
 
 /**
  * ClearBrowsingDataResult contains any possible follow-up notices that should
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.html
index 27a3559..55649e7 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.html
@@ -64,39 +64,23 @@
     <settings-clear-browsing-data-time-picker prefs="{{prefs}}">
     </settings-clear-browsing-data-time-picker>
     <div id="checkboxContainer">
-      <settings-checkbox id="browsingCheckbox"
-          pref="{{prefs.browser.clear_data.browsing_history}}" no-set-pref>
-        <div class="checkbox-title">$i18n{clearBrowsingHistory}</div>
-      </settings-checkbox>
-      <settings-checkbox id="cookiesCheckbox"
-          class="cookies-checkbox"
-          pref="{{prefs.browser.clear_data.cookies}}" no-set-pref>
-        <div class="checkbox-title">$i18n{clearCookies}</div>
-      </settings-checkbox>
-      <settings-checkbox id="cacheCheckbox"
-          class="cache-checkbox"
-          pref="{{prefs.browser.clear_data.cache}}" no-set-pref>
-        <div class="checkbox-title">$i18n{clearCache}</div>
-      </settings-checkbox>
-      <settings-checkbox id="downloadCheckbox"
-          pref="{{prefs.browser.clear_data.download_history}}" no-set-pref>
-        <div class="checkbox-title">$i18n{clearDownloadHistory}</div>
-      </settings-checkbox>
-      <settings-checkbox
-          pref="{{prefs.browser.clear_data.form_data}}" no-set-pref>
-        <div class="checkbox-title">$i18n{clearFormData}</div>
-      </settings-checkbox>
-      <settings-checkbox
-          pref="{{prefs.browser.clear_data.site_settings}}" no-set-pref>
-        <div class="checkbox-title">$i18n{siteSettings}</div>
-      </settings-checkbox>
-      <settings-checkbox
-          pref="{{prefs.browser.clear_data.hosted_apps_data}}" no-set-pref>
-        <div class="checkbox-title">$i18n{clearHostedAppData}</div>
-      </settings-checkbox>
+      <template is="dom-repeat"
+          items="[[expandedBrowsingDataTypeOptionsList_]]">
+        <settings-checkbox pref="[[item.pref]]" no-set-pref>
+          <div class="checkbox-title">[[item.label]]</div>
+        </settings-checkbox>
+      </template>
+      <template is="dom-if" if="[[dataTypesExpanded_]]">
+        <template is="dom-repeat" items="[[moreBrowsingDataTypeOptionsList_]]">
+          <settings-checkbox pref="[[item.pref]]" no-set-pref>
+            <div class="checkbox-title">[[item.label]]</div>
+          </settings-checkbox>
+        </template>
+      </template>
     </div>
     <cr-button id="showMoreButton" on-click="onShowMoreClick_"
-        hidden="[[dataTypesExpanded_]]">
+        hidden="[[shouldHideShowMoreButton_(
+            dataTypesExpanded_, moreBrowsingDataTypeOptionsList_)]]">
       $i18n{clearBrowsingDataShowMore}
       <cr-icon icon="cr:expand-more" aria-hidden="true" role="presentation">
       </cr-icon>
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.ts
index 5a207b4..68cdddb 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.ts
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_v2.ts
@@ -20,6 +20,9 @@
 import type {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {loadTimeData} from '../i18n_setup.js';
+
+import {BrowsingDataType} from './clear_browsing_data_browser_proxy.js';
 import {getTemplate} from './clear_browsing_data_dialog_v2.html.js';
 
 export interface SettingsClearBrowsingDataDialogV2Element {
@@ -32,6 +35,70 @@
   };
 }
 
+/**
+ * The list of all available Browsing Data types in the default order they
+ * should appear in the dialog.
+ */
+const ALL_BROWSING_DATATYPES_LIST: BrowsingDataType[] = [
+  BrowsingDataType.HISTORY,
+  BrowsingDataType.SITE_DATA,
+  BrowsingDataType.CACHE,
+  BrowsingDataType.DOWNLOADS,
+  BrowsingDataType.FORM_DATA,
+  BrowsingDataType.SITE_SETTINGS,
+  BrowsingDataType.HOSTED_APPS_DATA,
+];
+
+/** The list of Browsing Data types that should be expanded by default. */
+const DEFAULT_BROWSING_DATATYPES_LIST: BrowsingDataType[] = [
+  BrowsingDataType.HISTORY,
+  BrowsingDataType.SITE_DATA,
+  BrowsingDataType.CACHE,
+];
+
+interface BrowsingDataTypeOption {
+  label: string;
+  pref: chrome.settingsPrivate.PrefObject;
+}
+
+function getDataTypeLabel(datatypes: BrowsingDataType) {
+  switch (datatypes) {
+    case BrowsingDataType.HISTORY:
+      return loadTimeData.getString('clearBrowsingHistory');
+    case BrowsingDataType.CACHE:
+      return loadTimeData.getString('clearCache');
+    case BrowsingDataType.SITE_DATA:
+      return loadTimeData.getString('clearCookies');
+    case BrowsingDataType.FORM_DATA:
+      return loadTimeData.getString('clearFormData');
+    case BrowsingDataType.SITE_SETTINGS:
+      return loadTimeData.getString('siteSettings');
+    case BrowsingDataType.DOWNLOADS:
+      return loadTimeData.getString('clearDownloadHistory');
+    case BrowsingDataType.HOSTED_APPS_DATA:
+      return loadTimeData.getString('clearHostedAppData');
+  }
+}
+
+export function getDataTypePrefName(datatypes: BrowsingDataType) {
+  switch (datatypes) {
+    case BrowsingDataType.HISTORY:
+      return 'browser.clear_data.browsing_history';
+    case BrowsingDataType.CACHE:
+      return 'browser.clear_data.cache';
+    case BrowsingDataType.SITE_DATA:
+      return 'browser.clear_data.cookies';
+    case BrowsingDataType.FORM_DATA:
+      return 'browser.clear_data.form_data';
+    case BrowsingDataType.SITE_SETTINGS:
+      return 'browser.clear_data.site_settings';
+    case BrowsingDataType.DOWNLOADS:
+      return 'browser.clear_data.download_history';
+    case BrowsingDataType.HOSTED_APPS_DATA:
+      return 'browser.clear_data.hosted_apps_data';
+  }
+}
+
 const SettingsClearBrowsingDataDialogV2ElementBase = PrefsMixin(PolymerElement);
 
 export class SettingsClearBrowsingDataDialogV2Element extends
@@ -50,10 +117,49 @@
         type: Boolean,
         value: false,
       },
+
+      expandedBrowsingDataTypeOptionsList_: Array,
+
+      moreBrowsingDataTypeOptionsList_: Array,
     };
   }
 
   declare private dataTypesExpanded_: boolean;
+  declare private expandedBrowsingDataTypeOptionsList_:
+      BrowsingDataTypeOption[];
+  declare private moreBrowsingDataTypeOptionsList_: BrowsingDataTypeOption[];
+
+  override ready() {
+    super.ready();
+
+    this.setUpDataTypeOptionLists_();
+  }
+
+  private setUpDataTypeOptionLists_() {
+    const expandedOptionsList: BrowsingDataTypeOption[] = [];
+    const moreOptionsList: BrowsingDataTypeOption[] = [];
+
+    ALL_BROWSING_DATATYPES_LIST.forEach((datatype) => {
+      const datatypeOption = {
+        label: getDataTypeLabel(datatype),
+        pref: this.getPref(getDataTypePrefName(datatype)),
+      };
+
+      if (this.shouldDataTypeBeExpanded_(datatype)) {
+        expandedOptionsList.push(datatypeOption);
+      } else {
+        moreOptionsList.push(datatypeOption);
+      }
+    });
+
+    this.expandedBrowsingDataTypeOptionsList_ = expandedOptionsList;
+    this.moreBrowsingDataTypeOptionsList_ = moreOptionsList;
+  }
+
+  private shouldDataTypeBeExpanded_(datatype: BrowsingDataType) {
+    return DEFAULT_BROWSING_DATATYPES_LIST.includes(datatype) ||
+        this.getPref(getDataTypePrefName(datatype)).value;
+  }
 
   private onCancelClick_() {
     this.$.deleteBrowsingDataDialog.close();
@@ -65,7 +171,11 @@
 
   private onShowMoreClick_() {
     this.dataTypesExpanded_ = true;
-    // TODO(crbug.com/397187800): Handle checkbox expansion.
+  }
+
+  private shouldHideShowMoreButton_() {
+    return this.dataTypesExpanded_ || !this.moreBrowsingDataTypeOptionsList_ ||
+        this.moreBrowsingDataTypeOptionsList_.length === 0;
   }
 }
 
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index 9b1bec6..f402c20a 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -149,9 +149,9 @@
 // <if expr="not is_chromeos">
 export {SettingsClearBrowsingDataAccountIndicator} from './clear_browsing_data_dialog/clear_browsing_data_account_indicator.js';
 // </if>
-export {ClearBrowsingDataBrowserProxy, ClearBrowsingDataBrowserProxyImpl, ClearBrowsingDataResult, TimePeriod, UpdateSyncStateEvent} from './clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js';
+export {BrowsingDataType, ClearBrowsingDataBrowserProxy, ClearBrowsingDataBrowserProxyImpl, ClearBrowsingDataResult, TimePeriod, UpdateSyncStateEvent} from './clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js';
 export {SettingsClearBrowsingDataDialogElement} from './clear_browsing_data_dialog/clear_browsing_data_dialog.js';
-export {SettingsClearBrowsingDataDialogV2Element} from './clear_browsing_data_dialog/clear_browsing_data_dialog_v2.js';
+export {getDataTypePrefName, SettingsClearBrowsingDataDialogV2Element} from './clear_browsing_data_dialog/clear_browsing_data_dialog_v2.js';
 export {getTimePeriodString, SettingsClearBrowsingDataTimePicker} from './clear_browsing_data_dialog/clear_browsing_data_time_picker.js';
 export {SettingsHistoryDeletionDialogElement} from './clear_browsing_data_dialog/history_deletion_dialog.js';
 export {SettingsPasswordsDeletionDialogElement} from './clear_browsing_data_dialog/passwords_deletion_dialog.js';
diff --git a/chrome/browser/resources/settings/site_settings/constants.ts b/chrome/browser/resources/settings/site_settings/constants.ts
index fdf37b4..d3c5326 100644
--- a/chrome/browser/resources/settings/site_settings/constants.ts
+++ b/chrome/browser/resources/settings/site_settings/constants.ts
@@ -106,12 +106,14 @@
  * This should be kept in sync with the |CookieControlsMode| enum in
  * components/content_settings/core/browser/cookie_settings.h
  */
+// LINT.IfChange(CookieControlsMode)
 export enum CookieControlsMode {
   OFF = 0,
   BLOCK_THIRD_PARTY = 1,
   INCOGNITO_ONLY = 2,
   LIMITED = 3,
 }
+// LINT.ThenChange(/tools/metrics/histograms/enums.xml:CookieControlsMode, /components/content_settings/core/browser/cookie_settings.h:CookieControlsMode)
 
 /**
  * Contains the possible sources of a ContentSetting.
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index 5245d35c..beddbd29 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -19,13 +19,13 @@
 import {getHtml} from './app.html.js';
 import {AppStyleUpdater} from './app_style_updater.js';
 import type {SettingsPrefs} from './common.js';
-import {getCurrentSpeechRate, minOverflowLengthToScroll, playFromSelectionTimeout} from './common.js';
+import {minOverflowLengthToScroll, playFromSelectionTimeout} from './common.js';
 import type {LanguageToastElement} from './language_toast.js';
 import {NodeStore} from './node_store.js';
 import {ReadAloudHighlighter} from './read_aloud/highlighter.js';
 import {SpeechController} from './read_aloud/speech_controller.js';
 import type {SpeechListener} from './read_aloud/speech_controller.js';
-import {PauseActionSource} from './read_aloud/speech_model.js';
+import {PauseActionSource, SpeechEngineState} from './read_aloud/speech_model.js';
 import type {SpeechPlayingState} from './read_aloud/speech_model.js';
 import {VoicePackController} from './read_aloud/voice_pack_controller.js';
 import {WordBoundaries} from './read_aloud/word_boundaries.js';
@@ -40,13 +40,6 @@
 
 const AppElementBase = WebUiListenerMixinLit(CrLitElement);
 
-interface UtteranceSettings {
-  lang: string;
-  volume: number;
-  pitch: number;
-  rate: number;
-}
-
 const linkDataAttribute = 'link';
 
 // The maximum speech length that should be used with remote voices
@@ -124,11 +117,6 @@
   // resetting speech right after starting it.
   private accessor willDrawAgainSoon_: boolean = false;
 
-  // After the first utterance has been spoken, we should assume that the
-  // speech engine has loaded, and we shouldn't adjust the play / pause
-  // disabled state based on the message.onStart callback to avoid flickering.
-  private firstUtteranceSpoken_ = false;
-
   // When a new TTS Engine extension is loaded into reading mode, we want to try
   // to install new natural voices from it. However, the new engine isn't ready
   // until it calls onvoiceschanged, so set this and wait for that call to
@@ -144,8 +132,8 @@
   // All possible available voices for the current speech engine.
   protected accessor availableVoices_: SpeechSynthesisVoice[] = [];
   // If a preview is playing, this is set to the voice the preview is playing.
-  // Otherwise, this is undefined.
-  protected accessor previewVoicePlaying_: SpeechSynthesisVoice|undefined;
+  // Otherwise, this is null.
+  protected accessor previewVoicePlaying_: SpeechSynthesisVoice|null = null;
 
   protected accessor localeToDisplayName_: {[locale: string]: string} = {};
 
@@ -231,7 +219,6 @@
       // not always reliabled called.
       this.speech_.cancel();
       this.hasContent_ = false;
-      this.firstUtteranceSpoken_ = false;
       this.firstTextNodeSetForReadAloud = null;
       this.nodeStore_.clearDomNodes();
       this.clearReadAloudState();
@@ -1086,41 +1073,7 @@
     event.preventDefault();
     event.stopPropagation();
 
-    this.speechController_.stopSpeech(PauseActionSource.VOICE_PREVIEW);
-
-    // If there's no previewVoice, return after stopping the current preview
-    if (!event.detail) {
-      this.previewVoicePlaying_ = undefined;
-      return;
-    }
-
-    const defaultUtteranceSettings = this.defaultUtteranceSettings();
-    const utterance = new SpeechSynthesisUtterance(
-        loadTimeData.getString('readingModeVoicePreviewText'));
-    const voice = event.detail.previewVoice;
-    utterance.voice = voice;
-    utterance.lang = defaultUtteranceSettings.lang;
-    utterance.volume = defaultUtteranceSettings.volume;
-    utterance.pitch = defaultUtteranceSettings.pitch;
-    utterance.rate = defaultUtteranceSettings.rate;
-
-    utterance.onstart = event => {
-      this.previewVoicePlaying_ = event.utterance.voice || undefined;
-    };
-
-    utterance.onend = () => {
-      this.previewVoicePlaying_ = undefined;
-    };
-
-    // TODO: crbug.com/40927698 - There should probably be more sophisticated
-    // error handling for voice previews, but for now, simply setting the
-    // preview voice to null should be sufficient to reset state if an error is
-    // encountered during a preview.
-    utterance.onerror = () => {
-      this.previewVoicePlaying_ = undefined;
-    };
-
-    this.speech_.speak(utterance);
+    this.speechController_.previewVoice(event.detail.previewVoice);
   }
 
   protected onVoiceMenuClose_(
@@ -1155,6 +1108,14 @@
         this.speechController_.isAudioCurrentlyPlaying();
   }
 
+  onEngineStateChange(): void {
+    this.speechEngineLoaded_ = this.speechController_.isEngineLoaded();
+  }
+
+  onPreviewVoicePlaying(): void {
+    this.previewVoicePlaying_ = this.speechController_.getPreviewVoicePlaying();
+  }
+
   onPause() {
     // Restore links if they're enabled when speech pauses. Don't restore links
     // if it's paused from a non-pause button (e.g. voice previews) so the links
@@ -1544,16 +1505,7 @@
       }
     });
 
-    message.onstart = () => {
-      // We've gotten the signal that the speech engine has loaded, therefore
-      // we can enable the Read Aloud buttons.
-      this.speechEngineLoaded_ = true;
-
-      // Reset the isSpeechBeingRepositioned property after speech starts
-      // after a next / previous button.
-      this.speechController_.setIsSpeechBeingRepositioned(false);
-      this.speechController_.setIsAudioCurrentlyPlaying(true);
-    };
+    this.speechController_.setOnSpeechSynthesisUtteranceStart(message);
 
     message.onend = () => {
       if (isTextTooLong) {
@@ -1589,18 +1541,7 @@
       message.voice = voice;
     }
 
-    const utteranceSettings = this.defaultUtteranceSettings();
-    message.lang = utteranceSettings.lang;
-    message.volume = utteranceSettings.volume;
-    message.pitch = utteranceSettings.pitch;
-    message.rate = utteranceSettings.rate;
-
-
-    if (!this.firstUtteranceSpoken_) {
-      this.speechEngineLoaded_ = false;
-      this.firstUtteranceSpoken_ = true;
-    }
-    this.speech_.speak(message);
+    this.speechController_.speakMessage(message);
   }
 
   handleSpeechSynthesisError(
@@ -1610,7 +1551,7 @@
     // to prevent trapping users in a state where they can no longer play
     // Read Aloud, as this is preferable to a long delay before speech
     // with no feedback.
-    this.speechEngineLoaded_ = true;
+    this.speechController_.setEngineState(SpeechEngineState.LOADED);
 
     if (error.error === 'interrupted') {
       this.speechController_.onSpeechInterrupted();
@@ -1686,17 +1627,6 @@
     return utteranceText;
   }
 
-  private defaultUtteranceSettings(): UtteranceSettings {
-    return {
-      lang: this.voicePackController_.getCurrentLanguage(),
-      // TODO: crbug.com/40927698 - Ensure the rate is valid for the current
-      // speech engine.
-      rate: getCurrentSpeechRate(),
-      volume: 1,
-      pitch: 1,
-    };
-  }
-
   private onSpeechFinished() {
     this.logger_.logSpeechStopSource(
         chrome.readingMode.contentFinishedStopSource);
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
index 592631e..0aeb6fb 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
@@ -2,17 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {loadTimeData} from '//resources/js/load_time_data.js';
+
+import {getCurrentSpeechRate} from '../common.js';
 import {ReadAnythingLogger} from '../read_anything_logger.js';
 import type {SpeechBrowserProxy} from '../speech_browser_proxy.js';
 import {SpeechBrowserProxyImpl} from '../speech_browser_proxy.js';
 
-import {PauseActionSource, SpeechModel} from './speech_model.js';
+import {PauseActionSource, SpeechEngineState, SpeechModel} from './speech_model.js';
 import type {SpeechPlayingState} from './speech_model.js';
 
 export interface SpeechListener {
   onPause(): void;
   onIsSpeechActiveChange(): void;
   onIsAudioCurrentlyPlayingChange(): void;
+  onEngineStateChange(): void;
+  onPreviewVoicePlaying(): void;
 }
 
 export class SpeechController {
@@ -75,6 +80,28 @@
     }
   }
 
+  isEngineLoaded(): boolean {
+    return this.model_.getEngineState() === SpeechEngineState.LOADED;
+  }
+
+  setEngineState(state: SpeechEngineState) {
+    if (state !== this.model_.getEngineState()) {
+      this.model_.setEngineState(state);
+      this.listeners_.forEach(l => l.onEngineStateChange());
+    }
+  }
+
+  getPreviewVoicePlaying(): SpeechSynthesisVoice|null {
+    return this.model_.getPreviewVoicePlaying();
+  }
+
+  setPreviewVoicePlaying(voice: SpeechSynthesisVoice|null) {
+    if (voice !== this.model_.getPreviewVoicePlaying()) {
+      this.model_.setPreviewVoicePlaying(voice);
+      this.listeners_.forEach(l => l.onPreviewVoicePlaying());
+    }
+  }
+
   hasSpeechBeenTriggered(): boolean {
     return this.model_.hasSpeechBeenTriggered();
   }
@@ -137,6 +164,64 @@
     this.listeners_.forEach(l => l.onPause());
   }
 
+  setOnSpeechSynthesisUtteranceStart(message: SpeechSynthesisUtterance) {
+    message.onstart = () => {
+      // We've gotten the signal that the speech engine has started, therefore
+      // we can enable the Read Aloud buttons.
+      this.setEngineState(SpeechEngineState.LOADED);
+
+      // Reset the isSpeechBeingRepositioned property after speech starts
+      // after a next / previous button.
+      this.setIsSpeechBeingRepositioned(false);
+      this.setIsAudioCurrentlyPlaying(true);
+    };
+  }
+
+  speakMessage(message: SpeechSynthesisUtterance) {
+    if (this.model_.getEngineState() === SpeechEngineState.NONE) {
+      this.setEngineState(SpeechEngineState.LOADING);
+    }
+
+    this.speakWithDefaults_(message);
+  }
+
+  previewVoice(previewVoice: SpeechSynthesisVoice|null) {
+    this.stopSpeech(PauseActionSource.VOICE_PREVIEW);
+
+    // If there's no previewVoice, return after stopping the current preview
+    if (!previewVoice) {
+      this.setPreviewVoicePlaying(null);
+      return;
+    }
+
+    const utterance = new SpeechSynthesisUtterance(
+        loadTimeData.getString('readingModeVoicePreviewText'));
+    // This should only be false in tests where we can't properly construct an
+    // actual SpeechSynthesisVoice object even though the test voices pass the
+    // type checking of method signatures.
+    if (previewVoice instanceof SpeechSynthesisVoice) {
+      utterance.voice = previewVoice;
+    }
+
+    utterance.onstart = () => {
+      this.setPreviewVoicePlaying(previewVoice);
+    };
+
+    utterance.onend = () => {
+      this.setPreviewVoicePlaying(null);
+    };
+
+    // TODO: crbug.com/40927698 - There should probably be more sophisticated
+    // error handling for voice previews, but for now, simply setting the
+    // preview voice to null should be sufficient to reset state if an error is
+    // encountered during a preview.
+    utterance.onerror = () => {
+      this.setPreviewVoicePlaying(null);
+    };
+
+    this.speakWithDefaults_(utterance);
+  }
+
   onSpeechInterrupted() {
     // SpeechSynthesis.cancel() was called, which could have originated
     // either within or outside of reading mode. If it originated from
@@ -162,6 +247,12 @@
     chrome.readingMode.onSpeechPlayingStateChanged(isSpeechActive);
   }
 
+  private speakWithDefaults_(message: SpeechSynthesisUtterance) {
+    message.lang = chrome.readingMode.baseLanguageForSpeech;
+    message.rate = getCurrentSpeechRate();
+    this.speech_.speak(message);
+  }
+
   static getInstance(): SpeechController {
     return instance || (instance = new SpeechController());
   }
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_model.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_model.ts
index f82f0fe..55033f28 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_model.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_model.ts
@@ -38,6 +38,12 @@
   isSpeechBeingRepositioned: boolean;
 }
 
+export enum SpeechEngineState {
+  NONE,
+  LOADING,
+  LOADED,
+}
+
 export class SpeechModel {
   private speechPlayingState_: SpeechPlayingState = {
     isSpeechTreeInitialized: false,
@@ -48,6 +54,9 @@
     isSpeechBeingRepositioned: false,
   };
 
+  private speechEngineState_: SpeechEngineState = SpeechEngineState.NONE;
+  private previewVoicePlaying_: SpeechSynthesisVoice|null = null;
+
   reset(): void {
     this.speechPlayingState_ = {
       isSpeechTreeInitialized: false,
@@ -57,6 +66,24 @@
       hasSpeechBeenTriggered: false,
       isSpeechBeingRepositioned: false,
     };
+    this.speechEngineState_ = SpeechEngineState.NONE;
+    this.previewVoicePlaying_ = null;
+  }
+
+  getEngineState(): SpeechEngineState {
+    return this.speechEngineState_;
+  }
+
+  setEngineState(state: SpeechEngineState): void {
+    this.speechEngineState_ = state;
+  }
+
+  getPreviewVoicePlaying(): SpeechSynthesisVoice|null {
+    return this.previewVoicePlaying_;
+  }
+
+  setPreviewVoicePlaying(voice: SpeechSynthesisVoice|null) {
+    this.previewVoicePlaying_ = voice;
   }
 
   getState(): SpeechPlayingState {
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything.ts b/chrome/browser/resources/side_panel/read_anything/read_anything.ts
index 70f9d79..f7a0fc5 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything.ts
@@ -25,7 +25,7 @@
 export {NodeStore} from './node_store.js';
 export {currentReadHighlightClass, previousReadHighlightClass, ReadAloudHighlighter} from './read_aloud/highlighter.js';
 export {SpeechController, SpeechListener} from './read_aloud/speech_controller.js';
-export {PauseActionSource, SpeechModel} from './read_aloud/speech_model.js';
+export {PauseActionSource, SpeechEngineState, SpeechModel} from './read_aloud/speech_model.js';
 export {VoicePackController} from './read_aloud/voice_pack_controller.js';
 export {VoicePackModel} from './read_aloud/voice_pack_model.js';
 export type {WordBoundaryState} from './read_aloud/word_boundaries.js';
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 83f261a..02dedbf 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
@@ -139,7 +139,7 @@
   // This is set from the parent element via one way data binding.
   accessor isReadAloudPlayable: boolean = false;
   accessor localeToDisplayName: {[lang: string]: string} = {};
-  accessor previewVoicePlaying: SpeechSynthesisVoice|undefined;
+  accessor previewVoicePlaying: SpeechSynthesisVoice|null = null;
   accessor rateOptions: number[] = [0.5, 0.8, 1, 1.2, 1.5, 2, 3, 4];
   accessor settingsPrefs: SettingsPrefs = {
     letterSpacing: 0,
diff --git a/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts b/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts
index d4d8ea5..c5cc22d 100644
--- a/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts
+++ b/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts
@@ -407,8 +407,8 @@
       locale => locale.startsWith(possibleConvertedLang.toLowerCase()));
 }
 
-export function isWaitingForInstallLocally(status: VoiceClientSideStatusCode|
-                                           undefined) {
+export function isWaitingForInstallLocally(
+    status: VoiceClientSideStatusCode|undefined) {
   return status === VoiceClientSideStatusCode.SENT_INSTALL_REQUEST ||
       status === VoiceClientSideStatusCode.SENT_INSTALL_REQUEST_ERROR_RETRY;
 }
@@ -533,8 +533,8 @@
 ]);
 
 export function areVoicesEqual(
-    voice1: SpeechSynthesisVoice|undefined,
-    voice2: SpeechSynthesisVoice|undefined): boolean {
+    voice1?: SpeechSynthesisVoice|null,
+    voice2?: SpeechSynthesisVoice|null): boolean {
   if (!voice1 || !voice2) {
     return false;
   }
diff --git a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts
index cf5a6e2..680026e 100644
--- a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts
+++ b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts
@@ -93,7 +93,7 @@
 
   accessor selectedVoice: SpeechSynthesisVoice|undefined;
   accessor localeToDisplayName: {[lang: string]: string} = {};
-  accessor previewVoicePlaying: SpeechSynthesisVoice|undefined;
+  accessor previewVoicePlaying: SpeechSynthesisVoice|null = null;
   accessor enabledLangs: string[] = [];
   accessor availableVoices: SpeechSynthesisVoice[] = [];
   accessor isSpeechActive: boolean = false;
@@ -102,7 +102,7 @@
   private accessor currentNotifications_:
       {[language: string]: NotificationType} = {};
 
-  private accessor previewVoiceInitiated: SpeechSynthesisVoice|undefined;
+  private accessor previewVoiceInitiated: SpeechSynthesisVoice|null = null;
   protected errorMessages_: string[] = [];
   protected accessor downloadingMessages_: string[] = [];
   protected accessor voiceGroups_: VoiceDropdownGroup[] = [];
@@ -274,9 +274,11 @@
         ToolbarEvent.PLAY_PREVIEW,
         // If preview is currently playing, we pass null to indicate the audio
         // should be paused.
-        dropdownItem.previewActuallyPlaying ?
-            null :
-            {previewVoice: dropdownItem.voice});
+        {
+          previewVoice:
+              dropdownItem.previewActuallyPlaying ? null : dropdownItem.voice,
+        },
+    );
   }
 
   protected openLanguageMenu_() {
@@ -355,7 +357,9 @@
 
     // When the menu first opens, the target is the whole menu.
     // In that case, use default behavior.
-    if (!targetIsVoiceOption && !targetIsPreviewButton) return;
+    if (!targetIsVoiceOption && !targetIsPreviewButton) {
+      return;
+    }
 
     e.preventDefault();
 
diff --git a/chrome/browser/resources_util.cc b/chrome/browser/resources_util.cc
index eb57680b..b33ed83 100644
--- a/chrome/browser/resources_util.cc
+++ b/chrome/browser/resources_util.cc
@@ -20,6 +20,9 @@
 #include "components/grit/components_scaled_resources_map.h"
 #include "ui/resources/grit/ui_resources_map.h"
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "third_party/search_engines_data/search_engines_scaled_resources_map.h"
+#endif
 #if BUILDFLAG(IS_CHROMEOS)
 #include "ui/chromeos/resources/grit/ui_chromeos_resources_map.h"
 #endif
@@ -36,6 +39,9 @@
   ThemeMap() {
     size_t storage_size =
         kComponentsScaledResourcesSize + kThemeResourcesSize + kUiResourcesSize;
+#if !BUILDFLAG(IS_ANDROID)
+    storage_size += kSearchEnginesScaledResourcesSize;
+#endif
 #if BUILDFLAG(IS_CHROMEOS)
     storage_size += kUiChromeosResourcesSize;
 #endif
@@ -54,6 +60,12 @@
     for (size_t i = 0; i < kUiResourcesSize; ++i) {
       storage.emplace_back(kUiResources[i].path, kUiResources[i].id);
     }
+#if !BUILDFLAG(IS_ANDROID)
+    for (size_t i = 0; i < kSearchEnginesScaledResourcesSize; ++i) {
+      storage.emplace_back(kSearchEnginesScaledResources[i].path,
+                           kSearchEnginesScaledResources[i].id);
+    }
+#endif
 #if BUILDFLAG(IS_CHROMEOS)
     for (size_t i = 0; i < kUiChromeosResourcesSize; ++i) {
       storage.emplace_back(kUiChromeosResources[i].path,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
index b3e7c24b..49088142 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
@@ -32,6 +32,7 @@
 //   "SafeBrowsing.DeepScan.<access-point>.Duration"
 //   "SafeBrowsing.DeepScan.<access-point>.<result>.Duration"
 // for the new access point and every possible result.
+// LINT.IfChange(DeepScanAccessPoint)
 enum class DeepScanAccessPoint {
   // A deep scan was initiated from downloading 1+ file(s).
   DOWNLOAD,
@@ -50,7 +51,10 @@
 
   // A deep scan was initiated from transferring 1+ file(s) within ChromeOS.
   FILE_TRANSFER,
+
+  kMaxValue = FILE_TRANSFER,
 };
+// LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:DeepScanAccessPoint)
 std::string DeepScanAccessPointToString(DeepScanAccessPoint access_point);
 
 // Helper function to examine a ContentAnalysisResponse and report the
diff --git a/chrome/browser/search_engines/template_url_service_sync_unittest.cc b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
index 160b9260..1815361 100644
--- a/chrome/browser/search_engines/template_url_service_sync_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
@@ -4404,7 +4404,7 @@
   EXPECT_TRUE(model()->GetTemplateURLForGUID("localguid"));
   // Logged when removing the account only turl.
   histogram_tester.ExpectUniqueSample(
-      "Sync.SearchEngine.HasLocalDataDuringStopSyncing", false, 1);
+      "Sync.SearchEngine.HasLocalDataDuringStopSyncing2", false, 1);
 }
 
 TEST_F(TemplateURLServiceSyncTestWithSeparateLocalAndAccountSearchEngines,
@@ -4434,7 +4434,7 @@
   model()->StopSyncing(syncer::SEARCH_ENGINES);
 
   histogram_tester.ExpectUniqueSample(
-      "Sync.SearchEngine.HasLocalDataDuringStopSyncing", true, 1);
+      "Sync.SearchEngine.HasLocalDataDuringStopSyncing2", true, 1);
   // Only account data is removed.
   EXPECT_TRUE(model()->GetTemplateURLForGUID("guid"));
   EXPECT_EQ(turl->keyword(), u"localkey");
@@ -7193,3 +7193,48 @@
   EXPECT_EQ(turl3->keyword(), u"localkey3");
   EXPECT_FALSE(processor()->contains_guid("guid3"));
 }
+
+TEST_F(TemplateURLServiceSyncTestWithSeparateLocalAndAccountSearchEngines,
+       ShouldNotRemoveAccountDataUponBrowserShutdown) {
+  model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
+                                    syncer::SyncDataList{}, PassProcessor());
+
+  TemplateURLData data1 =
+      CreateTestTemplateURL(u"key1", "http://key1.com", "guid1")->data();
+  // Add a local-and-account search engine.
+  const TemplateURL* turl1 =
+      model()->Add(std::make_unique<TemplateURL>(data1, data1));
+  ASSERT_TRUE(turl1->GetAccountData());
+  ASSERT_TRUE(turl1->GetLocalData());
+
+  base::HistogramTester histogram_tester;
+  model()->OnBrowserShutdown(syncer::SEARCH_ENGINES);
+
+  ASSERT_EQ(turl1, model()->GetTemplateURLForGUID("guid1"));
+  EXPECT_TRUE(turl1->GetAccountData());
+  histogram_tester.ExpectTotalCount(
+      "Sync.SearchEngine.HasLocalDataDuringStopSyncing2", 0);
+}
+
+TEST_F(TemplateURLServiceSyncTestWithSeparateLocalAndAccountSearchEngines,
+       ShouldRemoveAccountDataUponStopSyncing) {
+  model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
+                                    syncer::SyncDataList{}, PassProcessor());
+
+  TemplateURLData data1 =
+      CreateTestTemplateURL(u"key1", "http://key1.com", "guid1")->data();
+  // Add a local-and-account search engine.
+  const TemplateURL* turl1 =
+      model()->Add(std::make_unique<TemplateURL>(data1, data1));
+
+  ASSERT_TRUE(turl1->GetAccountData());
+  ASSERT_TRUE(turl1->GetLocalData());
+
+  base::HistogramTester histogram_tester;
+  model()->StopSyncing(syncer::SEARCH_ENGINES);
+
+  ASSERT_EQ(turl1, model()->GetTemplateURLForGUID("guid1"));
+  EXPECT_FALSE(turl1->GetAccountData());
+  histogram_tester.ExpectUniqueSample(
+      "Sync.SearchEngine.HasLocalDataDuringStopSyncing2", true, 1);
+}
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index 529f41f..c6acd9c 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -1445,13 +1445,6 @@
 }
 
 // static
-void SessionRestore::OnWillRestoreTab(content::WebContents* web_contents) {
-  for (auto& observer : *observers()) {
-    observer.OnWillRestoreTab(web_contents);
-  }
-}
-
-// static
 void SessionRestore::OnGotSession(Profile* profile,
                                   bool for_apps,
                                   int window_count) {
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h
index c427e3ba..7b65517 100644
--- a/chrome/browser/sessions/session_restore.h
+++ b/chrome/browser/sessions/session_restore.h
@@ -122,9 +122,6 @@
   // without session restore started.
   static void OnTabLoaderFinishedLoadingTabs();
 
-  // Is called when session restore is going to restore a tab.
-  static void OnWillRestoreTab(content::WebContents* web_contents);
-
   // Is called when windows are read from the last session restore file.
   static void OnGotSession(Profile* profile, bool for_apps, int window_count);
 
diff --git a/chrome/browser/sessions/session_restore_observer.h b/chrome/browser/sessions/session_restore_observer.h
index 3f32ad1..33954927 100644
--- a/chrome/browser/sessions/session_restore_observer.h
+++ b/chrome/browser/sessions/session_restore_observer.h
@@ -5,10 +5,6 @@
 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_
 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_
 
-namespace content {
-class WebContents;
-}
-
 class Profile;
 
 // Observer of events during session restore. This observer does not cover
@@ -29,10 +25,6 @@
   // multiple concurrent session restores (on all profiles) occur.
   virtual void OnSessionRestoreFinishedLoadingTabs() {}
 
-  // OnWillRestoreTab() is called right after a tab is created by session
-  // restore.
-  virtual void OnWillRestoreTab(content::WebContents* web_contents) {}
-
   // OnGotSession() is called right after windows are read from the last session
   // restore file. If windows are read by AppSessionService for app windows,
   // `for_app` is true. Otherwise, `for_app` is false. This function is used
diff --git a/chrome/browser/sessions/session_restore_observer_unittest.cc b/chrome/browser/sessions/session_restore_observer_unittest.cc
index 277b5be..bf99bfbc 100644
--- a/chrome/browser/sessions/session_restore_observer_unittest.cc
+++ b/chrome/browser/sessions/session_restore_observer_unittest.cc
@@ -50,11 +50,6 @@
     return session_restore_events_;
   }
 
-  const std::set<raw_ptr<content::WebContents, SetExperimental>>&
-  tabs_restoring() const {
-    return tabs_restoring_;
-  }
-
   // SessionRestoreObserver implementation:
   void OnSessionRestoreStartedLoadingTabs() override {
     session_restore_events_.emplace_back(
@@ -64,17 +59,9 @@
     session_restore_events_.emplace_back(
         SessionRestoreEvent::FINISHED_LOADING_TABS);
   }
-  void OnWillRestoreTab(content::WebContents* contents) override {
-    tabs_restoring_.emplace(contents);
-  }
-
-  void OnDidRestoreTab(content::WebContents* contents) {
-    tabs_restoring_.erase(contents);
-  }
 
  private:
   std::vector<SessionRestoreEvent> session_restore_events_;
-  std::set<raw_ptr<content::WebContents, SetExperimental>> tabs_restoring_;
 };
 
 class SessionRestoreObserverTest : public ChromeRenderViewHostTestHarness {
@@ -131,7 +118,6 @@
     }
     TabLoadTracker::Get()->TransitionStateForTesting(contents,
                                                      LoadingState::LOADED);
-    mock_observer_.OnDidRestoreTab(contents);
   }
 
   const std::vector<MockSessionRestoreObserver::SessionRestoreEvent>&
@@ -143,10 +129,6 @@
     return session_restore_events().size();
   }
 
-  size_t number_of_tabs_restoring() const {
-    return mock_observer_.tabs_restoring().size();
-  }
-
  private:
   MockSessionRestoreObserver mock_observer_;
   std::vector<RestoredTab> restored_tabs_;
@@ -154,14 +136,12 @@
 
 TEST_F(SessionRestoreObserverTest, SingleSessionRestore) {
   SessionRestore::NotifySessionRestoreStartedLoadingTabs();
-  SessionRestore::OnWillRestoreTab(web_contents());
   RestoreTabs();
 
   ASSERT_EQ(1u, number_of_session_restore_events());
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS,
       session_restore_events()[0]);
-  EXPECT_EQ(1u, number_of_tabs_restoring());
 
   LoadWebContents(web_contents());
 
@@ -169,7 +149,6 @@
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS,
       session_restore_events()[1]);
-  EXPECT_EQ(0u, number_of_tabs_restoring());
 }
 
 TEST_F(SessionRestoreObserverTest, SequentialSessionRestores) {
@@ -184,21 +163,18 @@
         RestoredTab(test_contents, false, false, false, std::nullopt)};
 
     SessionRestore::NotifySessionRestoreStartedLoadingTabs();
-    SessionRestore::OnWillRestoreTab(test_contents);
     TabLoader::RestoreTabs(restored_tabs, base::TimeTicks());
 
     ASSERT_EQ(event_index + 1, number_of_session_restore_events());
     EXPECT_EQ(
         MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS,
         session_restore_events()[event_index++]);
-    EXPECT_EQ(1u, number_of_tabs_restoring());
 
     LoadWebContents(test_contents);
     ASSERT_EQ(event_index + 1, number_of_session_restore_events());
     EXPECT_EQ(
         MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS,
         session_restore_events()[event_index++]);
-    EXPECT_EQ(0u, number_of_tabs_restoring());
   }
 }
 
@@ -209,8 +185,6 @@
                                      std::nullopt);
 
   SessionRestore::NotifySessionRestoreStartedLoadingTabs();
-  SessionRestore::OnWillRestoreTab(web_contents());
-  SessionRestore::OnWillRestoreTab(test_contents.get());
   RestoreTabs();
   TabLoader::RestoreTabs(another_restored_tabs, base::TimeTicks());
 
@@ -218,7 +192,6 @@
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS,
       session_restore_events()[0]);
-  EXPECT_EQ(2u, number_of_tabs_restoring());
 
   LoadWebContents(web_contents());
   LoadWebContents(test_contents.get());
@@ -226,5 +199,4 @@
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS,
       session_restore_events()[1]);
-  EXPECT_EQ(0u, number_of_tabs_restoring());
 }
diff --git a/chrome/browser/signin/reauth_tab_helper_unittest.cc b/chrome/browser/signin/reauth_tab_helper_unittest.cc
index cb7ac50..e8a59d8 100644
--- a/chrome/browser/signin/reauth_tab_helper_unittest.cc
+++ b/chrome/browser/signin/reauth_tab_helper_unittest.cc
@@ -32,8 +32,15 @@
     tab_helper_ = ReauthTabHelper::FromWebContents(web_contents());
   }
 
+  void TearDown() override {
+    ClearTabHelper();
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
   ReauthTabHelper* tab_helper() { return tab_helper_; }
 
+  void ClearTabHelper() { tab_helper_ = nullptr; }
+
   base::MockOnceCallback<void(signin::ReauthResult)>* mock_callback() {
     return &mock_callback_;
   }
@@ -41,7 +48,7 @@
   const GURL& reauth_url() { return reauth_url_; }
 
  private:
-  raw_ptr<ReauthTabHelper, DanglingUntriaged> tab_helper_ = nullptr;
+  raw_ptr<ReauthTabHelper> tab_helper_;
   base::MockOnceCallback<void(signin::ReauthResult)> mock_callback_;
   const GURL reauth_url_;
 };
@@ -152,6 +159,7 @@
 // Tests the WebContents deletion.
 TEST_F(ReauthTabHelperTest, WebContentsDestroyed) {
   EXPECT_CALL(*mock_callback(), Run(signin::ReauthResult::kDismissedByUser));
+  ClearTabHelper();
   DeleteContents();
 }
 
diff --git a/chrome/browser/signin/signin_promo_unittest.cc b/chrome/browser/signin/signin_promo_unittest.cc
index 0115346..06154179 100644
--- a/chrome/browser/signin/signin_promo_unittest.cc
+++ b/chrome/browser/signin/signin_promo_unittest.cc
@@ -352,6 +352,22 @@
   EXPECT_FALSE(ShouldShowPasswordSignInPromo(*profile()));
 }
 
+TEST_F(ShowSigninPromoTestWithFeatureFlags, DoNotShowPromoWithNoSyncService) {
+  TestingProfile::Builder profile_builder;
+  profile_builder.AddTestingFactory(
+      SyncServiceFactory::GetInstance(),
+      base::BindRepeating([](content::BrowserContext* context) {
+        return static_cast<std::unique_ptr<KeyedService>>(nullptr);
+      }));
+
+  std::unique_ptr<TestingProfile> profile =
+      IdentityTestEnvironmentProfileAdaptor::
+          CreateProfileForIdentityTestEnvironment(profile_builder);
+
+  ASSERT_EQ(nullptr, SyncServiceFactory::GetForProfile(profile.get()));
+  EXPECT_FALSE(ShouldShowPasswordSignInPromo(*profile));
+}
+
 TEST_F(ShowSigninPromoTestWithFeatureFlags,
        DoNotShowPromoWithOffTheRecordProfile) {
   EXPECT_FALSE(ShouldShowPasswordSignInPromo(
diff --git a/chrome/browser/signin/signin_promo_util.cc b/chrome/browser/signin/signin_promo_util.cc
index 52195f4..a569db4 100644
--- a/chrome/browser/signin/signin_promo_util.cc
+++ b/chrome/browser/signin/signin_promo_util.cc
@@ -125,13 +125,16 @@
     return false;
   }
 
-  // Don't show the promo if the user is off-the-record.
-  if (profile.IsOffTheRecord()) {
-    return false;
-  }
-
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(&profile);
+
+  // Don't show the promo if the sync service is not available, e.g. if the
+  // profile is off-the-record.
+  if (!sync_service) {
+    return false;
+  }
+  CHECK(!profile.IsOffTheRecord());
+
   syncer::DataType data_type = GetDataTypeFromSignInPromoType(type);
 
   // Don't show the promo if policies disallow account storage.
@@ -310,21 +313,24 @@
     return false;
   }
 
-  // If the user is in sign in pending state, the promo should only be shown if
-  // they already have account storage for bookmarks enabled.
+  if (!ShouldShowSignInPromoCommon(profile, SignInPromoType::kBookmark)) {
+    return false;
+  }
+
+  // At this point, both the identity manager and sync service should not be
+  // null.
   IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(&profile);
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(&profile);
-  if (identity_manager && signin_util::IsSigninPending(identity_manager)) {
-    if (!sync_service ||
-        !sync_service->GetUserSettings()->GetSelectedTypes().Has(
-            syncer::UserSelectableType::kBookmarks)) {
-      return false;
-    }
-  }
+  CHECK(identity_manager);
+  CHECK(sync_service);
 
-  return ShouldShowSignInPromoCommon(profile, SignInPromoType::kBookmark);
+  // If the user is in sign in pending state, the promo should only be shown if
+  // they already have account storage for bookmarks enabled.
+  return !signin_util::IsSigninPending(identity_manager) ||
+         sync_service->GetUserSettings()->GetSelectedTypes().Has(
+             syncer::UserSelectableType::kBookmarks);
 #else
   return false;
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 85797b7..475f6c9 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -869,14 +869,6 @@
       "android/passwords/all_passwords_bottom_sheet_view_impl.h",
       "android/passwords/credential_leak_dialog_view_android.cc",
       "android/passwords/credential_leak_dialog_view_android.h",
-      "android/plus_addresses/all_plus_addresses_bottom_sheet_controller.cc",
-      "android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h",
-      "android/plus_addresses/all_plus_addresses_bottom_sheet_view.cc",
-      "android/plus_addresses/all_plus_addresses_bottom_sheet_view.h",
-      "android/plus_addresses/plus_address_creation_controller_android.cc",
-      "android/plus_addresses/plus_address_creation_controller_android.h",
-      "android/plus_addresses/plus_address_creation_view_android.cc",
-      "android/plus_addresses/plus_address_creation_view_android.h",
       "android/safe_browsing/password_reuse_dialog_view_android.cc",
       "android/safe_browsing/password_reuse_dialog_view_android.h",
       "android/simple_message_box_android.cc",
@@ -908,6 +900,14 @@
       "android/webid/account_selection_view_android.cc",
       "android/webid/account_selection_view_android.h",
       "browser_otr_state_android.cc",
+      "plus_addresses/android/all_plus_addresses_bottom_sheet_controller.cc",
+      "plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h",
+      "plus_addresses/android/all_plus_addresses_bottom_sheet_view.cc",
+      "plus_addresses/android/all_plus_addresses_bottom_sheet_view.h",
+      "plus_addresses/android/plus_address_creation_controller_android.cc",
+      "plus_addresses/android/plus_address_creation_controller_android.h",
+      "plus_addresses/android/plus_address_creation_view_android.cc",
+      "plus_addresses/android/plus_address_creation_view_android.h",
       "screen_capture_notification_ui_stub.cc",
       "webui/feed_internals/feed_internals_ui.cc",
       "webui/feed_internals/feed_internals_ui.h",
@@ -1513,8 +1513,6 @@
       "webui/profile_internals/profile_internals_ui.h",
       "webui/sanitized_image_source.cc",
       "webui/sanitized_image_source.h",
-      "webui/search_engine_choice/icon_utils.cc",
-      "webui/search_engine_choice/icon_utils.h",
       "webui/search_engine_choice/search_engine_choice_handler.cc",
       "webui/search_engine_choice/search_engine_choice_handler.h",
       "webui/search_engine_choice/search_engine_choice_ui.cc",
@@ -3686,6 +3684,9 @@
       "plus_addresses/plus_address_error_dialog.h",
       "plus_addresses/plus_address_menu_model.cc",
       "plus_addresses/plus_address_menu_model.h",
+      "plus_addresses/views/plus_address_creation_controller_desktop.cc",
+      "plus_addresses/views/plus_address_creation_dialog_delegate.cc",
+      "plus_addresses/views/plus_address_creation_dialog_delegate.h",
       "send_tab_to_self/send_tab_to_self_bubble.h",
       "send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc",
       "send_tab_to_self/send_tab_to_self_toolbar_icon_controller.h",
@@ -4572,9 +4573,6 @@
       "views/permissions/permission_prompt_quiet_icon.cc",
       "views/permissions/permission_prompt_quiet_icon.h",
       "views/permissions/permission_prompt_style.h",
-      "views/plus_addresses/plus_address_creation_controller_desktop.cc",
-      "views/plus_addresses/plus_address_creation_dialog_delegate.cc",
-      "views/plus_addresses/plus_address_creation_dialog_delegate.h",
       "views/profiles/avatar_toolbar_button.cc",
       "views/profiles/avatar_toolbar_button.h",
       "views/profiles/avatar_toolbar_button_delegate.cc",
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java
index 0bb49bf..3e1f515 100644
--- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java
+++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java
@@ -129,6 +129,12 @@
 
     @After
     public void tearDown() {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    if (mAppMenuHandler.isAppMenuShowing()) {
+                        mAppMenuHandler.getAppMenu().dismiss();
+                    }
+                });
         NightModeTestUtils.tearDownNightModeForBlankUiTestActivity();
     }
 
@@ -347,15 +353,15 @@
         showMenuAndAssert();
         AppMenu spiedMenu = Mockito.spy(mAppMenuHandler.getAppMenu());
 
-        View dummyView = new View(sActivity);
+        View testView = new View(sActivity);
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     spiedMenu.onItemLongClick(
                             mAppMenuHandler.getAppMenu().getMenuItemPropertyModel(R.id.icon_one),
-                            dummyView);
+                            testView);
                 });
 
-        Mockito.verify(spiedMenu, Mockito.times(1)).showToastForItem("Icon One", dummyView);
+        Mockito.verify(spiedMenu, Mockito.times(1)).showToastForItem("Icon One", testView);
     }
 
     @Test
@@ -365,15 +371,15 @@
         showMenuAndAssert();
         AppMenu spiedMenu = Mockito.spy(mAppMenuHandler.getAppMenu());
 
-        View dummyView = new View(sActivity);
+        View testView = new View(sActivity);
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     spiedMenu.onItemLongClick(
                             mAppMenuHandler.getAppMenu().getMenuItemPropertyModel(R.id.icon_two),
-                            dummyView);
+                            testView);
                 });
 
-        Mockito.verify(spiedMenu, Mockito.times(1)).showToastForItem("2", dummyView);
+        Mockito.verify(spiedMenu, Mockito.times(1)).showToastForItem("2", testView);
     }
 
     @Test
@@ -383,12 +389,12 @@
         showMenuAndAssert();
         AppMenu spiedMenu = Mockito.spy(mAppMenuHandler.getAppMenu());
 
-        View dummyView = new View(sActivity);
+        View testView = new View(sActivity);
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     spiedMenu.onItemLongClick(
                             mAppMenuHandler.getAppMenu().getMenuItemPropertyModel(R.id.icon_three),
-                            dummyView);
+                            testView);
                 });
 
         Mockito.verify(spiedMenu, Mockito.times(0))
@@ -737,7 +743,7 @@
         KeyEvent down = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
         Assert.assertFalse(
                 "#onKeyEvent should return false when app menu hidden",
-                appMenu.onKey(null, KeyEvent.KEYCODE_MENU, null));
+                appMenu.onKey(null, KeyEvent.KEYCODE_MENU, down));
     }
 
     @Test
diff --git a/chrome/browser/ui/android/layouts/glue/BUILD.gn b/chrome/browser/ui/android/layouts/glue/BUILD.gn
index 4ef2d93..24241ab 100644
--- a/chrome/browser/ui/android/layouts/glue/BUILD.gn
+++ b/chrome/browser/ui/android/layouts/glue/BUILD.gn
@@ -9,7 +9,7 @@
     ":*",
     "//chrome/android:chrome_java",
     "//chrome/android/junit:*",
-    "//chrome/browser/ui/android/plus_addresses:junit",
+    "//chrome/browser/ui/plus_addresses/android:junit",
   ]
 
   sources = [
diff --git a/chrome/browser/ui/android/multiwindow/java/res/layout/close_confirmation_dialog.xml b/chrome/browser/ui/android/multiwindow/java/res/layout/close_confirmation_dialog.xml
index 376033c..85a675e1 100644
--- a/chrome/browser/ui/android/multiwindow/java/res/layout/close_confirmation_dialog.xml
+++ b/chrome/browser/ui/android/multiwindow/java/res/layout/close_confirmation_dialog.xml
@@ -16,8 +16,15 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical">
-        <include layout="@layout/modal_dialog_title"
-            android:id="@+id/title_container"/>
+
+        <androidx.appcompat.widget.DialogTitle
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:ellipsize="end"
+            android:paddingHorizontal="@dimen/dialog_padding_sides"
+            android:paddingTop="@dimen/dialog_padding_sides"
+            android:textAppearance="@style/TextAppearance.AlertDialogTitleStyle" />
 
         <TextView
             android:id="@+id/message"
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java
index aadb289..ce01788b 100644
--- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java
+++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java
@@ -11,11 +11,9 @@
 import android.app.Dialog;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.CheckBox;
-import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
 
@@ -76,7 +74,6 @@
     private final ModelList mModelList = new ModelList();
     private final UiUtils mUiUtils;
     private final View mDialogView;
-    private final Drawable mArrowBackIcon;
 
     private @Nullable PropertyModel mDialog;
     private @Nullable InstanceInfo mItemToDelete;
@@ -126,7 +123,6 @@
         mCloseCallback = closeCallback;
         mUiUtils = new UiUtils(mContext, iconBridge);
         mNewWindowAction = newWindowAction;
-        mArrowBackIcon = mUiUtils.getTintedIcon(R.drawable.ic_arrow_back_24dp);
 
         ModelListAdapter adapter = new ModelListAdapter(mModelList);
         // TODO: Extend modern_list_item_view.xml to replace instance_switcher_item.xml
@@ -308,10 +304,6 @@
         dialog.setContentView(R.layout.close_confirmation_dialog);
 
         Resources res = mContext.getResources();
-        ImageView iconView = (ImageView) dialog.findViewById(R.id.title_icon);
-        iconView.setImageDrawable(mArrowBackIcon);
-        iconView.setOnClickListener(v -> dialog.dismiss());
-
         String title = res.getString(R.string.instance_switcher_close_confirm_header);
         ((TextView) dialog.findViewById(R.id.title)).setText(title);
         TextView messageView = (TextView) dialog.findViewById(R.id.message);
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
index 5f08674..c29d0c9 100644
--- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
+++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
@@ -24,6 +24,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -35,6 +36,8 @@
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Criteria;
+import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
@@ -290,7 +293,7 @@
 
     @Test
     @SmallTest
-    public void testBackOnConfirmDialog() throws Exception {
+    public void testCancelButton() throws Exception {
         InstanceInfo[] instances =
                 new InstanceInfo[] {
                     new InstanceInfo(
@@ -324,7 +327,11 @@
         onView(allOf(withText(R.string.instance_switcher_close_confirm_header)))
                 .check(matches(isDisplayed()));
 
-        onView(allOf(withId(R.id.title_icon), withEffectiveVisibility(VISIBLE))).perform(click());
-        onView(allOf(withText(R.string.instance_switcher_header))).check(matches(isDisplayed()));
+        onView(withText(R.string.cancel)).perform(click());
+        // The cancel button closes the instance switcher and opens the last opened window/tab
+        CriteriaHelper.pollUiThread(
+                () -> {
+                    Criteria.checkThat(mModalDialogManager.isShowing(), Matchers.is(false));
+                });
     }
 }
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java
index 04991c7..8fcbd90 100644
--- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java
+++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java
@@ -294,8 +294,6 @@
                 new Controller() {
                     @Override
                     public void onClick(PropertyModel model, int buttonType) {
-                        // TODO(crbug.com/40200588): Set clickable to false for title icon.
-                        if (buttonType == ButtonType.TITLE_ICON) return;
                         if (buttonType == ButtonType.POSITIVE) {
                             if (feedbackDialogEnabled) {
                                 showFeedback(activity, profile, url);
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageControllerUnitTest.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageControllerUnitTest.java
index eff947f..5a9d4a3 100644
--- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageControllerUnitTest.java
+++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageControllerUnitTest.java
@@ -447,20 +447,6 @@
     }
 
     @Test
-    public void testShowDialog_ClickTitleIcon() {
-        // Click on title icon.
-        WebContentsDarkModeMessageController.attemptToShowDialog(
-                mMockActivity, mMockProfile, TEST_URL, mModalDialogManager);
-        mModalDialogManager.clickButton(ButtonType.TITLE_ICON);
-
-        // Verify not dismissed.
-        Assert.assertNotNull(
-                "Shown dialog model should be non-null after clicking the title icon.",
-                mModalDialogManager.mShownDialogModel);
-        verify(mMockTracker, never()).dismissed(eq(OPT_OUT_FEATURE));
-    }
-
-    @Test
     public void testClickableSpan_SettingsLink() {
         AutoDarkClickableSpan clickableSpan = new AutoDarkClickableSpan(mMockActivity);
         clickableSpan.onClick(null);
diff --git a/chrome/browser/ui/android/plus_addresses/DEPS b/chrome/browser/ui/android/plus_addresses/DEPS
deleted file mode 100644
index a98971e61c..0000000
--- a/chrome/browser/ui/android/plus_addresses/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  "+chrome/android",
-  "+components/plus_addresses",
-]
diff --git a/chrome/browser/ui/android/plus_addresses/DIR_METADATA b/chrome/browser/ui/android/plus_addresses/DIR_METADATA
deleted file mode 100644
index a8bf562e..0000000
--- a/chrome/browser/ui/android/plus_addresses/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-mixins: "//components/plus_addresses/COMMON_METADATA"
diff --git a/chrome/browser/ui/android/plus_addresses/OWNERS b/chrome/browser/ui/android/plus_addresses/OWNERS
deleted file mode 100644
index 82cf094..0000000
--- a/chrome/browser/ui/android/plus_addresses/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/plus_addresses/OWNERS
diff --git a/chrome/browser/ui/android/searchactivityutils/java/src/org/chromium/chrome/browser/ui/searchactivityutils/SearchActivityPreferencesManager.java b/chrome/browser/ui/android/searchactivityutils/java/src/org/chromium/chrome/browser/ui/searchactivityutils/SearchActivityPreferencesManager.java
index b7d610c..18317173 100644
--- a/chrome/browser/ui/android/searchactivityutils/java/src/org/chromium/chrome/browser/ui/searchactivityutils/SearchActivityPreferencesManager.java
+++ b/chrome/browser/ui/android/searchactivityutils/java/src/org/chromium/chrome/browser/ui/searchactivityutils/SearchActivityPreferencesManager.java
@@ -137,7 +137,9 @@
 
     /** Returns current knowh SharedActivityPreferences values. */
     public static SearchActivityPreferences getCurrent() {
-        return assumeNonNull(get().mCurrentlyLoadedPreferences);
+        SearchActivityPreferences ret = get().mCurrentlyLoadedPreferences;
+        assert ret != null;
+        return ret;
     }
 
     /**
@@ -244,9 +246,10 @@
     public static void addObserver(Consumer<SearchActivityPreferences> observer) {
         ThreadUtils.assertOnUiThread();
         SearchActivityPreferencesManager self = get();
-        if (!self.mObservers.hasObserver(observer)) {
-            self.mObservers.addObserver(observer);
-            observer.accept(self.mCurrentlyLoadedPreferences);
+        if (self.mObservers.addObserver(observer)) {
+            if (self.mCurrentlyLoadedPreferences != null) {
+                observer.accept(self.mCurrentlyLoadedPreferences);
+            }
         }
     }
 
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetMediator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetMediator.java
index bc138d41..6c08924 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetMediator.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetMediator.java
@@ -4,13 +4,15 @@
 
 package org.chromium.chrome.browser.ui.signin.account_picker;
 
-import static org.chromium.build.NullUtil.assumeNonNull;
+import static org.chromium.build.NullUtil.assertNonNull;
 
 import android.accounts.AccountManager;
 import android.app.Activity;
 import android.content.Intent;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
+
 import org.chromium.base.BuildInfo;
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplierImpl;
@@ -26,6 +28,7 @@
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.AccountsChangeObserver;
+import org.chromium.components.signin.base.AccountInfo;
 import org.chromium.components.signin.base.CoreAccountId;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.metrics.AccountConsistencyPromoAction;
@@ -36,6 +39,7 @@
 import org.chromium.ui.modelutil.PropertyObservable.PropertyObserver;
 
 import java.util.List;
+import java.util.Objects;
 
 /** Mediator of the account picker bottom sheet in web sign-in flow. */
 @NullMarked
@@ -57,13 +61,12 @@
     private final boolean mIsWebSignin;
     private final @SigninAccessPoint int mSigninAccessPoint;
 
-    // TODO(crbug.com/41487829): Use CoreAccountInfo here instead.
-    private @Nullable String mSelectedAccountEmail;
-    private @Nullable String mDefaultAccountEmail;
-    private @Nullable String mAddedAccountEmail;
+    private @Nullable CoreAccountInfo mSelectedAccount;
+    private @Nullable CoreAccountInfo mDefaultAccount;
+    private @Nullable CoreAccountInfo mAddedAccount;
     // This field is used to save the added account email while the account info becomes available
     // in AccountManagerFacade for sign-in.
-    private @Nullable String mPendingSelectedAccountEmail;
+    private @Nullable String mPendingAddedAccountEmail;
     private boolean mAcceptedAccountManagement;
 
     private final PropertyObserver<PropertyKey> mModelPropertyChangedObserver;
@@ -81,7 +84,7 @@
             @SigninAccessPoint int signinAccessPoint,
             @Nullable CoreAccountId accountId) {
         mWindowAndroid = windowAndroid;
-        mActivity = assumeNonNull(windowAndroid.getActivity().get());
+        mActivity = assertNonNull(windowAndroid.getActivity().get());
         mAccountPickerDelegate = accountPickerDelegate;
         mProfileDataCache = ProfileDataCache.createWithDefaultImageSizeAndNoBadge(mActivity);
         mDeviceLockActivityLauncher = deviceLockActivityLauncher;
@@ -115,35 +118,22 @@
         mProfileDataCache.addObserver(this);
 
         mAccountManagerFacade = AccountManagerFacadeProvider.getInstance();
-        mAddedAccountEmail = null;
         initializeViewState(
-                AccountUtils.getCoreAccountInfosIfFulfilledOrEmpty(
-                        mAccountManagerFacade.getCoreAccountInfos()),
+                AccountUtils.getAccountsIfFulfilledOrEmpty(mAccountManagerFacade.getAccounts()),
                 accountId);
         mAccountManagerFacade.addObserver(this);
     }
 
     /** Implements {@link AccountPickerCoordinator.Listener}. */
     @Override
-    public void onAccountSelected(String accountName) {
-        if (mPendingSelectedAccountEmail != null) {
-            mPendingSelectedAccountEmail = null;
+    public void onAccountSelected(CoreAccountInfo account) {
+        if (mPendingAddedAccountEmail != null) {
+            // If another account is selected before the added account is available in account
+            // manager facade then clear the pending added account email so that it doesn't get
+            // selected automatically in #updateAccounts().
+            mPendingAddedAccountEmail = null;
         }
-
-        var coreAccountInfos =
-                AccountUtils.getCoreAccountInfosIfFulfilledOrEmpty(
-                        mAccountManagerFacade.getCoreAccountInfos());
-        @Nullable
-        CoreAccountInfo selectedAccount =
-                AccountUtils.findCoreAccountInfoByEmail(coreAccountInfos, accountName);
-        if (selectedAccount == null) {
-            // #updateAccounts() will call #onAccountSelected() when the account is available in
-            // AccountManagerFacade.
-            mPendingSelectedAccountEmail = accountName;
-            return;
-        }
-
-        setSelectedAccountName(accountName);
+        setSelectedAccount(account);
         launchDeviceLockIfNeededAndSignIn();
     }
 
@@ -160,15 +150,12 @@
 
         final WindowAndroid.IntentCallback onAddAccountCompleted =
                 (int resultCode, Intent data) -> {
-                    if (resultCode != Activity.RESULT_OK) {
+                    @Nullable String addedAccountEmail =
+                            data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
+                    if (resultCode != Activity.RESULT_OK || addedAccountEmail == null) {
                         return;
                     }
-                    SigninMetricsUtils.logAccountConsistencyPromoAction(
-                            AccountConsistencyPromoAction.ADD_ACCOUNT_COMPLETED,
-                            mSigninAccessPoint);
-                    mAddedAccountEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
-                    assert mAddedAccountEmail != null;
-                    onAccountSelected(mAddedAccountEmail);
+                    onAccountAddedInternal(addedAccountEmail);
                 };
         mAccountManagerFacade.createAddAccountIntent(
                 intent -> {
@@ -187,12 +174,25 @@
      * Called by the embedder when an account is added through the latter. Sign-in the just added
      * user.
      */
-    public void onAccountAdded(String accountEmail) {
+    public void onAccountAdded(@NonNull String accountEmail) {
+        assert mAccountPickerDelegate.canHandleAddAccount();
+        onAccountAddedInternal(accountEmail);
+    }
+
+    private void onAccountAddedInternal(String accountEmail) {
         SigninMetricsUtils.logAccountConsistencyPromoAction(
                 AccountConsistencyPromoAction.ADD_ACCOUNT_COMPLETED, mSigninAccessPoint);
 
-        assert mAccountPickerDelegate.canHandleAddAccount();
-        onAccountSelected(accountEmail);
+        var accounts =
+                AccountUtils.getAccountsIfFulfilledOrEmpty(mAccountManagerFacade.getAccounts());
+        mAddedAccount = AccountUtils.findAccountByEmail(accounts, accountEmail);
+        if (mAddedAccount == null) {
+            // #updateAccounts() will call #onAccountSelected() when the account is available in
+            // AccountManagerFacade.
+            mPendingAddedAccountEmail = accountEmail;
+            return;
+        }
+        onAccountSelected(mAddedAccount);
     }
 
     /**
@@ -217,7 +217,7 @@
     /** Implements {@link AccountsChangeObserver}. */
     @Override
     public void onCoreAccountInfosChanged() {
-        mAccountManagerFacade.getCoreAccountInfos().then(this::updateAccounts);
+        mAccountManagerFacade.getAccounts().then(this::updateAccounts);
     }
 
     /** Implements {@link ProfileDataCache.Observer}. */
@@ -274,8 +274,8 @@
     }
 
     private void initializeViewState(
-            List<CoreAccountInfo> coreAccountInfos, @Nullable CoreAccountId accountId) {
-        if (coreAccountInfos.isEmpty()) {
+            List<AccountInfo> accounts, @Nullable CoreAccountId accountId) {
+        if (accounts.isEmpty()) {
             // If all accounts disappeared, no matter if the account list initial state, we will go
             // to the zero account screen.
             setNoAccountState();
@@ -283,70 +283,72 @@
         }
 
         if (accountId != null) {
-            mDefaultAccountEmail =
-                    assumeNonNull(
-                                    AccountUtils.findCoreAccountInfoByGaiaId(
-                                            coreAccountInfos, accountId.getId()))
-                            .getEmail();
-            setSelectedAccountName(mDefaultAccountEmail);
+            mDefaultAccount =
+                    assertNonNull(AccountUtils.findAccountByGaiaId(accounts, accountId.getId()));
+            setSelectedAccount(mDefaultAccount);
             mModel.set(AccountPickerBottomSheetProperties.VIEW_STATE, mInitialViewState);
             return;
         }
-        mDefaultAccountEmail = coreAccountInfos.get(0).getEmail();
-        setSelectedAccountName(mDefaultAccountEmail);
+        mDefaultAccount = accounts.get(0);
+        setSelectedAccount(mDefaultAccount);
         mModel.set(AccountPickerBottomSheetProperties.VIEW_STATE, mInitialViewState);
     }
 
-    private void updateAccounts(List<CoreAccountInfo> coreAccountInfos) {
-        if (coreAccountInfos.isEmpty()) {
+    private void updateAccounts(List<AccountInfo> accounts) {
+        if (accounts.isEmpty()) {
             // If all accounts disappeared, no matter if the account list is collapsed or expanded,
             // we will go to the zero account screen.
             setNoAccountState();
             return;
         }
 
-        if (mPendingSelectedAccountEmail != null
-                && AccountUtils.findCoreAccountInfoByEmail(
-                                coreAccountInfos, mPendingSelectedAccountEmail)
-                        != null) {
-            onAccountSelected(mPendingSelectedAccountEmail);
+        @Nullable AccountInfo pendingAddedAccount =
+                mPendingAddedAccountEmail == null
+                        ? null
+                        : AccountUtils.findAccountByEmail(accounts, mPendingAddedAccountEmail);
+        if (pendingAddedAccount != null) {
+            mPendingAddedAccountEmail = null;
+            mAddedAccount = pendingAddedAccount;
+            onAccountSelected(mAddedAccount);
             return;
         }
 
-        mDefaultAccountEmail = coreAccountInfos.get(0).getEmail();
+        mDefaultAccount = accounts.get(0);
+        mSelectedAccount =
+                mSelectedAccount == null
+                        ? null
+                        : AccountUtils.findAccountByEmail(accounts, mSelectedAccount.getEmail());
         @ViewState int viewState = mModel.get(AccountPickerBottomSheetProperties.VIEW_STATE);
         if (viewState == ViewState.NO_ACCOUNTS) {
             // When a non-empty account list appears while it is currently zero-account screen,
             // we should change the screen to collapsed account list and set the selected account
             // to the first account of the account list
-            setSelectedAccountName(mDefaultAccountEmail);
+            setSelectedAccount(mDefaultAccount);
             mModel.set(
                     AccountPickerBottomSheetProperties.VIEW_STATE,
                     ViewState.COLLAPSED_ACCOUNT_LIST);
-        } else if (viewState == ViewState.COLLAPSED_ACCOUNT_LIST
-                && AccountUtils.findCoreAccountInfoByEmail(
-                                coreAccountInfos, assumeNonNull(mSelectedAccountEmail))
-                        == null) {
+        } else if (viewState == ViewState.COLLAPSED_ACCOUNT_LIST && mSelectedAccount == null) {
             // When it is already collapsed account list, we update the selected account only
             // when the current selected account name is no longer in the new account list
-            setSelectedAccountName(mDefaultAccountEmail);
+            setSelectedAccount(mDefaultAccount);
         }
     }
 
     private void setNoAccountState() {
         mModel.set(AccountPickerBottomSheetProperties.VIEW_STATE, ViewState.NO_ACCOUNTS);
-        mSelectedAccountEmail = null;
-        mDefaultAccountEmail = null;
+        mSelectedAccount = null;
+        mDefaultAccount = null;
         mModel.set(AccountPickerBottomSheetProperties.SELECTED_ACCOUNT_DATA, null);
     }
 
-    private void setSelectedAccountName(String accountName) {
-        mSelectedAccountEmail = accountName;
-        updateSelectedAccountData(mSelectedAccountEmail);
+    private void setSelectedAccount(CoreAccountInfo account) {
+        mSelectedAccount = account;
+        updateSelectedAccountData(account.getEmail());
     }
 
     private void updateSelectedAccountData(String accountEmail) {
-        if (TextUtils.equals(mSelectedAccountEmail, accountEmail)) {
+        if (mSelectedAccount != null
+                && TextUtils.equals(mSelectedAccount.getEmail(), accountEmail)) {
             mModel.set(
                     AccountPickerBottomSheetProperties.SELECTED_ACCOUNT_DATA,
                     mProfileDataCache.getProfileDataOrDefault(accountEmail));
@@ -398,7 +400,7 @@
         if (BuildInfo.getInstance().isAutomotive) {
             mDeviceLockActivityLauncher.launchDeviceLockActivity(
                     mActivity,
-                    mSelectedAccountEmail,
+                    CoreAccountInfo.getEmailFrom(mSelectedAccount),
                     /* requireDeviceLockReauthentication= */ true,
                     mWindowAndroid,
                     (resultCode, data) -> {
@@ -413,22 +415,17 @@
     }
 
     private void signIn() {
-        mModel.set(AccountPickerBottomSheetProperties.VIEW_STATE, ViewState.SIGNIN_IN_PROGRESS);
-        assumeNonNull(mSelectedAccountEmail);
-        CoreAccountInfo accountInfo =
-                AccountUtils.findCoreAccountInfoByEmail(
-                        mAccountManagerFacade.getCoreAccountInfos().getResult(),
-                        mSelectedAccountEmail);
         // If the account is not available or disappears right after the user adds it, the sign-in
         // can't be done and a general error view with retry button is shown.
-        if (accountInfo == null) {
+        if (mSelectedAccount == null) {
             mModel.set(
                     AccountPickerBottomSheetProperties.VIEW_STATE, ViewState.SIGNIN_GENERAL_ERROR);
             return;
         }
 
+        mModel.set(AccountPickerBottomSheetProperties.VIEW_STATE, ViewState.SIGNIN_IN_PROGRESS);
         mAccountPickerDelegate.isAccountManaged(
-                accountInfo,
+                mSelectedAccount,
                 (Boolean isAccountManaged) -> {
                     if (isAccountManaged) {
                         SigninMetricsUtils.logAccountConsistencyPromoAction(
@@ -444,14 +441,23 @@
     }
 
     private void signInAfterCheckingManagement() {
+        // If the account is not available or disappears right after the user adds it, the sign-in
+        // can't be done and a general error view with retry button is shown.
+        if (mSelectedAccount == null) {
+            mModel.set(
+                    AccountPickerBottomSheetProperties.VIEW_STATE, ViewState.SIGNIN_GENERAL_ERROR);
+            return;
+        }
+
         if (mAcceptedAccountManagement) {
             mAccountPickerDelegate.setUserAcceptedAccountManagement(true);
         }
         mModel.set(AccountPickerBottomSheetProperties.VIEW_STATE, ViewState.SIGNIN_IN_PROGRESS);
-        if (TextUtils.equals(mSelectedAccountEmail, mAddedAccountEmail)) {
+
+        if (Objects.equals(mSelectedAccount, mAddedAccount)) {
             SigninMetricsUtils.logAccountConsistencyPromoAction(
                     AccountConsistencyPromoAction.SIGNED_IN_WITH_ADDED_ACCOUNT, mSigninAccessPoint);
-        } else if (TextUtils.equals(mSelectedAccountEmail, mDefaultAccountEmail)) {
+        } else if (Objects.equals(mSelectedAccount, mDefaultAccount)) {
             SigninMetricsUtils.logAccountConsistencyPromoAction(
                     AccountConsistencyPromoAction.SIGNED_IN_WITH_DEFAULT_ACCOUNT,
                     mSigninAccessPoint);
@@ -465,20 +471,7 @@
             SigninPreferencesManager.getInstance()
                     .clearWebSigninAccountPickerActiveDismissalCount();
         }
-
-        assumeNonNull(mSelectedAccountEmail);
-        CoreAccountInfo accountInfo =
-                AccountUtils.findCoreAccountInfoByEmail(
-                        mAccountManagerFacade.getCoreAccountInfos().getResult(),
-                        mSelectedAccountEmail);
-        // If the account is not available or disappears right after the user adds it, the sign-in
-        // can't be done and a general error view with retry button is shown.
-        if (accountInfo == null) {
-            mModel.set(
-                    AccountPickerBottomSheetProperties.VIEW_STATE, ViewState.SIGNIN_GENERAL_ERROR);
-            return;
-        }
-        mAccountPickerDelegate.signIn(accountInfo, this);
+        mAccountPickerDelegate.signIn(mSelectedAccount, this);
     }
 
     private void updateCredentials() {
@@ -490,9 +483,9 @@
                                 ViewState.COLLAPSED_ACCOUNT_LIST);
                     }
                 };
-        assumeNonNull(mSelectedAccountEmail);
+        assertNonNull(mSelectedAccount);
         mAccountManagerFacade.updateCredentials(
-                AccountUtils.createAccountFromName(mSelectedAccountEmail),
+                CoreAccountInfo.getAndroidAccountFrom(mSelectedAccount),
                 mActivity,
                 onUpdateCredentialsCompleted);
     }
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerCoordinator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerCoordinator.java
index 50cde0b..f77c836 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerCoordinator.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerCoordinator.java
@@ -11,6 +11,7 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerProperties.AddAccountRowProperties;
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerProperties.ItemType;
+import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.ui.modelutil.LayoutViewBuilder;
 import org.chromium.ui.modelutil.MVCListAdapter;
 import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter;
@@ -25,12 +26,11 @@
     /** Listener for account picker. */
     public interface Listener {
         /**
-         * Notifies that the user has selected an account. TODO(crbug.com/40144553): Use
-         * CoreAccountInfo instead of account's email as the first argument of the method.
+         * Notifies that the user has selected an account.
          *
-         * @param accountName The email of the selected account.
+         * @param coreAccountInfo The selected account.
          */
-        void onAccountSelected(String accountName);
+        void onAccountSelected(CoreAccountInfo coreAccountInfo);
 
         /** Notifies when the user clicked the "add account" button. */
         void addAccount();
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerDialogTest.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerDialogTest.java
index c0f9e10c..c55452e 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerDialogTest.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerDialogTest.java
@@ -123,14 +123,14 @@
                 .inRoot(isDialog())
                 .check(matches(isDisplayed()));
         onView(withText(TestAccounts.ACCOUNT1.getFullName())).inRoot(isDialog()).perform(click());
-        verify(mListenerMock).onAccountSelected(TestAccounts.ACCOUNT1.getEmail());
+        verify(mListenerMock).onAccountSelected(TestAccounts.ACCOUNT1);
     }
 
     @Test
     @MediumTest
     public void testSelectNonDefaultAccount() {
         onView(withText(TestAccounts.ACCOUNT2.getEmail())).inRoot(isDialog()).perform(click());
-        verify(mListenerMock).onAccountSelected(TestAccounts.ACCOUNT2.getEmail());
+        verify(mListenerMock).onAccountSelected(TestAccounts.ACCOUNT2);
     }
 
     @Test
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediator.java
index 196b89a..b1f9717 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediator.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediator.java
@@ -9,9 +9,7 @@
 
 import androidx.annotation.MainThread;
 
-import org.chromium.base.Callback;
 import org.chromium.build.annotations.NullMarked;
-import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.ProfileDataCache;
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerProperties.AddAccountRowProperties;
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerProperties.ExistingAccountRowProperties;
@@ -94,15 +92,12 @@
         mListModel.clear();
 
         // Add an "existing account" row for each account
-        final Callback<DisplayableProfileData> callback =
-                profileData ->
-                        mAccountPickerListener.onAccountSelected(profileData.getAccountEmail());
         for (CoreAccountInfo coreAccountInfo : coreAccountInfos) {
             PropertyModel model =
                     ExistingAccountRowProperties.createModel(
                             mProfileDataCache.getProfileDataOrDefault(coreAccountInfo.getEmail()),
                             /* isCurrentlySelected= */ false,
-                            callback);
+                            () -> mAccountPickerListener.onAccountSelected(coreAccountInfo));
             mListModel.add(new MVCListAdapter.ListItem(ItemType.EXISTING_ACCOUNT_ROW, model));
         }
 
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerProperties.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerProperties.java
index ddc7668..ec96ff9 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerProperties.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerProperties.java
@@ -8,7 +8,6 @@
 
 import androidx.annotation.IntDef;
 
-import org.chromium.base.Callback;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.ui.modelutil.PropertyKey;
@@ -44,9 +43,8 @@
                 new PropertyModel.WritableObjectPropertyKey<>("profile_data");
         static final PropertyModel.WritableBooleanPropertyKey IS_CURRENTLY_SELECTED =
                 new PropertyModel.WritableBooleanPropertyKey("is_currently_selected");
-        static final PropertyModel.ReadableObjectPropertyKey<Callback<DisplayableProfileData>>
-                ON_CLICK_LISTENER =
-                        new PropertyModel.ReadableObjectPropertyKey<>("on_click_listener");
+        static final PropertyModel.ReadableObjectPropertyKey<Runnable> ON_CLICK_LISTENER =
+                new PropertyModel.ReadableObjectPropertyKey<>("on_click_listener");
 
         static final PropertyKey[] ALL_KEYS =
                 new PropertyKey[] {PROFILE_DATA, IS_CURRENTLY_SELECTED, ON_CLICK_LISTENER};
@@ -56,7 +54,7 @@
         static PropertyModel createModel(
                 DisplayableProfileData profileData,
                 boolean isCurrentlySelected,
-                Callback<DisplayableProfileData> listener) {
+                Runnable listener) {
             return new PropertyModel.Builder(ALL_KEYS)
                     .with(PROFILE_DATA, profileData)
                     .with(IS_CURRENTLY_SELECTED, isCurrentlySelected)
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/ExistingAccountRowViewBinder.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/ExistingAccountRowViewBinder.java
index 1ece2b9..b7217f6 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/ExistingAccountRowViewBinder.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/ExistingAccountRowViewBinder.java
@@ -31,9 +31,7 @@
         boolean isCurrentlySelected = model.get(ExistingAccountRowProperties.IS_CURRENTLY_SELECTED);
         if (propertyKey == ExistingAccountRowProperties.ON_CLICK_LISTENER) {
             view.setOnClickListener(
-                    v ->
-                            model.get(ExistingAccountRowProperties.ON_CLICK_LISTENER)
-                                    .onResult(profileData));
+                    v -> model.get(ExistingAccountRowProperties.ON_CLICK_LISTENER).run());
         } else if ((propertyKey == ExistingAccountRowProperties.PROFILE_DATA)
                 || (propertyKey == ExistingAccountRowProperties.IS_CURRENTLY_SELECTED)) {
             bindAccountView(profileData, view, isCurrentlySelected);
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/fullscreen_signin/FullscreenSigninMediator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/fullscreen_signin/FullscreenSigninMediator.java
index a1820d5..e6a1ce5 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/fullscreen_signin/FullscreenSigninMediator.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/fullscreen_signin/FullscreenSigninMediator.java
@@ -298,8 +298,8 @@
     }
 
     @Override
-    public void onAccountSelected(String accountName) {
-        setSelectedAccountEmail(accountName);
+    public void onAccountSelected(CoreAccountInfo coreAccountInfo) {
+        setSelectedAccountEmail(coreAccountInfo.getEmail());
         if (mDialogCoordinator != null) mDialogCoordinator.dismissDialog();
     }
 
diff --git a/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediatorTest.java b/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediatorTest.java
index 0d147d3..2a901a4 100644
--- a/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediatorTest.java
+++ b/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerMediatorTest.java
@@ -23,6 +23,8 @@
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerProperties.AddAccountRowProperties;
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerProperties.ExistingAccountRowProperties;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
+import org.chromium.components.signin.base.AccountInfo;
+import org.chromium.components.signin.test.util.TestAccounts;
 import org.chromium.ui.modelutil.MVCListAdapter;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -30,10 +32,13 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @LooperMode(LooperMode.Mode.LEGACY)
 public class AccountPickerMediatorTest {
-    private static final String FULL_NAME1 = "Test Account1";
-    private static final String FULL_NAME2 = "Test Account2";
-    private static final String ACCOUNT_EMAIL1 = "test.account1@gmail.com";
-    private static final String ACCOUNT_EMAIL2 = "test.account2@gmail.com";
+    /* Used to simulate a name change event for TestAccounts.ACCOUNT1. */
+    public static final AccountInfo ACCOUNT1_DIFFERENT_NAME =
+            new AccountInfo.Builder(
+                            TestAccounts.ACCOUNT1.getEmail(), TestAccounts.ACCOUNT1.getGaiaId())
+                    .fullName("Different Test1 Full")
+                    .givenName("Different Test1 Given")
+                    .build();
 
     @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@@ -56,46 +61,42 @@
 
     @Test
     public void testModelPopulation() {
-        mAccountManagerTestRule.addAccount(ACCOUNT_EMAIL1, FULL_NAME1, null, null);
-        mAccountManagerTestRule.addAccount(ACCOUNT_EMAIL2, FULL_NAME2, null, null);
+        mAccountManagerTestRule.addAccount(TestAccounts.ACCOUNT1);
+        mAccountManagerTestRule.addAccount(TestAccounts.ACCOUNT2);
         mMediator =
                 new AccountPickerMediator(
-                        RuntimeEnvironment.application, mModelList, mListenerMock);
-        // ACCOUNT_NAME1, ACCOUNT_NAME2, ADD_ACCOUNT.
+                        RuntimeEnvironment.getApplication(), mModelList, mListenerMock);
+        // ACCOUNT1, ACCOUNT2, ADD_ACCOUNT.
         Assert.assertEquals(3, mModelList.size());
-        checkItemForExistingAccountRow(0, ACCOUNT_EMAIL1, FULL_NAME1);
-        checkItemForExistingAccountRow(1, ACCOUNT_EMAIL2, FULL_NAME2);
+        checkItemForExistingAccountRow(0, TestAccounts.ACCOUNT1);
+        checkItemForExistingAccountRow(1, TestAccounts.ACCOUNT2);
         checkItemForAddAccountRow(2);
     }
 
     @Test
     public void testProfileDataUpdateWhenAccountPickerIsShownFromSettings() {
-        mAccountManagerTestRule.addAccount(ACCOUNT_EMAIL1, FULL_NAME1, null, null);
-        mAccountManagerTestRule.addAccount(ACCOUNT_EMAIL2, FULL_NAME2, null, null);
+        mAccountManagerTestRule.addAccount(TestAccounts.ACCOUNT1);
         mMediator =
                 new AccountPickerMediator(
-                        RuntimeEnvironment.application, mModelList, mListenerMock);
-        String newFullName2 = "Full Name2";
-        mAccountManagerTestRule.addAccount(ACCOUNT_EMAIL2, newFullName2, "", null);
-        // ACCOUNT_NAME1, ACCOUNT_NAME2, ADD_ACCOUNT
-        Assert.assertEquals(3, mModelList.size());
-        checkItemForExistingAccountRow(0, ACCOUNT_EMAIL1, FULL_NAME1);
-        checkItemForExistingAccountRow(1, ACCOUNT_EMAIL2, newFullName2);
-        checkItemForAddAccountRow(2);
+                        RuntimeEnvironment.getApplication(), mModelList, mListenerMock);
+        mAccountManagerTestRule.addAccount(ACCOUNT1_DIFFERENT_NAME);
+        // ACCOUNT_DIFFERENT_NAME, ADD_ACCOUNT
+        Assert.assertEquals(2, mModelList.size());
+        checkItemForExistingAccountRow(0, ACCOUNT1_DIFFERENT_NAME);
+        checkItemForAddAccountRow(1);
     }
 
-    private void checkItemForExistingAccountRow(
-            int position, String accountEmail, String fullName) {
+    private void checkItemForExistingAccountRow(int position, AccountInfo coreAccountInfo) {
         MVCListAdapter.ListItem item = mModelList.get(position);
         Assert.assertEquals(AccountPickerProperties.ItemType.EXISTING_ACCOUNT_ROW, item.type);
         PropertyModel model = item.model;
         DisplayableProfileData profileData = model.get(ExistingAccountRowProperties.PROFILE_DATA);
-        Assert.assertEquals(accountEmail, profileData.getAccountEmail());
-        Assert.assertEquals(fullName, profileData.getFullName());
+        Assert.assertEquals(coreAccountInfo.getEmail(), profileData.getAccountEmail());
+        Assert.assertEquals(coreAccountInfo.getFullName(), profileData.getFullName());
         Assert.assertNotNull("Profile avatar should not be null!", profileData.getImage());
 
-        model.get(ExistingAccountRowProperties.ON_CLICK_LISTENER).onResult(profileData);
-        verify(mListenerMock).onAccountSelected(accountEmail);
+        model.get(ExistingAccountRowProperties.ON_CLICK_LISTENER).run();
+        verify(mListenerMock).onAccountSelected(coreAccountInfo);
     }
 
     private void checkItemForAddAccountRow(int position) {
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
index b8abb5a..6fa36ead 100644
--- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
+++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
@@ -125,6 +125,31 @@
     }
 
     /**
+     * Returns the background color for the tab grid dialog based on the enabled flag and incognito.
+     *
+     * @param context {@link Context} used to retrieve colors.
+     * @param isIncognito Whether the color is used for incognito mode.
+     * @return The background color.
+     */
+    public static @ColorInt int getTabGridDialogBackgroundColor(
+            Context context, boolean isIncognito) {
+        // TODO(crbug.com/414404094): Add semantic color for incognito.
+        if (useNewGtsSurfaceColor()) {
+            return isIncognito
+                    ? ContextCompat.getColor(context, R.color.gm3_baseline_surface_container_dark)
+                    : SemanticColorUtils.getColorSurfaceContainer(context);
+        }
+        @ColorInt
+        int defaultBackground =
+                ColorUtils.inNightMode(context)
+                        ? SemanticColorUtils.getColorSurfaceContainerLow(context)
+                        : SemanticColorUtils.getColorSurface(context);
+        return isIncognito
+                ? ContextCompat.getColor(context, R.color.gm3_baseline_surface_container_low_dark)
+                : defaultBackground;
+    }
+
+    /**
      * Returns the background color for the card view in grid tab switcher on the enabled flag and
      * incognito.
      *
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java
index e6728e1..49d6ec54 100644
--- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java
+++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java
@@ -134,4 +134,36 @@
                         mContext, R.color.gm3_baseline_surface_container_highest_dark),
                 tabCardViewBackgroundColorIncognito);
     }
+
+    @Test
+    @Features.EnableFeatures({ChromeFeatureList.GRID_TAB_SWITCHER_SURFACE_COLOR_UPDATE})
+    public void testTabGridDialogColors_FlagEnabled() {
+        int gtsBackgroundColor =
+                SurfaceColorUpdateUtils.getTabGridDialogBackgroundColor(
+                        mContext, /* isIncognito= */ false);
+        assertEquals(SemanticColorUtils.getColorSurfaceContainer(mContext), gtsBackgroundColor);
+
+        int gtsBackgroundColorIncognito =
+                SurfaceColorUpdateUtils.getTabGridDialogBackgroundColor(
+                        mContext, /* isIncognito= */ true);
+        assertEquals(
+                ContextCompat.getColor(mContext, R.color.gm3_baseline_surface_container_dark),
+                gtsBackgroundColorIncognito);
+    }
+
+    @Test
+    @Features.DisableFeatures({ChromeFeatureList.GRID_TAB_SWITCHER_SURFACE_COLOR_UPDATE})
+    public void testTabGridDialogColors_FlagDisabled() {
+        int gtsBackgroundColor =
+                SurfaceColorUpdateUtils.getTabGridDialogBackgroundColor(
+                        mContext, /* isIncognito= */ false);
+        assertEquals(SemanticColorUtils.getColorSurface(mContext), gtsBackgroundColor);
+
+        int gtsBackgroundColorIncognito =
+                SurfaceColorUpdateUtils.getTabGridDialogBackgroundColor(
+                        mContext, /* isIncognito= */ true);
+        assertEquals(
+                ContextCompat.getColor(mContext, R.color.gm3_baseline_surface_container_low_dark),
+                gtsBackgroundColorIncognito);
+    }
 }
diff --git a/chrome/browser/ui/ash/capture_mode/search_results_view.cc b/chrome/browser/ui/ash/capture_mode/search_results_view.cc
index 2f3e99e8..d7fbdef9 100644
--- a/chrome/browser/ui/ash/capture_mode/search_results_view.cc
+++ b/chrome/browser/ui/ash/capture_mode/search_results_view.cc
@@ -85,6 +85,7 @@
 }
 
 bool SearchResultsView::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/chrome/browser/ui/ash/capture_mode/search_results_view.h b/chrome/browser/ui/ash/capture_mode/search_results_view.h
index de3968f..b7bcbac 100644
--- a/chrome/browser/ui/ash/capture_mode/search_results_view.h
+++ b/chrome/browser/ui/ash/capture_mode/search_results_view.h
@@ -29,6 +29,7 @@
       base::OnceCallback<void(content::NavigationHandle&)>
           navigation_handle_callback) override;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
index a0c24e0..a17c406 100644
--- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
+++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
@@ -76,6 +76,7 @@
   }
 
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc b/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc
index 44be635..08c84ca 100644
--- a/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc
+++ b/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc
@@ -117,6 +117,7 @@
 }
 
 bool AshWebViewImpl::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
@@ -129,8 +130,8 @@
     return true;
   }
   return content::WebContentsDelegate::IsWebContentsCreationOverridden(
-      source_site_instance, window_container_type, opener_url, frame_name,
-      target_url);
+      opener, source_site_instance, window_container_type, opener_url,
+      frame_name, target_url);
 }
 
 content::WebContents* AshWebViewImpl::OpenURLFromTab(
diff --git a/chrome/browser/ui/ash/web_view/ash_web_view_impl.h b/chrome/browser/ui/ash/web_view/ash_web_view_impl.h
index 4fd8dff1..b6582b40 100644
--- a/chrome/browser/ui/ash/web_view/ash_web_view_impl.h
+++ b/chrome/browser/ui/ash/web_view/ash_web_view_impl.h
@@ -56,6 +56,7 @@
 
   // content::WebContentsDelegate:
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/ui/autofill/BUILD.gn b/chrome/browser/ui/autofill/BUILD.gn
index aee50dda..2d8dedc 100644
--- a/chrome/browser/ui/autofill/BUILD.gn
+++ b/chrome/browser/ui/autofill/BUILD.gn
@@ -30,10 +30,12 @@
   public_deps = [
     "//base",
     "//base:i18n",
+    "//chrome/browser:global_features",
     "//chrome/browser/picture_in_picture",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui/autofill/payments",
     "//chrome/browser/ui/page_action:icon_type",
+    "//components/application_locale_storage:application_locale_storage",
     "//components/autofill/content/browser",
     "//components/autofill/core/browser",
     "//components/autofill/core/common",
diff --git a/chrome/browser/ui/autofill/address_bubbles_controller.cc b/chrome/browser/ui/autofill/address_bubbles_controller.cc
index 3bb9603..b695bbd 100644
--- a/chrome/browser/ui/autofill/address_bubbles_controller.cc
+++ b/chrome/browser/ui/autofill/address_bubbles_controller.cc
@@ -16,6 +16,7 @@
 #include "base/types/optional_util.h"
 #include "chrome/browser/autofill/ui/ui_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/global_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/promos/promos_types.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -30,6 +31,7 @@
 #include "chrome/browser/ui/promos/ios_promos_utils.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/grit/theme_resources.h"
+#include "components/application_locale_storage/application_locale_storage.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
 #include "components/autofill/core/browser/field_types.h"
@@ -92,7 +94,9 @@
     content::WebContents* web_contents)
     : AutofillBubbleControllerBase(web_contents),
       content::WebContentsUserData<AddressBubblesController>(*web_contents),
-      app_locale_(g_browser_process->GetApplicationLocale()) {}
+      app_locale_(g_browser_process->GetFeatures()
+                      ->application_locale_storage()
+                      ->Get()) {}
 
 AddressBubblesController::~AddressBubblesController() {
   // `address_profile_save_prompt_callback_` must have been invoked before
diff --git a/chrome/browser/ui/autofill/address_bubbles_controller_unittest.cc b/chrome/browser/ui/autofill/address_bubbles_controller_unittest.cc
index 082cf6f..cd643cb 100644
--- a/chrome/browser/ui/autofill/address_bubbles_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/address_bubbles_controller_unittest.cc
@@ -12,8 +12,10 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/autofill/ui/ui_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/global_features.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
+#include "components/application_locale_storage/application_locale_storage.h"
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
@@ -49,7 +51,9 @@
   }
 
   const std::string& app_locale() const {
-    return g_browser_process->GetApplicationLocale();
+    return g_browser_process->GetFeatures()
+        ->application_locale_storage()
+        ->Get();
   }
 };
 
diff --git a/chrome/browser/ui/autofill/address_editor_controller.cc b/chrome/browser/ui/autofill/address_editor_controller.cc
index 9de0ef5..702174a 100644
--- a/chrome/browser/ui/autofill/address_editor_controller.cc
+++ b/chrome/browser/ui/autofill/address_editor_controller.cc
@@ -13,8 +13,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/global_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/application_locale_storage/application_locale_storage.h"
 #include "components/autofill/core/browser/country_type.h"
 #include "components/autofill/core/browser/data_manager/addresses/address_data_manager.h"
 #include "components/autofill/core/browser/data_manager/personal_data_manager.h"
@@ -34,7 +36,9 @@
     bool is_validatable)
     : profile_to_edit_(profile_to_edit),
       pdm_(*pdm),
-      locale_(g_browser_process->GetApplicationLocale()),
+      locale_(g_browser_process->GetFeatures()
+                  ->application_locale_storage()
+                  ->Get()),
       is_validatable_(is_validatable) {
   const variations::VariationsService* variations_service =
       g_browser_process->variations_service();
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 357bf12..5126b61a 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/autofill/valuables_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/device_reauth/chrome_device_authenticator_factory.h"
+#include "chrome/browser/global_features.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
 #include "chrome/browser/metrics/variations/google_groups_manager_factory.h"
@@ -68,6 +69,7 @@
 #include "chrome/common/channel_info.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
+#include "components/application_locale_storage/application_locale_storage.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/content/browser/content_identity_credential_delegate.h"
@@ -371,7 +373,7 @@
 }
 
 const std::string& ChromeAutofillClient::GetAppLocale() const {
-  return g_browser_process->GetApplicationLocale();
+  return g_browser_process->GetFeatures()->application_locale_storage()->Get();
 }
 
 version_info::Channel ChromeAutofillClient::GetChannel() const {
diff --git a/chrome/browser/ui/autofill/risk_util.cc b/chrome/browser/ui/autofill/risk_util.cc
index abfe45b..32646606 100644
--- a/chrome/browser/ui/autofill/risk_util.cc
+++ b/chrome/browser/ui/autofill/risk_util.cc
@@ -14,8 +14,10 @@
 #include "build/build_config.h"
 #include "chrome/browser/apps/platform_apps/app_window_registry_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/global_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
+#include "components/application_locale_storage/application_locale_storage.h"
 #include "components/autofill/content/browser/risk/fingerprint.h"
 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
 #include "components/embedder_support/user_agent_utils.h"
@@ -101,12 +103,13 @@
       g_browser_process->local_state()->GetInt64(metrics::prefs::kInstallDate));
 
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  risk::GetFingerprint(obfuscated_gaia_id, window_bounds, web_contents,
-                       std::string(version_info::GetVersionNumber()), charset,
-                       accept_languages, install_time,
-                       g_browser_process->GetApplicationLocale(),
-                       embedder_support::GetUserAgent(),
-                       base::BindOnce(PassRiskData, std::move(callback)));
+  risk::GetFingerprint(
+      obfuscated_gaia_id, window_bounds, web_contents,
+      std::string(version_info::GetVersionNumber()), charset, accept_languages,
+      install_time,
+      g_browser_process->GetFeatures()->application_locale_storage()->Get(),
+      embedder_support::GetUserAgent(),
+      base::BindOnce(PassRiskData, std::move(callback)));
 }
 
 }  // namespace autofill::risk_util
diff --git a/chrome/browser/ui/autofill/save_address_bubble_controller.cc b/chrome/browser/ui/autofill/save_address_bubble_controller.cc
index a6b1944..bb7c722 100644
--- a/chrome/browser/ui/autofill/save_address_bubble_controller.cc
+++ b/chrome/browser/ui/autofill/save_address_bubble_controller.cc
@@ -13,7 +13,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autofill/ui/ui_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/global_features.h"
 #include "chrome/grit/theme_resources.h"
+#include "components/application_locale_storage/application_locale_storage.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
 #include "components/autofill/core/browser/data_manager/personal_data_manager.h"
 #include "components/autofill/core/browser/ui/addresses/autofill_address_util.h"
@@ -176,8 +178,10 @@
         NAME_FULL, ADDRESS_HOME_LINE1, EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER};
     std::vector<std::u16string> values;
     for (FieldType field : fields) {
-      std::u16string value = address_profile_.GetInfo(
-          field, g_browser_process->GetApplicationLocale());
+      std::u16string value =
+          address_profile_.GetInfo(field, g_browser_process->GetFeatures()
+                                              ->application_locale_storage()
+                                              ->Get());
       if (!value.empty()) {
         values.push_back(value);
       }
@@ -189,7 +193,8 @@
   }
 
   return GetEnvelopeStyleAddress(
-      address_profile_, g_browser_process->GetApplicationLocale(),
+      address_profile_,
+      g_browser_process->GetFeatures()->application_locale_storage()->Get(),
       /*include_recipient=*/true, /*include_country=*/true);
 }
 
@@ -200,8 +205,9 @@
     return {};
   }
 
-  return address_profile_.GetInfo(EMAIL_ADDRESS,
-                                  g_browser_process->GetApplicationLocale());
+  return address_profile_.GetInfo(
+      EMAIL_ADDRESS,
+      g_browser_process->GetFeatures()->application_locale_storage()->Get());
 }
 
 std::u16string SaveAddressBubbleController::GetProfilePhone() const {
@@ -211,8 +217,9 @@
     return {};
   }
 
-  return address_profile_.GetInfo(PHONE_HOME_WHOLE_NUMBER,
-                                  g_browser_process->GetApplicationLocale());
+  return address_profile_.GetInfo(
+      PHONE_HOME_WHOLE_NUMBER,
+      g_browser_process->GetFeatures()->application_locale_storage()->Get());
 }
 
 std::u16string SaveAddressBubbleController::GetOkButtonLabel() const {
diff --git a/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc b/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc
index a19e093..30db0e6 100644
--- a/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc
@@ -11,9 +11,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autofill/ui/ui_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/global_features.h"
 #include "chrome/browser/ui/autofill/address_bubble_controller_delegate.h"
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/application_locale_storage/application_locale_storage.h"
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile_test_api.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
 #include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
@@ -83,7 +85,9 @@
   content::WebContents* web_contents() { return web_contents_.get(); }
 
   const std::string& app_locale() const {
-    return g_browser_process->GetApplicationLocale();
+    return g_browser_process->GetFeatures()
+        ->application_locale_storage()
+        ->Get();
   }
 
  private:
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index de3f9f5..1dbef7a2 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2324,6 +2324,7 @@
 }
 
 bool Browser::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 0bcb2fc..ab7fb40 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -1024,6 +1024,7 @@
   bool ShouldFocusPageAfterCrash(content::WebContents* source) override;
   void ShowRepostFormWarningDialog(content::WebContents* source) override;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/ui/browser_command_controller_browsertest.cc b/chrome/browser/ui/browser_command_controller_browsertest.cc
index 85c3b488..9a64d235 100644
--- a/chrome/browser/ui/browser_command_controller_browsertest.cc
+++ b/chrome/browser/ui/browser_command_controller_browsertest.cc
@@ -690,47 +690,19 @@
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_GLIC_TOGGLE_PIN));
 }
 
-// TODO(https://crbug.com/410751413): Deleting temporary directories using
-// test_file_util is flaky on Windows.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_DisabledInIncognitoProfile DISABLED_DisabledInIncognitoProfile
-#else
-#define MAYBE_DisabledInIncognitoProfile DisabledInIncognitoProfile
-#endif
 IN_PROC_BROWSER_TEST_F(BrowserCommandControllerBrowserTestGlic,
-                       MAYBE_DisabledInIncognitoProfile) {
-  // Set up a profile with an off the record profile.
-  std::unique_ptr<TestingProfile> profile = TestingProfile::Builder().Build();
-  Profile* incognito_profile =
-      profile->GetPrimaryOTRProfile(/*create_if_needed=*/true);
-  ASSERT_EQ(incognito_profile->GetOriginalProfile(), profile.get());
-  ASSERT_TRUE(incognito_profile->IsIncognitoProfile());
-
-  // Create a new browser based on the off the record profile.
-  Browser::CreateParams profile_params(incognito_profile, true);
-  std::unique_ptr<Browser> incognito_browser =
-      CreateBrowserWithTestWindowForParams(profile_params);
-
+                       DisabledInIncognitoProfile) {
+  Browser* incognito_browser = CreateIncognitoBrowser();
+  EXPECT_TRUE(incognito_browser->profile()->IsIncognitoProfile());
   EXPECT_FALSE(
-      chrome::IsCommandEnabled(incognito_browser.get(), IDC_GLIC_TOGGLE_PIN));
+      chrome::IsCommandEnabled(incognito_browser, IDC_GLIC_TOGGLE_PIN));
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserCommandControllerBrowserTestGlic,
                        DisabledInGuestProfile) {
-  // Set up a guest profile.
-  std::unique_ptr<TestingProfile> profile = TestingProfile::Builder().Build();
-  profile->SetGuestSession(true);
-  Profile* guest_profile =
-      profile->GetPrimaryOTRProfile(/*create_if_needed=*/true);
-  ASSERT_TRUE(guest_profile->IsGuestSession());
-
-  // Create a new browser based on the off the record profile.
-  Browser::CreateParams profile_params(guest_profile, true);
-  std::unique_ptr<Browser> guest_browser =
-      CreateBrowserWithTestWindowForParams(profile_params);
-
-  EXPECT_FALSE(
-      chrome::IsCommandEnabled(guest_browser.get(), IDC_GLIC_TOGGLE_PIN));
+  Browser* guest_browser = CreateGuestBrowser();
+  EXPECT_TRUE(guest_browser->profile()->IsGuestSession());
+  EXPECT_FALSE(chrome::IsCommandEnabled(guest_browser, IDC_GLIC_TOGGLE_PIN));
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserCommandControllerBrowserTestGlic,
@@ -755,6 +727,6 @@
       glic::GlicKeyedServiceFactory::GetGlicKeyedService(browser()->profile())
           ->IsWindowShowing());
 }
-#endif
+#endif  // BUILDFLAG(ENABLE_GLIC)
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc
index 73e9e6c..5b33e17 100644
--- a/chrome/browser/ui/browser_tabrestore.cc
+++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tab_ui_helper.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"
@@ -75,7 +76,13 @@
       WebContents::CreateWithSessionStorage(create_params,
                                             session_storage_namespace_map);
   if (from_session_restore) {
-    SessionRestore::OnWillRestoreTab(web_contents.get());
+    // Indicate that the tab is created by session restore. This is used to hide
+    // the throbber when a background restored tab is loading. TabUIHelper is
+    // created by TabHelpers::AttachTabHelpers, but this happens later, so we
+    // explicitly create it early here.
+    TabUIHelper::CreateForWebContents(web_contents.get());
+    TabUIHelper::FromWebContents(web_contents.get())
+        ->set_created_by_session_restore(true);
   }
   apps::SetAppIdForWebContents(browser->profile(), web_contents.get(),
                                extension_app_id);
diff --git a/chrome/browser/ui/browser_window/browser_window_features.cc b/chrome/browser/ui/browser_window/browser_window_features.cc
index 6e462c0..2d59c0c 100644
--- a/chrome/browser/ui/browser_window/browser_window_features.cc
+++ b/chrome/browser/ui/browser_window/browser_window_features.cc
@@ -332,6 +332,10 @@
   glic_button_controller_.reset();
 #endif
 
+  if (download_toolbar_ui_controller_) {
+    download_toolbar_ui_controller_->TearDownPreBrowserViewDestruction();
+  }
+
   // TODO(crbug.com/346148093): This logic should not be gated behind a
   // conditional.
   if (side_panel_coordinator_) {
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index 5f3dfaf..d16ad26 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -444,6 +444,11 @@
 #else
             ctrl_key = blink::WebInputEvent::Modifiers::kControlKey;
 #endif
+
+            // Before sending a click, end paint-holding to enable input event
+            // processing.
+            content::SimulateEndOfPaintHoldingOnPrimaryMainFrame(app_contents);
+
             content::SimulateMouseClick(app_contents, ctrl_key,
                                         blink::WebMouseEvent::Button::kLeft);
             url_observer.Wait();
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.cc b/chrome/browser/ui/lens/lens_overlay_controller.cc
index 05964ca..620e377db 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller.cc
@@ -911,30 +911,9 @@
   return IsUrlEligibleForTutorialIPH(url);
 }
 
-std::unique_ptr<lens::LensOverlayQueryController>
-LensOverlayController::CreateLensQueryController(
-    lens::LensOverlayFullImageResponseCallback full_image_callback,
-    lens::LensOverlayUrlResponseCallback url_callback,
-    lens::LensOverlayInteractionResponseCallback interaction_callback,
-    lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
-    lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
-    lens::UploadProgressCallback upload_progress_callback,
-    variations::VariationsClient* variations_client,
-    signin::IdentityManager* identity_manager,
-    Profile* profile,
-    lens::LensOverlayInvocationSource invocation_source,
-    bool use_dark_mode,
-    lens::LensOverlayGen204Controller* gen204_controller) {
-  return std::make_unique<lens::LensOverlayQueryController>(
-      std::move(full_image_callback), std::move(url_callback),
-      std::move(interaction_callback), std::move(suggest_inputs_callback),
-      std::move(thumbnail_created_callback),
-      std::move(upload_progress_callback), variations_client, identity_manager,
-      profile, invocation_source, use_dark_mode, gen204_controller);
-}
-
 void LensOverlayController::ShowUI(
-    lens::LensOverlayInvocationSource invocation_source) {
+    lens::LensOverlayInvocationSource invocation_source,
+    lens::LensOverlayQueryController* lens_overlay_query_controller) {
   // If UI is already showing or in the process of showing, do nothing.
   if (state_ != State::kOff) {
     return;
@@ -951,8 +930,6 @@
     return;
   }
 
-  invocation_source_ = invocation_source;
-
   // Request user permission before grabbing a screenshot.
   CHECK(pref_service_);
   // If contextual serachbox is enabled, show permission bubble again informing
@@ -969,7 +946,8 @@
     permission_bubble_controller_->RequestPermission(
         tab_->GetContents(),
         base::BindRepeating(&LensOverlayController::ShowUI,
-                            weak_factory_.GetWeakPtr(), invocation_source));
+                            weak_factory_.GetWeakPtr(), invocation_source,
+                            lens_overlay_query_controller));
     return;
   }
 
@@ -980,6 +958,10 @@
   pref_service_->SetInteger(prefs::kLensOverlayStartCount,
                             lens_overlay_start_count + 1);
 
+  // Store reference for later use.
+  invocation_source_ = invocation_source;
+  lens_overlay_query_controller_ = lens_overlay_query_controller;
+
   // Grab reference to the side panel coordinator it not already done so.
   if (!results_side_panel_coordinator_) {
     results_side_panel_coordinator_ =
@@ -988,24 +970,6 @@
 
   Profile* profile =
       Profile::FromBrowserContext(tab_->GetContents()->GetBrowserContext());
-  // Create the query controller.
-  lens_overlay_query_controller_ = CreateLensQueryController(
-      base::BindRepeating(&LensOverlayController::HandleStartQueryResponse,
-                          weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&LensOverlayController::HandleInteractionURLResponse,
-                          weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&LensOverlayController::HandleInteractionResponse,
-                          weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&LensOverlayController::HandleSuggestInputsResponse,
-                          weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&LensOverlayController::HandleThumbnailCreated,
-                          weak_factory_.GetWeakPtr()),
-      base::BindRepeating(
-          &LensOverlayController::HandlePageContentUploadProgress,
-          weak_factory_.GetWeakPtr()),
-      variations_client_, identity_manager_, profile, invocation_source,
-      lens::LensOverlayShouldUseDarkMode(theme_service_),
-      gen204_controller_.get());
   side_panel_coordinator_ =
       tab_->GetBrowserWindowInterface()->GetFeatures().side_panel_coordinator();
   CHECK(side_panel_coordinator_);
@@ -1082,8 +1046,10 @@
 
 void LensOverlayController::IssueContextualSearchRequest(
     const GURL& destination_url,
+    lens::LensOverlayQueryController* lens_overlay_query_controller,
     AutocompleteMatchType::Type match_type,
-    bool is_zero_prefix_suggestion) {
+    bool is_zero_prefix_suggestion,
+    lens::LensOverlayInvocationSource invocation_source) {
   // Ignore the request if the overlay is off or closing.
   if (IsOverlayClosing()) {
     return;
@@ -1091,24 +1057,22 @@
 
   // If the overlay is off, turn it on so the request can be fulfilled.
   if (state_ == State::kOff) {
-    // TODO(crbug.com/402497756): For prototyping, reusing the existing
-    // omnibox entry point. However, for production, create a new invocation
-    // source for this new entry point.
     // TODO(crbug.com/403573362): This is a temporary fix to unblock
     // prototyping. Since this flow goes straight to the side panel results with
     // not overlay UI, this flow does a lot of unnecessary work. There should be
     // a new flow that can contextualize without the overlay UI being
     // initialized.
-    StartContextualizationWithoutOverlay(
-        lens::LensOverlayInvocationSource::kOmnibox);
+    StartContextualizationWithoutOverlay(invocation_source,
+                                         lens_overlay_query_controller);
   }
 
   // Hold the request until the overlay has finished initializing.
   if (IsOverlayInitializing()) {
     pending_contextual_search_request_ =
         base::BindOnce(&LensOverlayController::IssueContextualSearchRequest,
-                       weak_factory_.GetWeakPtr(), destination_url, match_type,
-                       is_zero_prefix_suggestion);
+                       weak_factory_.GetWeakPtr(), destination_url,
+                       lens_overlay_query_controller, match_type,
+                       is_zero_prefix_suggestion, invocation_source);
     return;
   }
 
@@ -1119,18 +1083,20 @@
 }
 
 void LensOverlayController::StartContextualizationWithoutOverlay(
-    lens::LensOverlayInvocationSource invocation_source) {
+    lens::LensOverlayInvocationSource invocation_source,
+    lens::LensOverlayQueryController* lens_overlay_query_controller) {
   should_show_overlay_ = false;
-  ShowUI(invocation_source);
+  ShowUI(invocation_source, lens_overlay_query_controller);
 }
 
 void LensOverlayController::ShowUIWithPendingRegion(
+    lens::LensOverlayQueryController* lens_overlay_query_controller,
     lens::LensOverlayInvocationSource invocation_source,
     lens::mojom::CenterRotatedBoxPtr region,
     const SkBitmap& region_bitmap) {
   pending_region_ = std::move(region);
   pending_region_bitmap_ = region_bitmap;
-  ShowUI(invocation_source);
+  ShowUI(invocation_source, lens_overlay_query_controller);
   // Overrides value set in ShowUI since invoking lens overlay with a pending
   // region is considered a search.
   search_performed_in_session_ = true;
@@ -2202,6 +2168,11 @@
   // Closes preselection toast if it exists.
   ClosePreselectionBubble();
 
+  // Notify the query controller to loose references to this classes data before
+  // it gets cleaned up to prevent dangling ptrs.
+  lens_overlay_query_controller_->ResetPageContentData();
+  lens_overlay_query_controller_ = nullptr;
+
   // A permission prompt may be suspended if the overlay was showing when the
   // permission was queued. Restore the suspended prompt if possible.
   // TODO(b/331940245): Refactor to be decoupled from PermissionPromptFactory
@@ -2238,9 +2209,6 @@
         ->RemoveObserver(this);
   }
 
-  // LensOverlayQueryController points to initialization data and therefore must
-  // be reset before the initialization data to avoid dangling pointers.
-  lens_overlay_query_controller_.reset();
   initialization_data_.reset();
 
   tab_contents_view_observer_.Reset();
@@ -2281,6 +2249,10 @@
 
   state_ = State::kOff;
 
+  // TODO(crbug.com/404941800): Make a more generalized solution once multiple
+  // async features are cleaning up at the same time.
+  lens_search_controller_->CloseLensPart2();
+
   // Update the entrypoints now that the controller is closed.
   UpdateEntryPointsState();
 
@@ -2374,6 +2346,7 @@
   }
 
   state_ = State::kOverlay;
+  lens_search_controller_->NotifyOverlayOpened();
 
   // Update the entry points state to ensure that the entry points are disabled
   // now that the overlay is showing.
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.h b/chrome/browser/ui/lens/lens_overlay_controller.h
index c56b694..01faf49 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller.h
+++ b/chrome/browser/ui/lens/lens_overlay_controller.h
@@ -518,27 +518,12 @@
   friend class LensSearchController;
   friend class lens::LensOverlaySidePanelCoordinator;
 
-  // Override these methods to stub out network requests for testing.
-  virtual std::unique_ptr<lens::LensOverlayQueryController>
-  CreateLensQueryController(
-      lens::LensOverlayFullImageResponseCallback full_image_callback,
-      lens::LensOverlayUrlResponseCallback url_callback,
-      lens::LensOverlayInteractionResponseCallback interaction_callback,
-      lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
-      lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
-      lens::UploadProgressCallback upload_progress_callback,
-      variations::VariationsClient* variations_client,
-      signin::IdentityManager* identity_manager,
-      Profile* profile,
-      lens::LensOverlayInvocationSource invocation_source,
-      bool use_dark_mode,
-      lens::LensOverlayGen204Controller* gen204_controller);
-
   // This is entry point for showing the overlay UI. This has no effect if state
   // is not kOff. This has no effect if the tab is not in the foreground. If the
   // overlay is successfully invoked, then the value of `invocation_source` will
   // be recorded in the relevant metrics.
-  void ShowUI(lens::LensOverlayInvocationSource invocation_source);
+  void ShowUI(lens::LensOverlayInvocationSource invocation_sourc,
+              lens::LensOverlayQueryController* lens_overlay_query_controller);
 
   // Issues a contextual search request for Lens to fulfill.
   // No-op if the Lens Overlay is off or closing. If the Lens Overlay is in the
@@ -546,26 +531,32 @@
   // opened.
   // TODO(crbug.com/403629222): Revisit if it makes sense to pass the
   // destination URL instead of the query text directly.
-  void IssueContextualSearchRequest(const GURL& destination_url,
-                                    AutocompleteMatchType::Type match_type,
-                                    bool is_zero_prefix_suggestion);
+  void IssueContextualSearchRequest(
+      const GURL& destination_url,
+      lens::LensOverlayQueryController* lens_overlay_query_controller,
+      AutocompleteMatchType::Type match_type,
+      bool is_zero_prefix_suggestion,
+      lens::LensOverlayInvocationSource invocation_source);
 
   // Starts the contextualization flow without the overlay being shown to the
   // user.
   // TODO(crbug.com/404941800): This still goes through the entire
-  // initialization flow for the overlay. This is not efficeient, but is being
+  // TODO(crbug.com/404941800): This still goes through the entire
+  // initialization flow for the overlay. This is not efficient, but is being
   // done to unblock the contextual searchbox prototype. This should be
   // refactored to be done in the LensSearchController to not go through the
   // overlay controller.
   // Virtual for testing.
   virtual void StartContextualizationWithoutOverlay(
-      lens::LensOverlayInvocationSource invocation_source);
+      lens::LensOverlayInvocationSource invocation_source,
+      lens::LensOverlayQueryController* lens_overlay_query_controller);
 
   // Sets a region to search after the overlay loads, then calls ShowUI().
   // All units are in device pixels. region_bitmap contains the high definition
   // image bytes to use for the search instead of cropping the region from the
   // viewport.
   void ShowUIWithPendingRegion(
+      lens::LensOverlayQueryController* lens_overlay_query_controller,
       lens::LensOverlayInvocationSource invocation_source,
       lens::mojom::CenterRotatedBoxPtr region,
       const SkBitmap& region_bitmap);
@@ -638,6 +629,35 @@
   // Returns a search query struct containing the current state of the overlay.
   void AddOverlayStateToSearchQuery(lens::SearchQuery& search_query);
 
+  // TODO(crbug.com/404941800): All the Handle*Response methods should not exist
+  // in this class. They currently exist to unblock development. They will be
+  // removed once the migration is complete. Handles the response to the Lens
+  // start query request.
+  void HandleStartQueryResponse(
+      std::vector<lens::mojom::OverlayObjectPtr> objects,
+      lens::mojom::TextPtr text,
+      bool is_error);
+
+  // Handles the URL response to the Lens interaction request.
+  void HandleInteractionURLResponse(
+      lens::proto::LensOverlayUrlResponse response);
+
+  // Handles the text response to the Lens interaction request.
+  void HandleInteractionResponse(lens::mojom::TextPtr text);
+
+  // Handles an update to the suggest inputs. This will be called whenever
+  // any part of the suggest inputs changes, such as when a new objects
+  // request is sent, or when an interaction data response is received.
+  void HandleSuggestInputsResponse(
+      lens::proto::LensOverlaySuggestInputs suggest_inputs);
+
+  // Handles the progress of the page content upload. Notifies the side panel
+  // to update the progress bar.
+  void HandlePageContentUploadProgress(uint64_t position, uint64_t total);
+
+  // Handles the creation of a new thumbnail based on the user selection.
+  void HandleThumbnailCreated(const std::string& thumbnail_bytes);
+
  private:
   // Data class for constructing overlay and storing overlay state for
   // kSuspended state.
@@ -1118,32 +1138,6 @@
       bool is_zero_prefix_suggestion,
       std::map<std::string, std::string> additional_query_params);
 
-  // Handles the response to the Lens start query request.
-  void HandleStartQueryResponse(
-      std::vector<lens::mojom::OverlayObjectPtr> objects,
-      lens::mojom::TextPtr text,
-      bool is_error);
-
-  // Handles the URL response to the Lens interaction request.
-  void HandleInteractionURLResponse(
-      lens::proto::LensOverlayUrlResponse response);
-
-  // Handles the text response to the Lens interaction request.
-  void HandleInteractionResponse(lens::mojom::TextPtr text);
-
-  // Handles an update to the suggest inputs. This will be called whenever
-  // any part of the suggest inputs changes, such as when a new objects
-  // request is sent, or when an interaction data response is received.
-  void HandleSuggestInputsResponse(
-      lens::proto::LensOverlaySuggestInputs suggest_inputs);
-
-  // Handles the progress of the page content upload. Notifies the side panel
-  // to update the progress bar.
-  void HandlePageContentUploadProgress(uint64_t position, uint64_t total);
-
-  // Handles the creation of a new thumbnail based on the user selection.
-  void HandleThumbnailCreated(const std::string& thumbnail_bytes);
-
   // Records UMA and UKM metrics for time to first interaction. Not recorded
   // when invocation source is an image's content area menu because in this
   // case the time to first interaction is essentially zero.
@@ -1292,9 +1286,9 @@
   // overlay view is showing.
   std::unique_ptr<UnderlyingWebContentsObserver> tab_contents_observer_;
 
-  // Query controller.
-  std::unique_ptr<lens::LensOverlayQueryController>
-      lens_overlay_query_controller_;
+  // Query controller. Owned by the search controller, guaranteed to be alive
+  // until the overlay is closed.
+  raw_ptr<lens::LensOverlayQueryController> lens_overlay_query_controller_;
 
   // Holds subscriptions for TabInterface callbacks.
   std::vector<base::CallbackListSubscription> tab_subscriptions_;
diff --git a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
index 3da7734..6c10e622 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
@@ -528,6 +528,74 @@
                                         sync_service,
                                         theme_service) {}
 
+  void BindOverlay(mojo::PendingReceiver<lens::mojom::LensPageHandler> receiver,
+                   mojo::PendingRemote<lens::mojom::LensPage> page) override {
+    // Reset the receiver to close any existing connection.
+    fake_overlay_page_receiver_.reset();
+    fake_overlay_page_.overlay_page_.reset();
+
+    // Set up the fake overlay page to intercept the mojo call.
+    fake_overlay_page_.overlay_page_.Bind(std::move(page));
+    LensOverlayController::BindOverlay(
+        std::move(receiver),
+        fake_overlay_page_receiver_.BindNewPipeAndPassRemote());
+  }
+
+  bool IsScreenshotPossible(content::RenderWidgetHostView*) override {
+    return is_screenshot_possible_;
+  }
+
+  void FlushForTesting() { fake_overlay_page_receiver_.FlushForTesting(); }
+
+  LensOverlayPageFake fake_overlay_page_;
+  bool is_screenshot_possible_ = true;
+  mojo::Receiver<lens::mojom::LensPage> fake_overlay_page_receiver_{
+      &fake_overlay_page_};
+};
+
+class LensSearchControllerFake : public lens::TestLensSearchController {
+ public:
+  explicit LensSearchControllerFake(tabs::TabInterface* tab)
+      : lens::TestLensSearchController(tab) {}
+
+  ~LensSearchControllerFake() override { ResetPageContextEligibilityAPI(); }
+
+  // Sets the context eligibility of the page and creates the new API.
+  void SetContextEligible(bool eligible) {
+    is_context_eligible_ = eligible;
+    CreatePageContextEligibilityAPI();
+  }
+
+  // Helper function to force the fake query controller to return errors in its
+  // responses to full image requests. This should be called before ShowUI.
+  void SetFullImageRequestShouldReturnError() {
+    full_image_request_should_return_error_ = true;
+  }
+
+  void SetOcrResponseWords(const std::vector<std::string>& words) {
+    ocr_response_words_ = words;
+  }
+
+  std::string GetLastSearchUrl() { return last_search_url_; }
+
+ protected:
+  std::unique_ptr<LensOverlayController> CreateLensOverlayController(
+      tabs::TabInterface* tab,
+      LensSearchController* lens_search_controller,
+      variations::VariationsClient* variations_client,
+      signin::IdentityManager* identity_manager,
+      PrefService* pref_service,
+      syncer::SyncService* sync_service,
+      ThemeService* theme_service) override {
+    // Set browser color scheme to light mode for consistency.
+    theme_service->SetBrowserColorScheme(
+        ThemeService::BrowserColorScheme::kLight);
+
+    return std::make_unique<LensOverlayControllerFake>(
+        tab, lens_search_controller, variations_client, identity_manager,
+        pref_service, sync_service, theme_service);
+  }
+
   std::unique_ptr<lens::LensOverlayQueryController> CreateLensQueryController(
       lens::LensOverlayFullImageResponseCallback full_image_callback,
       lens::LensOverlayUrlResponseCallback url_callback,
@@ -546,7 +614,7 @@
         std::make_unique<lens::TestLensOverlayQueryController>(
             full_image_callback,
             base::BindRepeating(
-                &LensOverlayControllerFake::RecordUrlResponseCallback,
+                &LensSearchControllerFake::RecordUrlResponseCallback,
                 base::Unretained(this)),
             interaction_callback, suggest_inputs_callback,
             thumbnail_created_callback, upload_progress_callback,
@@ -571,80 +639,6 @@
     return fake_query_controller;
   }
 
-  void BindOverlay(mojo::PendingReceiver<lens::mojom::LensPageHandler> receiver,
-                   mojo::PendingRemote<lens::mojom::LensPage> page) override {
-    // Reset the receiver to close any existing connection.
-    fake_overlay_page_receiver_.reset();
-    fake_overlay_page_.overlay_page_.reset();
-
-    // Set up the fake overlay page to intercept the mojo call.
-    fake_overlay_page_.overlay_page_.Bind(std::move(page));
-    LensOverlayController::BindOverlay(
-        std::move(receiver),
-        fake_overlay_page_receiver_.BindNewPipeAndPassRemote());
-  }
-
-  bool IsScreenshotPossible(content::RenderWidgetHostView*) override {
-    return is_screenshot_possible_;
-  }
-
-  // Helper function to force the fake query controller to return errors in its
-  // responses to full image requests. This should be called before ShowUI.
-  void SetFullImageRequestShouldReturnError() {
-    full_image_request_should_return_error_ = true;
-  }
-
-  // A url response callback that records the url sent to the callback.
-  void RecordUrlResponseCallback(lens::proto::LensOverlayUrlResponse response) {
-    last_search_url_ = response.url();
-    if (!url_callback_.is_null()) {
-      url_callback_.Run(response);
-    }
-  }
-
-  void FlushForTesting() { fake_overlay_page_receiver_.FlushForTesting(); }
-
-  std::string last_search_url_;
-  std::vector<std::string> ocr_response_words_;
-  LensOverlayPageFake fake_overlay_page_;
-  lens::LensOverlayUrlResponseCallback url_callback_;
-  bool full_image_request_should_return_error_ = false;
-  bool is_screenshot_possible_ = true;
-  mojo::Receiver<lens::mojom::LensPage> fake_overlay_page_receiver_{
-      &fake_overlay_page_};
-};
-
-class LensSearchControllerFake : public lens::TestLensSearchController {
- public:
-  explicit LensSearchControllerFake(tabs::TabInterface* tab)
-      : lens::TestLensSearchController(tab) {}
-
-  ~LensSearchControllerFake() override { ResetPageContextEligibilityAPI(); }
-
-  // Sets the context eligibility of the page and creates the new API.
-  void SetContextEligible(bool eligible) {
-    is_context_eligible_ = eligible;
-    CreatePageContextEligibilityAPI();
-  }
-
- protected:
-  std::unique_ptr<LensOverlayController> CreateLensOverlayController(
-      tabs::TabInterface* tab,
-      LensSearchController* lens_search_controller,
-      variations::VariationsClient* variations_client,
-      signin::IdentityManager* identity_manager,
-      PrefService* pref_service,
-      syncer::SyncService* sync_service,
-      ThemeService* theme_service) override {
-    // Set browser color scheme to light mode for consistency.
-    theme_service->SetBrowserColorScheme(
-        ThemeService::BrowserColorScheme::kLight);
-
-    return std::make_unique<LensOverlayControllerFake>(
-        tab, lens_search_controller, variations_client, identity_manager,
-        pref_service, sync_service, theme_service);
-  }
-
   std::unique_ptr<lens::LensOverlaySidePanelCoordinator>
   CreateLensOverlaySidePanelCoordinator() override {
     return std::make_unique<lens::TestLensOverlaySidePanelCoordinator>(this);
@@ -681,6 +675,18 @@
     page_context_eligibility_api_.reset();
   }
 
+  // A url response callback that records the url sent to the callback.
+  void RecordUrlResponseCallback(lens::proto::LensOverlayUrlResponse response) {
+    last_search_url_ = response.url();
+    if (!url_callback_.is_null()) {
+      url_callback_.Run(response);
+    }
+  }
+
+  std::vector<std::string> ocr_response_words_;
+  std::string last_search_url_;
+  lens::LensOverlayUrlResponseCallback url_callback_;
+  bool full_image_request_should_return_error_ = false;
   bool is_context_eligible_ = true;
   std::unique_ptr<optimization_guide::PageContextEligibilityAPI>
       page_context_eligibility_api_;
@@ -1971,8 +1977,9 @@
   auto* controller = GetLensOverlayController();
   ASSERT_EQ(controller->state(), State::kOff);
 
-  // Set the full image request to return an error.
-  auto* fake_controller = static_cast<LensOverlayControllerFake*>(controller);
+  // Set the full image request to return an error via the search controller.
+  auto* fake_controller =
+      static_cast<LensSearchControllerFake*>(GetLensSearchController());
   ASSERT_TRUE(fake_controller);
   fake_controller->SetFullImageRequestShouldReturnError();
 
@@ -2030,9 +2037,9 @@
   auto* controller = GetLensOverlayController();
   ASSERT_EQ(controller->state(), State::kOff);
 
-  // Set the full image request to return an error.
-  auto* fake_controller = static_cast<LensOverlayControllerFake*>(controller);
-  ASSERT_TRUE(fake_controller);
+  // Set the full image request to return an error via the search controller.
+  auto* fake_controller =
+      static_cast<LensSearchControllerFake*>(GetLensSearchController());
   fake_controller->SetFullImageRequestShouldReturnError();
 
   // Showing UI should change the state to screenshot and eventually to overlay.
@@ -4953,8 +4960,9 @@
   auto* controller = GetLensOverlayController();
   ASSERT_EQ(controller->state(), State::kOff);
 
-  auto* fake_controller = static_cast<LensOverlayControllerFake*>(controller);
-  ASSERT_TRUE(fake_controller);
+  auto* fake_search_controller =
+      static_cast<LensSearchControllerFake*>(GetLensSearchController());
+  ASSERT_TRUE(fake_search_controller);
 
   // Showing UI should change the state to screenshot and eventually to overlay.
   // When the overlay is bound, it should start the query flow which returns a
@@ -5068,8 +5076,8 @@
 
   std::string search_url_vsrid;
   EXPECT_TRUE(net::GetValueForKeyInQuery(
-      GURL(fake_controller->last_search_url_), kLensRequestQueryParameter,
-      &search_url_vsrid));
+      GURL(fake_search_controller->GetLastSearchUrl()),
+      kLensRequestQueryParameter, &search_url_vsrid));
   EXPECT_EQ(EncodeRequestId(
                 fake_query_controller->last_semantic_event_gen204_request_id()
                     .value()),
@@ -6610,9 +6618,10 @@
 
   // Setup fake text in the OCR response. Included 0 words from the DOM to
   // ensure the similarity score is still recorded when its 0.
-  auto* fake_controller = static_cast<LensOverlayControllerFake*>(controller);
-  fake_controller->ocr_response_words_ = {"BLAH.", "   random   - ", " ,no] ",
-                                          "RANDOM", "\n\npuppies.\n"};
+  auto* fake_controller =
+      static_cast<LensSearchControllerFake*>(GetLensSearchController());
+  fake_controller->SetOcrResponseWords(
+      {"BLAH.", "   random   - ", " ,no] ", "RANDOM", "\n\npuppies.\n"});
 
   // Open the overlay.
   OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
@@ -6760,9 +6769,10 @@
   // Setup fake text in the OCR response. Included 4 words on the DOM, and 1
   // not, to make a similarity score of 0.8. Also include some random characters
   // to make sure they are ignored.
-  auto* fake_controller = static_cast<LensOverlayControllerFake*>(controller);
-  fake_controller->ocr_response_words_ = {"The.", "   below   - ", " ,are] ",
-                                          "RANDOM", "\n\n\nCharacters.\n"};
+  auto* fake_controller =
+      static_cast<LensSearchControllerFake*>(GetLensSearchController());
+  fake_controller->SetOcrResponseWords(
+      {"The.", "   below   - ", " ,are] ", "RANDOM", "\n\n\nCharacters.\n"});
 
   // Open the overlay.
   OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
diff --git a/chrome/browser/ui/lens/lens_search_controller.cc b/chrome/browser/ui/lens/lens_search_controller.cc
index 69b0eb6..fce4034 100644
--- a/chrome/browser/ui/lens/lens_search_controller.cc
+++ b/chrome/browser/ui/lens/lens_search_controller.cc
@@ -11,7 +11,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_image_helper.h"
+#include "chrome/browser/ui/lens/lens_overlay_query_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h"
+#include "chrome/browser/ui/lens/lens_overlay_theme_utils.h"
 #include "chrome/browser/ui/lens/lens_searchbox_controller.h"
 #include "chrome/browser/ui/tabs/public/tab_features.h"
 #include "chrome/browser/ui/webui/webui_embedding_context.h"
@@ -33,6 +35,8 @@
     : tab_(tab) {}
 LensSearchController::~LensSearchController() = default;
 
+// TODO(crbug.com/404941800): Reconsider which of these controllers should be
+// created in Initialize() vs created on demand when invoked.
 void LensSearchController::Initialize(
     variations::VariationsClient* variations_client,
     signin::IdentityManager* identity_manager,
@@ -41,6 +45,12 @@
     ThemeService* theme_service) {
   CHECK(!initialized_);
   initialized_ = true;
+  variations_client_ = variations_client;
+  identity_manager_ = identity_manager;
+  theme_service_ = theme_service;
+
+  // Create Gen204 controller first as query controller depends on it.
+  gen204_controller_ = std::make_unique<lens::LensOverlayGen204Controller>();
 
   lens_overlay_controller_ = CreateLensOverlayController(
       tab_, this, variations_client, identity_manager, pref_service,
@@ -70,20 +80,30 @@
 
 void LensSearchController::OpenLensOverlay(
     lens::LensOverlayInvocationSource invocation_source) {
+  CHECK(initialized_)
+      << "The LensSearchController has not been initialized. Initialize() must "
+         "be called before using the LensSearchController.";
+
   // The UI should only show if the tab is in the foreground or if the tab web
   // contents is not in a crash state.
   if (!tab_->IsActivated() || tab_->GetContents()->IsCrashed()) {
     return;
   }
 
+  // Exit early if the Lens feature is already active.
+  if (state() != State::kOff) {
+    return;
+  }
+  state_ = State::kInitializing;
+
+  // Create the query controller to be used for the current invocation.
+  CHECK(!lens_overlay_query_controller_);
+  lens_overlay_query_controller_ = CreateLensQueryController(invocation_source);
+
   // TODO(crbug.com/404941800): Add logic based on this classes state once the
   // state machine is available.
-  lens_overlay_controller_->ShowUI(invocation_source);
-
-  // TODO(crbug.com/404941800): This state should start with kInitializing and
-  // then move to kActive once the overlay is fully initialized. Setting
-  // straight to kActive for now to unblock development.
-  state_ = State::kActive;
+  lens_overlay_controller_->ShowUI(invocation_source,
+                                   lens_overlay_query_controller_.get());
 }
 
 void LensSearchController::OpenLensOverlayWithPendingRegion(
@@ -109,15 +129,21 @@
     return;
   }
 
+  // Exit early if the Lens feature is already active.
+  if (state() != State::kOff) {
+    return;
+  }
+  state_ = State::kInitializing;
+
+  // Create the query controller to be used for the current invocation.
+  CHECK(!lens_overlay_query_controller_);
+  lens_overlay_query_controller_ = CreateLensQueryController(invocation_source);
+
   // TODO(crbug.com/404941800): Add logic based on this classes state once the
   // state machine is available.
   lens_overlay_controller_->ShowUIWithPendingRegion(
-      invocation_source, std::move(region), region_bitmap);
-
-  // TODO(crbug.com/404941800): This state should start with kInitializing and
-  // then move to kActive once the overlay is fully initialized. Setting
-  // straight to kActive for now to unblock development.
-  state_ = State::kActive;
+      lens_overlay_query_controller_.get(), invocation_source,
+      std::move(region), region_bitmap);
 }
 
 void LensSearchController::StartContextualization(
@@ -128,17 +154,22 @@
     return;
   }
 
+  // Exit early if the Lens feature is already active.
+  if (state() != State::kOff) {
+    return;
+  }
+  state_ = State::kInitializing;
+
+  // Create the query controller to be used for the current invocation.
+  CHECK(!lens_overlay_query_controller_);
+  lens_overlay_query_controller_ = CreateLensQueryController(invocation_source);
+
   // TODO(crbug.com/404941800): Add logic based on this classes state once the
   // state machine is available.
   // TODO(crbug.com/404941800): This flow should not start the overlay once
   // contextualization is separated from the overlay.
   lens_overlay_controller_->StartContextualizationWithoutOverlay(
-      invocation_source);
-
-  // TODO(crbug.com/404941800): This state should start with kInitializing and
-  // then move to kActive once the overlay is fully initialized. Setting
-  // straight to kActive for now to unblock development.
-  state_ = State::kActive;
+      invocation_source, lens_overlay_query_controller_.get());
 }
 
 void LensSearchController::IssueContextualSearchRequest(
@@ -151,30 +182,64 @@
     return;
   }
 
+  // Exit early if the Lens feature is already active.
+  if (state() != State::kOff) {
+    return;
+  }
+  state_ = State::kInitializing;
+
+  // TODO(crbug.com/402497756): For prototyping, reusing the existing
+  // omnibox entry point. However, for production, create a new invocation
+  // source for this new entry point.
+  lens::LensOverlayInvocationSource invocation_source =
+      lens::LensOverlayInvocationSource::kOmnibox;
+
+  // Create the query controller to be used for the current invocation.
+  CHECK(!lens_overlay_query_controller_);
+  lens_overlay_query_controller_ = CreateLensQueryController(invocation_source);
+
   // TODO(crbug.com/404941800): This flow should not start the overlay once
   // contextualization is separated from the overlay.
   lens_overlay_controller_->IssueContextualSearchRequest(
-      destination_url, match_type, is_zero_prefix_suggestion);
-
-  // TODO(crbug.com/404941800): This state should start with kInitializing and
-  // then move to kActive once the overlay is fully initialized. Setting
-  // straight to kActive for now to unblock development.
-  state_ = State::kActive;
+      destination_url, lens_overlay_query_controller_.get(), match_type,
+      is_zero_prefix_suggestion, invocation_source);
 }
 
 void LensSearchController::CloseLensAsync(
     lens::LensOverlayDismissalSource dismissal_source) {
-  lens_overlay_controller_->CloseUIAsync(dismissal_source);
-  // TODO(crbug.com/404941800): This state should start with kClosing and
-  // then move to kOff once all Lens feature have finished closing. Setting
-  // straight to kOff for now to unblock development.
-  state_ = State::kOff;
+  if (state() == State::kOff) {
+    return;
+  }
+  state_ = State::kClosing;
+
+  // The overlay controller must be closed before the query controller so it
+  // doesn't hold a dangling pointer. However, since the query controller
+  // points to references owned by the overlay controller, those references
+  // need to be invalidated before cleaning the overlay controller.
+  // lens_overlay_query_controller_->ResetPageContentData();
+  if (lens_overlay_controller_->state() != LensOverlayController::State::kOff) {
+    lens_overlay_controller_->CloseUIAsync(dismissal_source);
+  } else {
+    CloseLensPart2();
+  }
 }
 
 void LensSearchController::CloseLensSync(
     lens::LensOverlayDismissalSource dismissal_source) {
-  lens_overlay_controller_->CloseUISync(dismissal_source);
-  state_ = State::kOff;
+  if (state() == State::kOff) {
+    return;
+  }
+  state_ = State::kClosing;
+  // The overlay controller must be closed before the query controller so it
+  // doesn't hold a dangling pointer. However, since the query controller
+  // points to references owned by the overlay controller, those references
+  // need to be invalidated before cleaning the overlay controller.
+  // lens_overlay_query_controller_->ResetPageContentData();
+  if (lens_overlay_controller_->state() != LensOverlayController::State::kOff) {
+    lens_overlay_controller_->CloseUISync(dismissal_source);
+  } else {
+    CloseLensPart2();
+  }
 }
 
 tabs::TabInterface* LensSearchController::GetTabInterface() {
@@ -186,25 +251,25 @@
 }
 
 LensOverlayController* LensSearchController::lens_overlay_controller() {
-  CHECK(initialized_)
-      << "The LensSearchController has not been initialized. Initialize() must "
-         "be called before using the LensSearchController.";
+  CHECK(initialized_) << "The LensSearchController has not been initialized. "
+                         "Initialize() must "
+                         "be called before using the LensSearchController.";
   return lens_overlay_controller_.get();
 }
 
 lens::LensOverlaySidePanelCoordinator*
 LensSearchController::lens_overlay_side_panel_coordinator() {
-  CHECK(initialized_)
-      << "The LensSearchController has not been initialized. Initialize() must "
-         "be called before using the LensSearchController.";
+  CHECK(initialized_) << "The LensSearchController has not been initialized. "
+                         "Initialize() must "
+                         "be called before using the LensSearchController.";
   return lens_overlay_side_panel_coordinator_.get();
 }
 
 optimization_guide::PageContextEligibility*
 LensSearchController::page_context_eligibility() {
-  CHECK(initialized_)
-      << "The LensSearchController has not been initialized. Initialize() must "
-         "be called before using the LensSearchController.";
+  CHECK(initialized_) << "The LensSearchController has not been initialized. "
+                         "Initialize() must "
+                         "be called before using the LensSearchController.";
   if (page_context_eligibility_) {
     return page_context_eligibility_;
   }
@@ -226,6 +291,28 @@
       pref_service, sync_service, theme_service);
 }
 
+std::unique_ptr<lens::LensOverlayQueryController>
+LensSearchController::CreateLensQueryController(
+    lens::LensOverlayFullImageResponseCallback full_image_callback,
+    lens::LensOverlayUrlResponseCallback url_callback,
+    lens::LensOverlayInteractionResponseCallback interaction_callback,
+    lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
+    lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
+    lens::UploadProgressCallback upload_progress_callback,
+    variations::VariationsClient* variations_client,
+    signin::IdentityManager* identity_manager,
+    Profile* profile,
+    lens::LensOverlayInvocationSource invocation_source,
+    bool use_dark_mode,
+    lens::LensOverlayGen204Controller* gen204_controller) {
+  return std::make_unique<lens::LensOverlayQueryController>(
+      std::move(full_image_callback), std::move(url_callback),
+      std::move(interaction_callback), std::move(suggest_inputs_callback),
+      std::move(thumbnail_created_callback),
+      std::move(upload_progress_callback), variations_client, identity_manager,
+      profile, invocation_source, use_dark_mode, gen204_controller);
+}
+
 std::unique_ptr<lens::LensOverlaySidePanelCoordinator>
 LensSearchController::CreateLensOverlaySidePanelCoordinator() {
   return std::make_unique<lens::LensOverlaySidePanelCoordinator>(this);
@@ -249,3 +336,72 @@
     optimization_guide::PageContextEligibility* page_context_eligibility) {
   page_context_eligibility_ = page_context_eligibility;
 }
+
+std::unique_ptr<lens::LensOverlayQueryController>
+LensSearchController::CreateLensQueryController(
+    lens::LensOverlayInvocationSource invocation_source) {
+  Profile* profile =
+      Profile::FromBrowserContext(tab_->GetContents()->GetBrowserContext());
+  return CreateLensQueryController(
+      base::BindRepeating(&LensSearchController::HandleStartQueryResponse,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&LensSearchController::HandleInteractionURLResponse,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&LensSearchController::HandleInteractionResponse,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&LensSearchController::HandleSuggestInputsResponse,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&LensSearchController::HandleThumbnailCreated,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(
+          &LensSearchController::HandlePageContentUploadProgress,
+          weak_ptr_factory_.GetWeakPtr()),
+      variations_client_, identity_manager_, profile,
+      /*invocation_source=*/invocation_source,
+      /*use_dark_mode=*/lens::LensOverlayShouldUseDarkMode(theme_service_),
+      gen204_controller_.get());
+}
+
+void LensSearchController::NotifyOverlayOpened() {
+  CHECK(state() == State::kInitializing);
+  state_ = State::kActive;
+}
+
+void LensSearchController::CloseLensPart2() {
+  // Cleanup the query controller.
+  lens_overlay_query_controller_.reset();
+  state_ = State::kOff;
+}
+
+void LensSearchController::HandleStartQueryResponse(
+    std::vector<lens::mojom::OverlayObjectPtr> objects,
+    lens::mojom::TextPtr text,
+    bool is_error) {
+  lens_overlay_controller_->HandleStartQueryResponse(std::move(objects),
+                                                     std::move(text), is_error);
+}
+
+void LensSearchController::HandleInteractionURLResponse(
+    lens::proto::LensOverlayUrlResponse response) {
+  lens_overlay_controller_->HandleInteractionURLResponse(response);
+}
+
+void LensSearchController::HandleInteractionResponse(
+    lens::mojom::TextPtr text) {
+  lens_overlay_controller_->HandleInteractionResponse(std::move(text));
+}
+
+void LensSearchController::HandleSuggestInputsResponse(
+    lens::proto::LensOverlaySuggestInputs suggest_inputs) {
+  lens_overlay_controller_->HandleSuggestInputsResponse(suggest_inputs);
+}
+
+void LensSearchController::HandlePageContentUploadProgress(uint64_t position,
+                                                           uint64_t total) {
+  lens_overlay_controller_->HandlePageContentUploadProgress(position, total);
+}
+
+void LensSearchController::HandleThumbnailCreated(
+    const std::string& thumbnail_bytes) {
+  lens_overlay_controller_->HandleThumbnailCreated(thumbnail_bytes);
+}
diff --git a/chrome/browser/ui/lens/lens_search_controller.h b/chrome/browser/ui/lens/lens_search_controller.h
index e3e7a6e..4336b7c 100644
--- a/chrome/browser/ui/lens/lens_search_controller.h
+++ b/chrome/browser/ui/lens/lens_search_controller.h
@@ -10,6 +10,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/lens/core/mojom/geometry.mojom.h"
+#include "chrome/browser/ui/lens/lens_overlay_query_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
 #include "components/lens/lens_overlay_dismissal_source.h"
 #include "components/lens/lens_overlay_invocation_source.h"
@@ -23,6 +24,7 @@
 class GURL;
 
 namespace lens {
+class LensOverlayGen204Controller;
 class LensOverlaySidePanelCoordinator;
 class LensSearchboxController;
 }  // namespace lens
@@ -133,6 +135,9 @@
   // Returns the LensOverlayController.
   LensOverlayController* lens_overlay_controller();
 
+  // Returns the LensOverlayQueryController.
+  lens::LensOverlayQueryController* lens_overlay_query_controller();
+
   // Returns the LensOverlaySidePanelCoordinator.
   lens::LensOverlaySidePanelCoordinator* lens_overlay_side_panel_coordinator();
 
@@ -146,6 +151,8 @@
   }
 
  protected:
+  friend class LensOverlayController;
+
   // Override these methods to stub out individual feature controllers for
   // testing.
   virtual std::unique_ptr<LensOverlayController> CreateLensOverlayController(
@@ -157,6 +164,22 @@
       syncer::SyncService* sync_service,
       ThemeService* theme_service);
 
+  // Override these methods to stub out network requests for testing.
+  virtual std::unique_ptr<lens::LensOverlayQueryController>
+  CreateLensQueryController(
+      lens::LensOverlayFullImageResponseCallback full_image_callback,
+      lens::LensOverlayUrlResponseCallback url_callback,
+      lens::LensOverlayInteractionResponseCallback interaction_callback,
+      lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
+      lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
+      lens::UploadProgressCallback page_content_upload_progress_callback,
+      variations::VariationsClient* variations_client,
+      signin::IdentityManager* identity_manager,
+      Profile* profile,
+      lens::LensOverlayInvocationSource invocation_source,
+      bool use_dark_mode,
+      lens::LensOverlayGen204Controller* gen204_controller);
+
   // Override these methods to be able to track calls made to the side panel
   // coordinator.
   virtual std::unique_ptr<lens::LensOverlaySidePanelCoordinator>
@@ -167,6 +190,17 @@
   virtual std::unique_ptr<lens::LensSearchboxController>
   CreateLensSearchboxController();
 
+  // Called by the Lens overlay when it has finished opening and has moved to
+  // the kOverlay state. This is how this class knows it can move into kActive
+  // state.
+  // TODO(crbug.com/404941800): Make this more generic to allow for multiple
+  // features to initialize at the same time.
+  void NotifyOverlayOpened();
+
+  // Shared logic for cleanup that is called after all features have finished
+  // cleaning up.
+  void CloseLensPart2();
+
   // Override these methods to be able to track calls made to the page context
   // eligibility API.
   virtual void CreatePageContextEligibilityAPI();
@@ -177,9 +211,16 @@
     // active.
     kOff,
 
+    // The controller is in the process of starting up. Soon to be kActive.
+    kInitializing,
+
     // One or more Lens features are active on this tab.
     kActive,
 
+    // The controller is in the process of closing all dependencies and cleaning
+    // up. Will soon be kOff.
+    kClosing,
+
     // TODO(crbug.com/335516480): Implement suspended state.
     kSuspended,
   };
@@ -189,6 +230,43 @@
   void OnPageContextEligibilityAPILoaded(
       optimization_guide::PageContextEligibility* page_context_eligibility);
 
+  // Passes the correct callbacks and dependencies to the protected
+  // CreateLensQueryController method.
+  std::unique_ptr<lens::LensOverlayQueryController> CreateLensQueryController(
+      lens::LensOverlayInvocationSource invocation_source);
+
+  // Callback used by the query controller to notify the search controller of
+  // the response to the initial image upload request.
+  void HandleStartQueryResponse(
+      std::vector<lens::mojom::OverlayObjectPtr> objects,
+      lens::mojom::TextPtr text,
+      bool is_error);
+
+  // Callback used by the query controller to notify the search controller of
+  // the URL response to the interaction request, aka, the URL that should be
+  // opened in the results frame.
+  void HandleInteractionURLResponse(
+      lens::proto::LensOverlayUrlResponse response);
+
+  // Callback used by the query controller to notify the search controller of
+  // the response of an interaction request. If this is a visual interaction
+  // request, the response will contain the text container within that image.
+  void HandleInteractionResponse(lens::mojom::TextPtr text);
+
+  // Callback used by the query controller to notify the search controller of
+  // the suggest inputs response. This is used to update the searchbox with
+  // the most recent suggest inputs.
+  void HandleSuggestInputsResponse(
+      lens::proto::LensOverlaySuggestInputs suggest_inputs);
+
+  // Callback used by the query controller to pass the thumbnail bytes of a
+  // visual interaction request to the searchbox.
+  void HandleThumbnailCreated(const std::string& thumbnail_bytes);
+
+  // Callback used by the query controller to notify the search controller of
+  // the progress of the page content upload.
+  void HandlePageContentUploadProgress(uint64_t position, uint64_t total);
+
   // Whether the LensSearchController has been initialized. Meaning, all the
   // dependencies have been initialized and the controller is ready to use.
   bool initialized_ = false;
@@ -196,9 +274,19 @@
   // Tracks the internal state machine.
   State state_ = State::kOff;
 
+  // The query controller for the Lens Search feature on this tab. Lives for the
+  // duration of a Lens feature being active on this tab.
+  std::unique_ptr<lens::LensOverlayQueryController>
+      lens_overlay_query_controller_;
+
   // The overlay controller for the Lens Search feature on this tab.
   std::unique_ptr<LensOverlayController> lens_overlay_controller_;
 
+  // The controller for sending gen204 pings. Owned by this class so it can
+  // outlive the query controller, allowing gen204 requests to be sent upon
+  // query end.
+  std::unique_ptr<lens::LensOverlayGen204Controller> gen204_controller_;
+
   // The side panel coordinator for the Lens Search feature on this tab.
   std::unique_ptr<lens::LensOverlaySidePanelCoordinator>
       lens_overlay_side_panel_coordinator_;
@@ -211,6 +299,17 @@
   // The page context eligibility API if it has been fetched. Can be nullptr.
   raw_ptr<optimization_guide::PageContextEligibility> page_context_eligibility_;
 
+  // Owned by Profile, and thus guaranteed to outlive this instance.
+  raw_ptr<variations::VariationsClient> variations_client_;
+
+  // Unowned IdentityManager for fetching access tokens. Could be null for
+  // incognito profiles.
+  raw_ptr<signin::IdentityManager> identity_manager_;
+
+  // The theme service associated with the current profile. Owned by Profile,
+  // and thus guaranteed to outlive this instance.
+  raw_ptr<ThemeService> theme_service_;
+
   // Owns this class.
   raw_ptr<tabs::TabInterface> tab_;
 
diff --git a/chrome/browser/ui/lens/test_lens_overlay_controller.cc b/chrome/browser/ui/lens/test_lens_overlay_controller.cc
index 67aa47d..5d7a1b761 100644
--- a/chrome/browser/ui/lens/test_lens_overlay_controller.cc
+++ b/chrome/browser/ui/lens/test_lens_overlay_controller.cc
@@ -6,8 +6,6 @@
 
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/ui/lens/lens_overlay_query_controller.h"
-#include "chrome/browser/ui/lens/test_lens_overlay_query_controller.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/sync/service/sync_service.h"
@@ -16,82 +14,20 @@
 
 namespace lens {
 
-namespace {
-
-// The fake server session id.
-constexpr char kTestServerSessionId[] = "server_session_id";
-
-// The fake search session id.
-constexpr char kTestSearchSessionId[] = "search_session_id";
-
-// The fake suggest signals.
-constexpr char kTestSuggestSignals[] = "encoded_image_signals";
-
-lens::Text CreateTestText(const std::vector<std::string>& words) {
-  lens::Text text;
-  text.set_content_language("es");
-  // Create a paragraph.
-  lens::TextLayout::Paragraph* paragraph =
-      text.mutable_text_layout()->add_paragraphs();
-  // Create a line.
-  lens::TextLayout::Line* line = paragraph->add_lines();
-
-  for (size_t i = 0; i < words.size(); ++i) {
-    lens::TextLayout::Word* word = line->add_words();
-    word->set_plain_text(words[i]);
-    word->set_text_separator(" ");
-    word->mutable_geometry()->mutable_bounding_box()->set_center_x(0.1 * i);
-    word->mutable_geometry()->mutable_bounding_box()->set_center_y(0.1);
-    word->mutable_geometry()->mutable_bounding_box()->set_width(0.1);
-    word->mutable_geometry()->mutable_bounding_box()->set_height(0.1);
-    word->mutable_geometry()->mutable_bounding_box()->set_coordinate_type(
-        lens::NORMALIZED);
-  }
-  return text;
-}
-
-}  // namespace
-
-std::unique_ptr<lens::LensOverlayQueryController>
-TestLensOverlayController::CreateLensQueryController(
-    lens::LensOverlayFullImageResponseCallback full_image_callback,
-    lens::LensOverlayUrlResponseCallback url_callback,
-    lens::LensOverlayInteractionResponseCallback interaction_callback,
-    lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
-    lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
-    lens::UploadProgressCallback upload_progress_callback,
+TestLensOverlayController::TestLensOverlayController(
+    tabs::TabInterface* tab,
+    LensSearchController* lens_search_controller,
     variations::VariationsClient* variations_client,
     signin::IdentityManager* identity_manager,
-    Profile* profile,
-    lens::LensOverlayInvocationSource invocation_source,
-    bool use_dark_mode,
-    lens::LensOverlayGen204Controller* gen204_controller) {
-  auto fake_query_controller =
-      std::make_unique<lens::TestLensOverlayQueryController>(
-          full_image_callback, url_callback, interaction_callback,
-          suggest_inputs_callback, thumbnail_created_callback,
-          upload_progress_callback, variations_client, identity_manager,
-          profile, invocation_source, use_dark_mode, gen204_controller);
-
-  // Set up the fake responses for the query controller.
-  lens::LensOverlayServerClusterInfoResponse cluster_info_response;
-  cluster_info_response.set_server_session_id(kTestServerSessionId);
-  cluster_info_response.set_search_session_id(kTestSearchSessionId);
-  fake_query_controller->set_fake_cluster_info_response(cluster_info_response);
-
-  lens::LensOverlayObjectsResponse objects_response;
-  objects_response.mutable_text()->CopyFrom(
-      CreateTestText({"This", "is", "test", "text."}));
-  objects_response.mutable_cluster_info()->set_server_session_id(
-      kTestServerSessionId);
-  objects_response.mutable_cluster_info()->set_search_session_id(
-      kTestSearchSessionId);
-  fake_query_controller->set_fake_objects_response(objects_response);
-
-  lens::LensOverlayInteractionResponse interaction_response;
-  interaction_response.set_encoded_response(kTestSuggestSignals);
-  fake_query_controller->set_fake_interaction_response(interaction_response);
-  return fake_query_controller;
-}
+    PrefService* pref_service,
+    syncer::SyncService* sync_service,
+    ThemeService* theme_service)
+    : LensOverlayController(tab,
+                            lens_search_controller,
+                            variations_client,
+                            identity_manager,
+                            pref_service,
+                            sync_service,
+                            theme_service) {}
 
 }  // namespace lens
diff --git a/chrome/browser/ui/lens/test_lens_overlay_controller.h b/chrome/browser/ui/lens/test_lens_overlay_controller.h
index 5dd1eea..4188a96 100644
--- a/chrome/browser/ui/lens/test_lens_overlay_controller.h
+++ b/chrome/browser/ui/lens/test_lens_overlay_controller.h
@@ -18,28 +18,7 @@
                             signin::IdentityManager* identity_manager,
                             PrefService* pref_service,
                             syncer::SyncService* sync_service,
-                            ThemeService* theme_service)
-      : LensOverlayController(tab,
-                              lens_search_controller,
-                              variations_client,
-                              identity_manager,
-                              pref_service,
-                              sync_service,
-                              theme_service) {}
-
-  std::unique_ptr<lens::LensOverlayQueryController> CreateLensQueryController(
-      lens::LensOverlayFullImageResponseCallback full_image_callback,
-      lens::LensOverlayUrlResponseCallback url_callback,
-      lens::LensOverlayInteractionResponseCallback interaction_callback,
-      lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
-      lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
-      lens::UploadProgressCallback upload_progress_callback,
-      variations::VariationsClient* variations_client,
-      signin::IdentityManager* identity_manager,
-      Profile* profile,
-      lens::LensOverlayInvocationSource invocation_source,
-      bool use_dark_mode,
-      lens::LensOverlayGen204Controller* gen204_controller) override;
+                            ThemeService* theme_service);
 };
 
 }  // namespace lens
diff --git a/chrome/browser/ui/lens/test_lens_search_controller.cc b/chrome/browser/ui/lens/test_lens_search_controller.cc
index b066a86..0b3040d0 100644
--- a/chrome/browser/ui/lens/test_lens_search_controller.cc
+++ b/chrome/browser/ui/lens/test_lens_search_controller.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/ui/lens/test_lens_search_controller.h"
 
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/ui/lens/lens_overlay_query_controller.h"
 #include "chrome/browser/ui/lens/test_lens_overlay_controller.h"
+#include "chrome/browser/ui/lens/test_lens_overlay_query_controller.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/sync/service/sync_service.h"
@@ -14,6 +17,42 @@
 
 namespace lens {
 
+namespace {
+
+// The fake server session id.
+constexpr char kTestServerSessionId[] = "server_session_id";
+
+// The fake search session id.
+constexpr char kTestSearchSessionId[] = "search_session_id";
+
+// The fake suggest signals.
+constexpr char kTestSuggestSignals[] = "encoded_image_signals";
+
+lens::Text CreateTestText(const std::vector<std::string>& words) {
+  lens::Text text;
+  text.set_content_language("es");
+  // Create a paragraph.
+  lens::TextLayout::Paragraph* paragraph =
+      text.mutable_text_layout()->add_paragraphs();
+  // Create a line.
+  lens::TextLayout::Line* line = paragraph->add_lines();
+
+  for (size_t i = 0; i < words.size(); ++i) {
+    lens::TextLayout::Word* word = line->add_words();
+    word->set_plain_text(words[i]);
+    word->set_text_separator(" ");
+    word->mutable_geometry()->mutable_bounding_box()->set_center_x(0.1 * i);
+    word->mutable_geometry()->mutable_bounding_box()->set_center_y(0.1);
+    word->mutable_geometry()->mutable_bounding_box()->set_width(0.1);
+    word->mutable_geometry()->mutable_bounding_box()->set_height(0.1);
+    word->mutable_geometry()->mutable_bounding_box()->set_coordinate_type(
+        lens::NORMALIZED);
+  }
+  return text;
+}
+
+}  // namespace
+
 std::unique_ptr<LensOverlayController>
 TestLensSearchController::CreateLensOverlayController(
     tabs::TabInterface* tab,
@@ -32,4 +71,46 @@
       pref_service, sync_service, theme_service);
 }
 
+std::unique_ptr<lens::LensOverlayQueryController>
+TestLensSearchController::CreateLensQueryController(
+    lens::LensOverlayFullImageResponseCallback full_image_callback,
+    lens::LensOverlayUrlResponseCallback url_callback,
+    lens::LensOverlayInteractionResponseCallback interaction_callback,
+    lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
+    lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
+    lens::UploadProgressCallback upload_progress_callback,
+    variations::VariationsClient* variations_client,
+    signin::IdentityManager* identity_manager,
+    Profile* profile,
+    lens::LensOverlayInvocationSource invocation_source,
+    bool use_dark_mode,
+    lens::LensOverlayGen204Controller* gen204_controller) {
+  auto fake_query_controller =
+      std::make_unique<lens::TestLensOverlayQueryController>(
+          full_image_callback, url_callback, interaction_callback,
+          suggest_inputs_callback, thumbnail_created_callback,
+          upload_progress_callback, variations_client, identity_manager,
+          profile, invocation_source, use_dark_mode, gen204_controller);
+
+  // Set up the fake responses for the query controller.
+  lens::LensOverlayServerClusterInfoResponse cluster_info_response;
+  cluster_info_response.set_server_session_id(kTestServerSessionId);
+  cluster_info_response.set_search_session_id(kTestSearchSessionId);
+  fake_query_controller->set_fake_cluster_info_response(cluster_info_response);
+
+  lens::LensOverlayObjectsResponse objects_response;
+  objects_response.mutable_text()->CopyFrom(
+      CreateTestText({"This", "is", "test", "text."}));
+  objects_response.mutable_cluster_info()->set_server_session_id(
+      kTestServerSessionId);
+  objects_response.mutable_cluster_info()->set_search_session_id(
+      kTestSearchSessionId);
+  fake_query_controller->set_fake_objects_response(objects_response);
+
+  lens::LensOverlayInteractionResponse interaction_response;
+  interaction_response.set_encoded_response(kTestSuggestSignals);
+  fake_query_controller->set_fake_interaction_response(interaction_response);
+  return fake_query_controller;
+}
+
 }  // namespace lens
diff --git a/chrome/browser/ui/lens/test_lens_search_controller.h b/chrome/browser/ui/lens/test_lens_search_controller.h
index 3be2168..52c7f639 100644
--- a/chrome/browser/ui/lens/test_lens_search_controller.h
+++ b/chrome/browser/ui/lens/test_lens_search_controller.h
@@ -26,6 +26,20 @@
       PrefService* pref_service,
       syncer::SyncService* sync_service,
       ThemeService* theme_service) override;
+
+  std::unique_ptr<lens::LensOverlayQueryController> CreateLensQueryController(
+      lens::LensOverlayFullImageResponseCallback full_image_callback,
+      lens::LensOverlayUrlResponseCallback url_callback,
+      lens::LensOverlayInteractionResponseCallback interaction_callback,
+      lens::LensOverlaySuggestInputsCallback suggest_inputs_callback,
+      lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback,
+      lens::UploadProgressCallback upload_progress_callback,
+      variations::VariationsClient* variations_client,
+      signin::IdentityManager* identity_manager,
+      Profile* profile,
+      lens::LensOverlayInvocationSource invocation_source,
+      bool use_dark_mode,
+      lens::LensOverlayGen204Controller* gen204_controller) override;
 };
 
 }  // namespace lens
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc b/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
index 0d2a68e..a05510e 100644
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
@@ -202,6 +202,7 @@
 }
 
 bool PresentationReceiverWindowController::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
index ca72b324..3fc06be 100644
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
@@ -102,6 +102,7 @@
                    const std::string& request_method,
                    base::OnceCallback<void(bool)> callback) final;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
index 754cb4d1..47021c5 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
@@ -154,7 +154,7 @@
 
 void SaveUpdateBubbleController::OnNotNowClicked() {
   CHECK_EQ(password_manager::ui::PENDING_PASSWORD_STATE, GetState());
-  // TODO(crbug.com/414573697): Log appropriate metrics.
+  SetDismissalReason(metrics_util::CLICKED_NOT_NOW);
   if (delegate_) {
     delegate_->OnNotNowClicked();
   }
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.h b/chrome/browser/ui/passwords/manage_passwords_test.h
index 49e6f4d4..a4d53cf 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.h
+++ b/chrome/browser/ui/passwords/manage_passwords_test.h
@@ -105,6 +105,14 @@
       password_manager::PasswordStoreInterface* profile_store = nullptr,
       password_manager::PasswordStoreInterface* account_store = nullptr);
 
+  auto CheckHistogramUniqueSample(const std::string& name,
+                                  int sample,
+                                  int expected_count) {
+    return Do([=, this]() {
+      histogram_tester_.ExpectUniqueSample(name, sample, expected_count);
+    });
+  }
+
  private:
   password_manager::PasswordForm password_form_;
   password_manager::PasswordForm insecure_credential_;
diff --git a/chrome/browser/ui/android/plus_addresses/BUILD.gn b/chrome/browser/ui/plus_addresses/android/BUILD.gn
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/BUILD.gn
rename to chrome/browser/ui/plus_addresses/android/BUILD.gn
diff --git a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.cc b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.cc
similarity index 93%
rename from chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.cc
rename to chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.cc
index 83c47ad4..a1d46af 100644
--- a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.cc
+++ b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h"
 
 #include "base/check_deref.h"
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.h"
 #include "components/plus_addresses/plus_address_service.h"
 #include "content/public/browser/web_contents.h"
 
diff --git a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h
similarity index 91%
rename from chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h
rename to chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h
index 58a68d5d..16be50d 100644
--- a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h
+++ b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_CONTROLLER_H_
-#define CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_CONTROLLER_H_
+#ifndef CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_CONTROLLER_H_
+#define CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_CONTROLLER_H_
 
 #include <memory>
 #include <string>
@@ -64,4 +64,4 @@
 
 }  // namespace plus_addresses
 
-#endif  // CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_CONTROLLER_H_
+#endif  // CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_CONTROLLER_H_
diff --git a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.cc b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.cc
similarity index 91%
rename from chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.cc
rename to chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.cc
index 54ba7e0..bedc0f5 100644
--- a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.cc
+++ b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.h"
 
 #include <vector>
 
@@ -10,7 +10,7 @@
 #include "base/android/jni_string.h"
 #include "base/check_deref.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h"
 #include "components/plus_addresses/grit/plus_addresses_strings.h"
 #include "components/plus_addresses/plus_address_types.h"
 #include "components/plus_addresses/plus_address_ui_utils.h"
@@ -18,8 +18,8 @@
 #include "ui/base/l10n/l10n_util.h"
 
 // Must come after all headers that specialize FromJniType() / ToJniType().
-#include "chrome/browser/ui/android/plus_addresses/jni_headers/AllPlusAddressesBottomSheetBridge_jni.h"
-#include "chrome/browser/ui/android/plus_addresses/jni_headers/PlusProfile_jni.h"
+#include "chrome/browser/ui/plus_addresses/android/jni_headers/AllPlusAddressesBottomSheetBridge_jni.h"
+#include "chrome/browser/ui/plus_addresses/android/jni_headers/PlusProfile_jni.h"
 
 namespace plus_addresses {
 
diff --git a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.h b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.h
similarity index 89%
rename from chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.h
rename to chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.h
index 020dc04..1e54e5b 100644
--- a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.h
+++ b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_VIEW_H_
-#define CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_VIEW_H_
+#ifndef CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_VIEW_H_
+#define CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_VIEW_H_
 
 #include "base/android/scoped_java_ref.h"
 #include "base/containers/span.h"
@@ -44,4 +44,4 @@
 
 }  // namespace plus_addresses
 
-#endif  // CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_VIEW_H_
+#endif  // CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_ALL_PLUS_ADDRESSES_BOTTOM_SHEET_VIEW_H_
diff --git a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view_browsertest.cc b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view_browsertest.cc
similarity index 95%
rename from chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view_browsertest.cc
rename to chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view_browsertest.cc
index 7e01f167..c83c30be 100644
--- a/chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view_browsertest.cc
+++ b/chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view_browsertest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view.h"
 
 #include <memory>
 #include <string>
@@ -12,7 +12,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_controller.h"
+#include "chrome/browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_controller.h"
 #include "chrome/test/base/android/android_browser_test.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "components/plus_addresses/fake_plus_address_service.h"
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/color/refresh_plus_address_icon_tint_list.xml b/chrome/browser/ui/plus_addresses/android/java/res/color/refresh_plus_address_icon_tint_list.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/color/refresh_plus_address_icon_tint_list.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/color/refresh_plus_address_icon_tint_list.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/drawable/proposed_plus_address_background.xml b/chrome/browser/ui/plus_addresses/android/java/res/drawable/proposed_plus_address_background.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/drawable/proposed_plus_address_background.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/drawable/proposed_plus_address_background.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/layout/all_plus_addresses_bottom_sheet.xml b/chrome/browser/ui/plus_addresses/android/java/res/layout/all_plus_addresses_bottom_sheet.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/layout/all_plus_addresses_bottom_sheet.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/layout/all_plus_addresses_bottom_sheet.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/layout/plus_address_creation_error_state.xml b/chrome/browser/ui/plus_addresses/android/java/res/layout/plus_address_creation_error_state.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/layout/plus_address_creation_error_state.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/layout/plus_address_creation_error_state.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/layout/plus_address_creation_normal_state.xml b/chrome/browser/ui/plus_addresses/android/java/res/layout/plus_address_creation_normal_state.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/layout/plus_address_creation_normal_state.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/layout/plus_address_creation_normal_state.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/layout/plus_address_creation_prompt.xml b/chrome/browser/ui/plus_addresses/android/java/res/layout/plus_address_creation_prompt.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/layout/plus_address_creation_prompt.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/layout/plus_address_creation_prompt.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/layout/plus_profile_info_view.xml b/chrome/browser/ui/plus_addresses/android/java/res/layout/plus_profile_info_view.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/layout/plus_profile_info_view.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/layout/plus_profile_info_view.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/values-night/colors.xml b/chrome/browser/ui/plus_addresses/android/java/res/values-night/colors.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/values-night/colors.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/values-night/colors.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/values/colors.xml b/chrome/browser/ui/plus_addresses/android/java/res/values/colors.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/values/colors.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/values/colors.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/res/values/dimens.xml b/chrome/browser/ui/plus_addresses/android/java/res/values/dimens.xml
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/res/values/dimens.xml
rename to chrome/browser/ui/plus_addresses/android/java/res/values/dimens.xml
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetBridge.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetBridge.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetBridge.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetBridge.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetCoordinator.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetCoordinator.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetCoordinator.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetCoordinator.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediator.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediator.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediator.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediator.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetProperties.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetProperties.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetProperties.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetProperties.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetView.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetView.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetView.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetView.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewBinder.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewBinder.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewBinder.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewBinder.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContent.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContent.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContent.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContent.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinator.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinator.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinator.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinator.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationDelegate.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationDelegate.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationDelegate.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationDelegate.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationErrorStateInfo.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationErrorStateInfo.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationErrorStateInfo.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationErrorStateInfo.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediator.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediator.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediator.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediator.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationNormalStateInfo.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationNormalStateInfo.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationNormalStateInfo.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationNormalStateInfo.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationProperties.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationProperties.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationProperties.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationProperties.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBinder.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBinder.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBinder.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBinder.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridge.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridge.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridge.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridge.java
diff --git a/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusProfile.java b/chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusProfile.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusProfile.java
rename to chrome/browser/ui/plus_addresses/android/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusProfile.java
diff --git a/chrome/browser/ui/android/plus_addresses/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetRenderTest.java b/chrome/browser/ui/plus_addresses/android/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetRenderTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetRenderTest.java
rename to chrome/browser/ui/plus_addresses/android/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetRenderTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationRenderTest.java b/chrome/browser/ui/plus_addresses/android/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationRenderTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationRenderTest.java
rename to chrome/browser/ui/plus_addresses/android/javatests/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationRenderTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediatorTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediatorTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediatorTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetMediatorTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetModuleTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetModuleTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetModuleTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetModuleTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/AllPlusAddressesBottomSheetViewTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContentTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContentTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContentTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationBottomSheetContentTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinatorTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinatorTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinatorTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationCoordinatorTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediatorTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediatorTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediatorTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediatorTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationModuleTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationModuleTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationModuleTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationModuleTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridgeTest.java b/chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridgeTest.java
similarity index 100%
rename from chrome/browser/ui/android/plus_addresses/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridgeTest.java
rename to chrome/browser/ui/plus_addresses/android/junit/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationViewBridgeTest.java
diff --git a/chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.cc b/chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.cc
similarity index 98%
rename from chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.cc
rename to chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.cc
index 660497a..3f21765 100644
--- a/chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.cc
+++ b/chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.h"
+#include "chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.h"
 
 #include <optional>
 
@@ -15,9 +15,9 @@
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/plus_addresses/plus_address_setting_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.h"
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
+#include "chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
 #include "components/plus_addresses/features.h"
 #include "components/plus_addresses/grit/plus_addresses_strings.h"
diff --git a/chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.h b/chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.h
similarity index 94%
rename from chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.h
rename to chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.h
index 0099739c..154a867 100644
--- a/chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.h
+++ b/chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_CONTROLLER_ANDROID_H_
-#define CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_CONTROLLER_ANDROID_H_
+#ifndef CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_PLUS_ADDRESS_CREATION_CONTROLLER_ANDROID_H_
+#define CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_PLUS_ADDRESS_CREATION_CONTROLLER_ANDROID_H_
 
 #include <memory>
 #include <optional>
 
-#include "chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.h"
+#include "chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.h"
 #include "chrome/browser/ui/plus_addresses/plus_address_creation_controller.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
 #include "components/autofill/core/common/plus_address_survey_type.h"
@@ -113,4 +113,4 @@
 
 }  // namespace plus_addresses
 
-#endif  // CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_CONTROLLER_ANDROID_H_
+#endif  // CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_PLUS_ADDRESS_CREATION_CONTROLLER_ANDROID_H_
diff --git a/chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android_unittest.cc b/chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android_unittest.cc
similarity index 99%
rename from chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android_unittest.cc
rename to chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android_unittest.cc
index a0d577b..53d83a9 100644
--- a/chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android_unittest.cc
+++ b/chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.h"
+#include "chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.h"
 
 #include <memory>
 #include <optional>
diff --git a/chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.cc b/chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.cc
similarity index 95%
rename from chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.cc
rename to chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.cc
index ccbee209..0aefec70 100644
--- a/chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.cc
+++ b/chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.h"
+#include "chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.h"
 
 #include <string>
 
@@ -11,8 +11,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/types/cxx23_to_underlying.h"
-#include "chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.h"
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
+#include "chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.h"
 #include "components/plus_addresses/features.h"
 #include "components/plus_addresses/grit/plus_addresses_strings.h"
 #include "components/plus_addresses/plus_address_types.h"
@@ -24,9 +24,9 @@
 #include "url/gurl.h"
 
 // Must come after all headers that specialize FromJniType() / ToJniType().
-#include "chrome/browser/ui/android/plus_addresses/jni_headers/PlusAddressCreationErrorStateInfo_jni.h"
-#include "chrome/browser/ui/android/plus_addresses/jni_headers/PlusAddressCreationNormalStateInfo_jni.h"
-#include "chrome/browser/ui/android/plus_addresses/jni_headers/PlusAddressCreationViewBridge_jni.h"
+#include "chrome/browser/ui/plus_addresses/android/jni_headers/PlusAddressCreationErrorStateInfo_jni.h"
+#include "chrome/browser/ui/plus_addresses/android/jni_headers/PlusAddressCreationNormalStateInfo_jni.h"
+#include "chrome/browser/ui/plus_addresses/android/jni_headers/PlusAddressCreationViewBridge_jni.h"
 
 namespace plus_addresses {
 
diff --git a/chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.h b/chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.h
similarity index 94%
rename from chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.h
rename to chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.h
index 4e9b822..78ef06b6 100644
--- a/chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android.h
+++ b/chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_VIEW_ANDROID_H_
-#define CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_VIEW_ANDROID_H_
+#ifndef CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_PLUS_ADDRESS_CREATION_VIEW_ANDROID_H_
+#define CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_PLUS_ADDRESS_CREATION_VIEW_ANDROID_H_
 
 #include <jni.h>
 
@@ -95,4 +95,4 @@
 
 }  // namespace plus_addresses
 
-#endif  // CHROME_BROWSER_UI_ANDROID_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_VIEW_ANDROID_H_
+#endif  // CHROME_BROWSER_UI_PLUS_ADDRESSES_ANDROID_PLUS_ADDRESS_CREATION_VIEW_ANDROID_H_
diff --git a/chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android_browsertest.cc b/chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android_browsertest.cc
similarity index 98%
rename from chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android_browsertest.cc
rename to chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android_browsertest.cc
index e36c5f4..b3bd9cb0 100644
--- a/chrome/browser/ui/android/plus_addresses/plus_address_creation_view_android_browsertest.cc
+++ b/chrome/browser/ui/plus_addresses/android/plus_address_creation_view_android_browsertest.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_test_util.h"
-#include "chrome/browser/ui/android/plus_addresses/plus_address_creation_controller_android.h"
+#include "chrome/browser/ui/plus_addresses/android/plus_address_creation_controller_android.h"
 #include "chrome/test/base/android/android_browser_test.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "components/plus_addresses/fake_plus_address_service.h"
diff --git a/chrome/browser/ui/views/plus_addresses/plus_address_creation_controller_desktop.cc b/chrome/browser/ui/plus_addresses/views/plus_address_creation_controller_desktop.cc
similarity index 99%
rename from chrome/browser/ui/views/plus_addresses/plus_address_creation_controller_desktop.cc
rename to chrome/browser/ui/plus_addresses/views/plus_address_creation_controller_desktop.cc
index 502b73f..a0385353a 100644
--- a/chrome/browser/ui/views/plus_addresses/plus_address_creation_controller_desktop.cc
+++ b/chrome/browser/ui/plus_addresses/views/plus_address_creation_controller_desktop.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/plus_addresses/plus_address_setting_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.h"
 #include "chrome/browser/ui/user_education/browser_user_education_interface.h"
-#include "chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/feature_engagement/public/feature_constants.h"
diff --git a/chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.cc b/chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.cc
similarity index 99%
rename from chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.cc
rename to chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.cc
index 45c24974..9444c78 100644
--- a/chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.cc
+++ b/chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.h"
+#include "chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.h"
 
 #include <memory>
 #include <optional>
diff --git a/chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.h b/chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.h
similarity index 94%
rename from chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.h
rename to chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.h
index 5f51f9a..1362008b 100644
--- a/chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_delegate.h
+++ b/chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_DIALOG_DELEGATE_H_
-#define CHROME_BROWSER_UI_VIEWS_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_DIALOG_DELEGATE_H_
+#ifndef CHROME_BROWSER_UI_PLUS_ADDRESSES_VIEWS_PLUS_ADDRESS_CREATION_DIALOG_DELEGATE_H_
+#define CHROME_BROWSER_UI_PLUS_ADDRESSES_VIEWS_PLUS_ADDRESS_CREATION_DIALOG_DELEGATE_H_
 
 #include "base/functional/callback_forward.h"
 #include "base/memory/weak_ptr.h"
@@ -102,4 +102,4 @@
 
 }  // namespace plus_addresses
 
-#endif  // CHROME_BROWSER_UI_VIEWS_PLUS_ADDRESSES_PLUS_ADDRESS_CREATION_DIALOG_DELEGATE_H_
+#endif  // CHROME_BROWSER_UI_PLUS_ADDRESSES_VIEWS_PLUS_ADDRESS_CREATION_DIALOG_DELEGATE_H_
diff --git a/chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_interactive_uitest.cc b/chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_interactive_uitest.cc
similarity index 100%
rename from chrome/browser/ui/views/plus_addresses/plus_address_creation_dialog_interactive_uitest.cc
rename to chrome/browser/ui/plus_addresses/views/plus_address_creation_dialog_interactive_uitest.cc
diff --git a/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc b/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc
index b3f7c5e5..96e3ee9a 100644
--- a/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc
+++ b/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc
@@ -238,16 +238,16 @@
   RunTestSequence(
       WaitForEvent(BubbleSignInPromoSignInButtonView::kPromoSignInButton,
                    kBubbleSignInPromoSignInButtonHasCallback),
-      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubbleElementId),
       SetOnIncompatibleAction(
           OnIncompatibleAction::kIgnoreAndContinue,
           "Screenshot can only run in pixel_tests on Windows."),
-      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
-                 "5455375"),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubbleElementId,
+                 std::string(), "5455375"),
       NameChildViewByType<views::MdTextButton>(
           BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
       PressButton(kButton).SetMustRemainVisible(false),
-      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubbleElementId));
 
   // Check that clicking the sign in button navigated to a sign in page.
   EXPECT_TRUE(IsSignInURL());
@@ -322,16 +322,16 @@
   RunTestSequence(
       WaitForEvent(BubbleSignInPromoSignInButtonView::kPromoSignInButton,
                    kBubbleSignInPromoSignInButtonHasCallback),
-      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubbleElementId),
       SetOnIncompatibleAction(
           OnIncompatibleAction::kIgnoreAndContinue,
           "Screenshot can only run in pixel_tests on Windows."),
-      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
-                 "5455375"),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubbleElementId,
+                 std::string(), "5455375"),
       NameChildViewByType<views::MdTextButton>(
           BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
       PressButton(kButton).SetMustRemainVisible(false),
-      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubbleElementId));
 
   // Check that there is no helper attached to the sign in tab, because the
   // password was already moved.
@@ -390,16 +390,16 @@
   RunTestSequence(
       WaitForEvent(BubbleSignInPromoSignInButtonView::kPromoSignInButton,
                    kBubbleSignInPromoSignInButtonHasCallback),
-      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubbleElementId),
       SetOnIncompatibleAction(
           OnIncompatibleAction::kIgnoreAndContinue,
           "Screenshot can only run in pixel_tests on Windows."),
-      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
-                 "5455375"),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubbleElementId,
+                 std::string(), "5455375"),
       NameChildViewByType<views::MdTextButton>(
           BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
       PressButton(kButton).SetMustRemainVisible(false),
-      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubbleElementId));
 
   // Check that clicking the sign in button navigated to a sign in page.
   EXPECT_TRUE(IsSignInURL());
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
index 63b4993..fa497bf 100644
--- a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
@@ -489,6 +489,7 @@
 
   // Indicates intent to interfere with window creations.
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc
index d883b7f3..b375b9e 100644
--- a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc
@@ -223,7 +223,7 @@
   WaitForDialogToLoad();
 
   ASSERT_TRUE(web_view_->IsWebContentsCreationOverridden(
-      nullptr /* source_site_instance */,
+      nullptr /* opener */, nullptr /* source_site_instance */,
       content::mojom::WindowContainerType::NORMAL /* window_container_type */,
       GURL() /* opener_url */, "foo" /* frame_name */,
       GURL() /* target_url */));
diff --git a/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.cc b/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.cc
index ac54730..ec7191b 100644
--- a/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.cc
+++ b/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.cc
@@ -154,3 +154,7 @@
 
   return ConfirmInfoBarDelegate::Accept();
 }
+
+bool DefaultBrowserInfoBarDelegate::ShouldHideInFullscreen() const {
+  return true;
+}
diff --git a/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.h b/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.h
index ad59c0b9..8275e974 100644
--- a/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.h
+++ b/chrome/browser/ui/startup/default_browser_prompt/default_browser_infobar_delegate.h
@@ -61,6 +61,7 @@
   int GetButtons() const override;
   std::u16string GetButtonLabel(InfoBarButton button) const override;
   bool Accept() override;
+  bool ShouldHideInFullscreen() const override;
 
   // The WebContents's corresponding profile.
   raw_ptr<Profile> profile_;
diff --git a/chrome/browser/ui/startup/default_browser_prompt/default_browser_prompt_interactive_uitest.cc b/chrome/browser/ui/startup/default_browser_prompt/default_browser_prompt_interactive_uitest.cc
index 38e1bbe..fc8ad55 100644
--- a/chrome/browser/ui/startup/default_browser_prompt/default_browser_prompt_interactive_uitest.cc
+++ b/chrome/browser/ui/startup/default_browser_prompt/default_browser_prompt_interactive_uitest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/webui/test_support/webui_interactive_test_mixin.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/branded_strings.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "chrome/test/interaction/tracked_element_webcontents.h"
 #include "content/public/test/browser_test.h"
@@ -86,6 +87,14 @@
             SelectMenuItem(AppMenuModel::kSetBrowserAsDefaultMenuItem))));
 }
 
+IN_PROC_BROWSER_TEST_F(DefaultBrowserPromptInteractiveTest, HidesInFullscreen) {
+  DefaultBrowserPromptManager::GetInstance()->MaybeShowPrompt();
+  RunTestSequence(WaitForShow(ConfirmInfoBar::kInfoBarElementId), Do([&]() {
+                    ui_test_utils::ToggleFullscreenModeAndWait(browser());
+                  }),
+                  WaitForHide(ConfirmInfoBar::kInfoBarElementId));
+}
+
 // Linux test environment doesn't allow setting default via the
 // chrome://settings/defaultBrowser page.
 #if !BUILDFLAG(IS_LINUX)
diff --git a/chrome/browser/ui/tab_ui_helper.cc b/chrome/browser/ui/tab_ui_helper.cc
index dca1a48a..43c21ca8 100644
--- a/chrome/browser/ui/tab_ui_helper.cc
+++ b/chrome/browser/ui/tab_ui_helper.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/tab_ui_helper.h"
 
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "build/build_config.h"
 #include "chrome/browser/favicon/favicon_utils.h"
@@ -12,6 +13,17 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/resources/grit/ui_resources.h"
 
+namespace {
+
+// Whether the throbber should be shown for a restored tab after it becomes
+// visible, instead of when it's active in the tab strip (this signal is known
+// to be broken crbug.com/413080225#comment8).
+BASE_FEATURE(kSessionRestoreShowThrobberOnVisible,
+             "SessionRestoreShowThrobberOnVisible",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace
+
 TabUIHelper::TabUIHelper(content::WebContents* contents)
     : WebContentsObserver(contents),
       content::WebContentsUserData<TabUIHelper>(*contents) {}
@@ -47,6 +59,12 @@
   return false;
 }
 
+void TabUIHelper::SetWasActiveAtLeastOnce() {
+  if (!base::FeatureList::IsEnabled(kSessionRestoreShowThrobberOnVisible)) {
+    was_active_at_least_once_ = true;
+  }
+}
+
 void TabUIHelper::DidStopLoading() {
   // Reset the properties after the initial navigation finishes loading, so that
   // latter navigations are not affected. Note that the prerendered page won't
@@ -54,4 +72,11 @@
   created_by_session_restore_ = false;
 }
 
+void TabUIHelper::OnVisibilityChanged(content::Visibility visiblity) {
+  if (base::FeatureList::IsEnabled(kSessionRestoreShowThrobberOnVisible) &&
+      visiblity == content::Visibility::VISIBLE) {
+    was_active_at_least_once_ = true;
+  }
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(TabUIHelper);
diff --git a/chrome/browser/ui/tab_ui_helper.h b/chrome/browser/ui/tab_ui_helper.h
index 50002cb..b7db8ed1 100644
--- a/chrome/browser/ui/tab_ui_helper.h
+++ b/chrome/browser/ui/tab_ui_helper.h
@@ -33,10 +33,12 @@
   // Return true if the throbber should be hidden during a page load.
   bool ShouldHideThrobber() const;
 
+  void SetWasActiveAtLeastOnce();
+
   // content::WebContentsObserver implementation
   void DidStopLoading() override;
+  void OnVisibilityChanged(content::Visibility visiblity) override;
 
-  void set_was_active_at_least_once() { was_active_at_least_once_ = true; }
   void set_created_by_session_restore(bool created_by_session_restore) {
     created_by_session_restore_ = created_by_session_restore;
   }
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc
index b0a7329..646370d 100644
--- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc
+++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc
@@ -106,3 +106,8 @@
     tabs_api::mojom::TabsObserver* observer) {
   observers_.RemoveObserver(observer);
 }
+
+void TabStripServiceImpl::Accept(
+    mojo::PendingReceiver<tabs_api::mojom::TabStripService> client) {
+  clients_.Add(this, std::move(client));
+}
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h
index f83dfe0d..1487da99 100644
--- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h
+++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h
@@ -10,6 +10,7 @@
 #include "base/observer_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 
 class BrowserWindowInterface;
 class TabStripModel;
@@ -29,6 +30,8 @@
   void AddObserver(tabs_api::mojom::TabsObserver* observer);
   void RemoveObserver(tabs_api::mojom::TabsObserver* observer);
 
+  void Accept(mojo::PendingReceiver<tabs_api::mojom::TabStripService> client);
+
   // tabs_api::mojom::TabStripService overrides
   void CreateTabAt(tabs_api::mojom::PositionPtr pos,
                    const std::optional<GURL>& url,
@@ -55,6 +58,7 @@
   // If usage expands to different threads, this needs to transition to
   // ObserverListThreadSafe.
   base::ObserverList<tabs_api::mojom::TabsObserver, true>::Unchecked observers_;
+  mojo::ReceiverSet<tabs_api::mojom::TabStripService> clients_;
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_API_TAB_STRIP_SERVICE_IMPL_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc
index 096e846..9428acb 100644
--- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc
@@ -40,26 +40,6 @@
   }
 };
 
-// Temporary scaffolding to link the mojo receiver with the impl. Once we
-// we figure out how clients will connect with the service, this scaffolding
-// should be removed.
-class ServiceBridge {
- public:
-  ServiceBridge(BrowserWindowInterface* browser, TabStripModel* model)
-      : impl_{browser, model} {}
-  ServiceBridge(const ServiceBridge&) = delete;
-  ServiceBridge operator=(const ServiceBridge&) = delete;
-  ~ServiceBridge() = default;
-
-  mojo::PendingRemote<tabs_api::mojom::TabStripService> GetRemote() {
-    return service_.BindNewPipeAndPassRemote();
-  }
-
- private:
-  mojo::Receiver<tabs_api::mojom::TabStripService> service_{&impl_};
-  MockTabStripServiceImpl impl_;
-};
-
 class TabStripServiceImplTest : public testing::Test {
  protected:
   TabStripServiceImplTest()
@@ -74,9 +54,9 @@
   ~TabStripServiceImplTest() override = default;
 
   void SetUp() override {
-    bridge_ = std::make_unique<ServiceBridge>(browser_window_interface(),
-                                              tab_strip_model());
-    client_.Bind(bridge_->GetRemote());
+    impl_ = std::make_unique<MockTabStripServiceImpl>(
+        browser_window_interface(), tab_strip_model());
+    impl_->Accept(client_.BindNewPipeAndPassReceiver());
   }
 
   TestingProfile* profile() { return profile_.get(); }
@@ -94,7 +74,7 @@
   std::unique_ptr<TestTabStripModelDelegate> delegate_;
   std::unique_ptr<TabStripModel> tab_strip_model_;
   std::unique_ptr<MockBrowserWindowInterface> browser_window_interface_;
-  std::unique_ptr<ServiceBridge> bridge_;
+  std::unique_ptr<TabStripServiceImpl> impl_;
 };
 
 TEST_F(TabStripServiceImplTest, CreateNewTab) {
diff --git a/chrome/browser/ui/toasts/api/toast_id.cc b/chrome/browser/ui/toasts/api/toast_id.cc
index 003bd3a0..086f6f8 100644
--- a/chrome/browser/ui/toasts/api/toast_id.cc
+++ b/chrome/browser/ui/toasts/api/toast_id.cc
@@ -38,6 +38,8 @@
       return "TabGroupSyncUserJoined";
     case ToastId::kTabGroupSyncRemovedFromGroup:
       return "TabGroupSyncRemovedFromGroup";
+    case ToastId::kVideoFrameCopied:
+      return "VideoFrameCopied";
   }
 
   NOTREACHED();
diff --git a/chrome/browser/ui/toasts/api/toast_id.h b/chrome/browser/ui/toasts/api/toast_id.h
index 6244d14..8e8905e 100644
--- a/chrome/browser/ui/toasts/api/toast_id.h
+++ b/chrome/browser/ui/toasts/api/toast_id.h
@@ -34,7 +34,8 @@
   kTabGroupSyncTabRemoved = 12,
   kTabGroupSyncUserJoined = 13,
   kTabGroupSyncRemovedFromGroup = 14,
-  kMaxValue = kTabGroupSyncRemovedFromGroup
+  kVideoFrameCopied = 15,
+  kMaxValue = kVideoFrameCopied
 };
 // LINT.ThenChange(/tools/metrics/histograms/metadata/toasts/enums.xml:ToastId)
 
diff --git a/chrome/browser/ui/toasts/toast_features.cc b/chrome/browser/ui/toasts/toast_features.cc
index 3db62e0..a6e6b345 100644
--- a/chrome/browser/ui/toasts/toast_features.cc
+++ b/chrome/browser/ui/toasts/toast_features.cc
@@ -41,6 +41,11 @@
              "ImageCopiedToast",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Enables the video frame copied confirmation toast.
+BASE_FEATURE(kVideoFrameCopiedToast,
+             "VideoFrameCopiedToast",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Enables the link to highlight copied confirmation toast.
 BASE_FEATURE(kLinkToHighlightCopiedToast,
              "LinkToHighlightCopiedToast",
diff --git a/chrome/browser/ui/toasts/toast_features.h b/chrome/browser/ui/toasts/toast_features.h
index 5902d1b..a2ba1d5 100644
--- a/chrome/browser/ui/toasts/toast_features.h
+++ b/chrome/browser/ui/toasts/toast_features.h
@@ -31,6 +31,7 @@
 // Individual toasts
 BASE_DECLARE_FEATURE(kLinkCopiedToast);
 BASE_DECLARE_FEATURE(kImageCopiedToast);
+BASE_DECLARE_FEATURE(kVideoFrameCopiedToast);
 BASE_DECLARE_FEATURE(kLinkToHighlightCopiedToast);
 BASE_DECLARE_FEATURE(kReadingListToast);
 BASE_DECLARE_FEATURE(kLensOverlayToast);
diff --git a/chrome/browser/ui/toasts/toast_service.cc b/chrome/browser/ui/toasts/toast_service.cc
index 2981643a..7018bad 100644
--- a/chrome/browser/ui/toasts/toast_service.cc
+++ b/chrome/browser/ui/toasts/toast_service.cc
@@ -67,6 +67,11 @@
       ToastId::kImageCopied,
       ToastSpecification::Builder(kCopyMenuIcon, IDS_IMAGE_COPIED_TOAST_BODY)
           .Build());
+  toast_registry_->RegisterToast(
+      ToastId::kVideoFrameCopied,
+      ToastSpecification::Builder(kCopyMenuIcon,
+                                  IDS_VIDEO_FRAME_COPIED_TOAST_BODY)
+          .Build());
 
   toast_registry_->RegisterToast(
       ToastId::kLinkToHighlightCopied,
diff --git a/chrome/browser/ui/toolbar/chrome_labs/chrome_labs_model.cc b/chrome/browser/ui/toolbar/chrome_labs/chrome_labs_model.cc
index 377dad8..9d144fe 100644
--- a/chrome/browser/ui/toolbar/chrome_labs/chrome_labs_model.cc
+++ b/chrome/browser/ui/toolbar/chrome_labs/chrome_labs_model.cc
@@ -41,23 +41,8 @@
   static const base::NoDestructor<std::vector<LabInfo>> lab_info_([]() {
     std::vector<LabInfo> lab_info;
 
-    // Tab Scrolling.
-    std::vector<std::u16string> tab_scrolling_variation_descriptions = {
-        l10n_util::GetStringUTF16(IDS_TABS_SHRINK_TO_PINNED_TAB_WIDTH),
-        l10n_util::GetStringUTF16(IDS_TABS_SHRINK_TO_MEDIUM_WIDTH),
-        l10n_util::GetStringUTF16(IDS_TABS_SHRINK_TO_LARGE_WIDTH),
-        l10n_util::GetStringUTF16(IDS_TABS_DO_NOT_SHRINK)};
-
-    lab_info.emplace_back(
-        flag_descriptions::kScrollableTabStripFlagId,
-        l10n_util::GetStringUTF16(IDS_TAB_SCROLLING_EXPERIMENT_NAME),
-        l10n_util::GetStringUTF16(IDS_TAB_SCROLLING_EXPERIMENT_DESCRIPTION),
-        "chrome-labs-tab-scrolling", version_info::Channel::BETA,
-        tab_scrolling_variation_descriptions);
-
     // Thumbnail Tab Strip for Windows.
-#if BUILDFLAG(ENABLE_WEBUI_TAB_STRIP) && \
-    (BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(ENABLE_WEBUI_TAB_STRIP) && BUILDFLAG(IS_WIN)
     lab_info.emplace_back(
         flag_descriptions::kWebUITabStripFlagId,
         l10n_util::GetStringUTF16(IDS_THUMBNAIL_TAB_STRIP_EXPERIMENT_NAME),
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.cc b/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.cc
index 8f42b68..06ecd721 100644
--- a/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.cc
+++ b/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.cc
@@ -447,23 +447,20 @@
           base::BindRepeating(
               &DownloadToolbarUIController::AutoClosePartialView,
               base::Unretained(this))) {
-  action_item_ =
-      actions::ActionManager::Get()
-          .FindAction(
-              kActionShowDownloads,
-              browser_view_->browser()->browser_actions()->root_action_item())
-          ->GetAsWeakPtr();
+  Browser* const browser = browser_view_->browser();
+  action_item_ = actions::ActionManager::Get()
+                     .FindAction(kActionShowDownloads,
+                                 browser->browser_actions()->root_action_item())
+                     ->GetAsWeakPtr();
   tooltip_texts_[0] = l10n_util::GetStringUTF16(IDS_TOOLTIP_DOWNLOAD_ICON);
   action_item_->SetTooltipText(tooltip_texts_.at(0));
 
-  bubble_controller_ =
-      std::make_unique<DownloadBubbleUIController>(browser_view_->browser());
+  bubble_controller_ = std::make_unique<DownloadBubbleUIController>(browser);
 
-  BrowserList::GetInstance()->AddObserver(this);
+  browser_list_observation_.Observe(BrowserList::GetInstance());
 }
 
 DownloadToolbarUIController::~DownloadToolbarUIController() {
-  BrowserList::GetInstance()->RemoveObserver(this);
   controller_.reset();
   bubble_controller_.reset();
 }
@@ -475,6 +472,11 @@
       this, browser_view_->browser(), bubble_controller_.get());
 }
 
+void DownloadToolbarUIController::TearDownPreBrowserViewDestruction() {
+  immersive_revealed_lock_.reset();
+  browser_view_ = nullptr;
+}
+
 void DownloadToolbarUIController::Show() {
   auto* container = GetPinnedToolbarActionsContainer(browser_view_);
   if (!container) {
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.h b/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.h
index 4986235..0039597 100644
--- a/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.h
+++ b/chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.h
@@ -8,8 +8,10 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "base/scoped_observation.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/download/download_ui_model.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/download/download_bubble_row_list_view_info.h"
 #include "chrome/browser/ui/download/download_display.h"
@@ -58,6 +60,7 @@
   // PinnedToolbarActionsContainer is available since the
   // DownloadDisplayController can call Show() immediately.
   void Init();
+  void TearDownPreBrowserViewDestruction();
 
   // DownloadDisplay:
   void Show() override;
@@ -240,6 +243,9 @@
 
   base::TimeTicks button_click_time_;
 
+  base::ScopedObservation<BrowserList, BrowserListObserver>
+      browser_list_observation_{this};
+
   // Maps number of in-progress downloads to the corresponding tooltip text, to
   // avoid having to create the strings repeatedly. The entry for 0 is the
   // default tooltip ("Downloads"), the entries for larger numbers are the
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
index c035bab..1477cb4 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
-#include "chrome/browser/ui/views/frame/scrim_view.h"
 #include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/profiles/profile_indicator_icon.h"
@@ -1052,11 +1051,6 @@
     caption_button_container_->layer()->SetIsFastRoundedCorner(/*enable=*/true);
   }
 
-  // Ensure that browser scrims match window rounding.
-  browser_view()->window_scrim_view()->SetRoundedCorners(window_radii);
-  browser_view()->contents_scrim_view()->SetRoundedCorners(gfx::RoundedCornersF(
-      0, 0, window_radii.lower_right(), window_radii.lower_left()));
-
   GetWidget()->client_view()->UpdateWindowRoundedCorners(window_radii);
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_view_ash.cc b/chrome/browser/ui/views/frame/browser_view_ash.cc
index 6ae33fd..74cbf45 100644
--- a/chrome/browser/ui/views/frame/browser_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_view_ash.cc
@@ -9,6 +9,7 @@
 #include "base/check.h"
 #include "chrome/browser/ui/sad_tab_helper.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/scrim_view.h"
 #include "chrome/browser/ui/views/sad_tab_view.h"
 #include "chrome/browser/ui/views/side_panel/side_panel.h"
 #include "ui/gfx/geometry/rounded_corners_f.h"
@@ -134,4 +135,9 @@
   if (contents_webview->GetBackgroundRadii() != contents_webview_radii) {
     contents_webview->SetBackgroundRadii(contents_webview_radii);
   }
+
+  // Ensure that browser scrims are rounded as well.
+  window_scrim_view()->SetRoundedCorners(window_radii);
+  contents_scrim_view()->SetRoundedCorners(contents_webview_radii);
+  devtools_scrim_view()->SetRoundedCorners(devtools_webview_radii);
 }
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index 39fc0f2..f13479e0 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -603,9 +603,13 @@
   int content_top = infobar_top + infobar_container_->height();
   infobar_top += delegate_->GetExtraInfobarOffset();
   SetViewVisibility(infobar_container_, IsInfobarVisible());
-  infobar_container_->SetBounds(
-      vertical_layout_rect_.x(), infobar_top, vertical_layout_rect_.width(),
-      infobar_container_->GetPreferredSize().height());
+  if (infobar_container_->GetVisible()) {
+    infobar_container_->SetBounds(
+        vertical_layout_rect_.x(), infobar_top, vertical_layout_rect_.width(),
+        infobar_container_->GetPreferredSize().height());
+  } else {
+    infobar_container_->SetBounds(vertical_layout_rect_.x(), infobar_top, 0, 0);
+  }
   return content_top;
 }
 
@@ -868,5 +872,7 @@
 }
 
 bool BrowserViewLayout::IsInfobarVisible() const {
-  return !infobar_container_->IsEmpty();
+  return !infobar_container_->IsEmpty() &&
+         (!browser_view_->IsFullscreen() ||
+          !infobar_container_->ShouldHideInFullscreen());
 }
diff --git a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
index 5a8bec0a..ccf2bba1 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
@@ -303,7 +303,7 @@
   // Top views are zero-height.
   EXPECT_EQ(gfx::Rect(0, 0, 0, 0), tab_strip()->bounds());
   EXPECT_EQ(gfx::Rect(0, 0, 800, 0), toolbar()->bounds());
-  EXPECT_EQ(gfx::Rect(0, 0, 800, 0), infobar_container()->bounds());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), infobar_container()->bounds());
   // Contents split fills the window.
   EXPECT_EQ(gfx::Rect(0, 0, 800, 600), contents_container()->bounds());
 
@@ -316,7 +316,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 800, kToolbarHeight), toolbar()->bounds());
   EXPECT_EQ(gfx::Rect(0, kToolbarHeight, 800, views::Separator::kThickness),
             separator()->bounds());
-  EXPECT_EQ(gfx::Rect(0, 30, 800, 0), infobar_container()->bounds());
+  EXPECT_EQ(gfx::Rect(0, 30, 0, 0), infobar_container()->bounds());
   EXPECT_EQ(gfx::Rect(0, 30, 800, 570), contents_container()->bounds());
 
   // Disable the contents separator.
@@ -327,7 +327,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 0, 0), tab_strip()->bounds());
   EXPECT_EQ(gfx::Rect(0, 0, 800, kToolbarHeight), toolbar()->bounds());
   EXPECT_FALSE(separator()->GetVisible());
-  EXPECT_EQ(gfx::Rect(0, 29, 800, 0), infobar_container()->bounds());
+  EXPECT_EQ(gfx::Rect(0, 29, 0, 0), infobar_container()->bounds());
   EXPECT_EQ(gfx::Rect(0, 29, 800, 571), contents_container()->bounds());
 
   // TODO(jamescook): Tab strip and bookmark bar.
diff --git a/chrome/browser/ui/views/frame/multi_contents_resize_area.cc b/chrome/browser/ui/views/frame/multi_contents_resize_area.cc
index dcbc60d..29d209a 100644
--- a/chrome/browser/ui/views/frame/multi_contents_resize_area.cc
+++ b/chrome/browser/ui/views/frame/multi_contents_resize_area.cc
@@ -87,6 +87,16 @@
   SetPreferredSize(gfx::Size(kHandleWidth + kHandlePadding, kHandleHeight));
 }
 
+void MultiContentsResizeArea::OnGestureEvent(ui::GestureEvent* event) {
+  // If the gesture event was a double tap and was not part of a resizing event,
+  // swap the contents views.
+  if (!is_resizing() && event->type() == ui::EventType::kGestureTap &&
+      event->details().tap_count() == 2) {
+    multi_contents_view_->OnSwap();
+  }
+  ResizeArea::OnGestureEvent(event);
+}
+
 void MultiContentsResizeArea::OnMouseReleased(const ui::MouseEvent& event) {
   // If the mouse event was a left double click and was not part of a resizing
   // event, swap the contents views.
diff --git a/chrome/browser/ui/views/frame/multi_contents_resize_area.h b/chrome/browser/ui/views/frame/multi_contents_resize_area.h
index fa291687..eab0b4d7 100644
--- a/chrome/browser/ui/views/frame/multi_contents_resize_area.h
+++ b/chrome/browser/ui/views/frame/multi_contents_resize_area.h
@@ -44,6 +44,7 @@
   explicit MultiContentsResizeArea(MultiContentsView* multi_contents_view);
 
   // views::ResizeArea:
+  void OnGestureEvent(ui::GestureEvent* event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   void OnMouseMoved(const ui::MouseEvent& event) override;
diff --git a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc
index d0eff8b..cbba3036 100644
--- a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc
@@ -293,7 +293,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest,
-                       ResizeDoubleClickSwapsSplitViews) {
+                       ResizeMouseDoubleClickSwapsSplitViews) {
   using MultiContentsViewSwapObserver =
       views::test::PollingViewObserver<bool, MultiContentsView>;
   DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(MultiContentsViewSwapObserver,
@@ -353,3 +353,59 @@
       WaitForState(kMultiContentsViewSwapObserver, true), CheckTabIsActive(1),
       CheckActiveContentsHasFocus());
 }
+
+IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest,
+                       ResizeGestureDoubleTapSwapsSplitViews) {
+  using MultiContentsViewSwapObserver =
+      views::test::PollingViewObserver<bool, MultiContentsView>;
+  DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(MultiContentsViewSwapObserver,
+                                      kMultiContentsViewSwapObserver);
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kWebContentsId);
+  RunTestSequence(
+      // Create a split view with and verify web contents are as expected and
+      // the active index is correct.
+      InstrumentTab(kWebContentsId),
+      NavigateWebContents(kWebContentsId, GURL(chrome::kChromeUINewTabURL)),
+      CreateTabsAndEnterSplitView(), Check([&]() {
+        return multi_contents_view()
+                   ->start_contents_view_for_testing()
+                   ->GetWebContents()
+                   ->GetVisibleURL() == GURL(chrome::kChromeUISettingsURL);
+      }),
+      Check([&]() {
+        return multi_contents_view()
+                   ->end_contents_view_for_testing()
+                   ->GetWebContents()
+                   ->GetVisibleURL() == GURL(chrome::kChromeUINewTabURL);
+      }),
+      CheckResult([this]() { return tab_strip_model()->active_index(); }, 0),
+      // Simulate a double press gesture event on the resize area to trigger the
+      // split tabs to swap.
+      Do([&]() {
+        auto* resize_area = multi_contents_view()->resize_area_for_testing();
+        gfx::Point center(resize_area->width() / 2, resize_area->height() / 2);
+        ui::GestureEventDetails details(ui::EventType::kGestureTap);
+        details.set_tap_count(2);
+        ui::GestureEvent gesture_event(center.x(), center.y(), ui::EF_NONE,
+                                       ui::EventTimeForNow(), details);
+        resize_area->OnGestureEvent(&gesture_event);
+      }),
+      // Verify the web contents in the split have swapped and the active index
+      // is correct.
+      PollView(kMultiContentsViewSwapObserver,
+               MultiContentsView::kMultiContentsViewElementId,
+               [&](const MultiContentsView* multi_contents_view) -> bool {
+                 bool first_web_contents_set =
+                     multi_contents_view->start_contents_view_for_testing()
+                         ->GetWebContents()
+                         ->GetVisibleURL() == GURL(chrome::kChromeUINewTabURL);
+                 bool second_web_contents_set =
+                     multi_contents_view->end_contents_view_for_testing()
+                         ->GetWebContents()
+                         ->GetVisibleURL() ==
+                     GURL(chrome::kChromeUISettingsURL);
+                 return first_web_contents_set && second_web_contents_set;
+               }),
+      WaitForState(kMultiContentsViewSwapObserver, true), CheckTabIsActive(1),
+      CheckActiveContentsHasFocus());
+}
diff --git a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
index 1085003..1c30afe 100644
--- a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
+++ b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
@@ -97,6 +97,7 @@
     return true;
   }
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
index 2139be8..752ff85 100644
--- a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/controls/rich_hover_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_details_view.h"
@@ -57,6 +58,7 @@
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/test/views_test_utils.h"
 #include "ui/views/test/widget_test.h"
+#include "ui/views/window/dialog_client_view.h"
 
 using base::Bucket;
 using net::test_server::BasicHttpResponse;
@@ -1342,3 +1344,43 @@
   RunTestSequence(Do(setup_shared_passwords),
                   EnsureNotPresent(SharedPasswordsNotificationView::kTopView));
 }
+
+IN_PROC_BROWSER_TEST_F(PasswordBubbleInteractiveUiTest, ClickNever) {
+  SetupPendingPassword();
+  const auto button = views::DialogClientView::kCancelButtonElementId;
+  RunTestSequence(PressButton(button), WaitForHide(button),
+                  CheckHistogramUniqueSample(
+                      "PasswordManager.SaveUIDismissalReason",
+                      password_manager::metrics_util::CLICKED_NEVER, 1));
+}
+class ThreeButtonPasswordBubbleInteractiveUiTest
+    : public PasswordBubbleInteractiveUiTest {
+ public:
+  ThreeButtonPasswordBubbleInteractiveUiTest() {
+    scoped_feature_list_.InitWithFeatureState(
+        features::kThreeButtonPasswordSaveDialog, true);
+  }
+  ~ThreeButtonPasswordBubbleInteractiveUiTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(ThreeButtonPasswordBubbleInteractiveUiTest,
+                       ClickNotNow) {
+  SetupPendingPassword();
+  const auto button = views::DialogClientView::kCancelButtonElementId;
+  RunTestSequence(PressButton(button), WaitForHide(button),
+                  CheckHistogramUniqueSample(
+                      "PasswordManager.SaveUIDismissalReason",
+                      password_manager::metrics_util::CLICKED_NOT_NOW, 1));
+}
+
+IN_PROC_BROWSER_TEST_F(ThreeButtonPasswordBubbleInteractiveUiTest, ClickNever) {
+  SetupPendingPassword();
+  const auto button = PasswordSaveUpdateView::kExtraButtonElementId;
+  RunTestSequence(PressButton(button), WaitForHide(button),
+                  CheckHistogramUniqueSample(
+                      "PasswordManager.SaveUIDismissalReason",
+                      password_manager::metrics_util::CLICKED_NEVER, 1));
+}
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.cc b/chrome/browser/ui/views/passwords/password_save_update_view.cc
index 31eb552ff..ad68ce2 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_view.cc
+++ b/chrome/browser/ui/views/passwords/password_save_update_view.cc
@@ -141,6 +141,8 @@
     if (base::FeatureList::IsEnabled(
             features::kThreeButtonPasswordSaveDialog)) {
       extra_view_ = SetExtraView(std::make_unique<views::MdTextButton>());
+      extra_view_->SetProperty(views::kElementIdentifierKey,
+                               kExtraButtonElementId);
     }
   }
 
@@ -241,7 +243,7 @@
   AnnounceBubbleChange();
 
   GetBubbleFrameView()->SetProperty(views::kElementIdentifierKey,
-                                    kPasswordBubble);
+                                    kPasswordBubbleElementId);
 
   return false;
 #else
@@ -442,4 +444,7 @@
 BEGIN_METADATA(PasswordSaveUpdateView)
 END_METADATA
 
-DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PasswordSaveUpdateView, kPasswordBubble);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PasswordSaveUpdateView,
+                                      kPasswordBubbleElementId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PasswordSaveUpdateView,
+                                      kExtraButtonElementId);
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.h b/chrome/browser/ui/views/passwords/password_save_update_view.h
index 9a1ddfc..ecdcac5 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_view.h
+++ b/chrome/browser/ui/views/passwords/password_save_update_view.h
@@ -28,7 +28,8 @@
   METADATA_HEADER(PasswordSaveUpdateView, PasswordBubbleViewBase)
 
  public:
-  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPasswordBubble);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPasswordBubbleElementId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kExtraButtonElementId);
 
   PasswordSaveUpdateView(content::WebContents* web_contents,
                          views::View* anchor_view,
diff --git a/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc b/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc
index 8062943b..6d18ea9 100644
--- a/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc
+++ b/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc
@@ -631,8 +631,16 @@
 
 // Memory Saver Dialog bubble's cancel button's state should be preserved
 // for that tab even when navigating to another tab.
+// TODO(crbug.com/415992663): Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_CancelButtonStatePreservedWhenSwitchingTabs \
+  DISABLED_CancelButtonStatePreservedWhenSwitchingTabs
+#else
+#define MAYBE_CancelButtonStatePreservedWhenSwitchingTabs \
+  CancelButtonStatePreservedWhenSwitchingTabs
+#endif
 IN_PROC_BROWSER_TEST_P(MemorySaverChipInteractiveTest,
-                       CancelButtonStatePreservedWhenSwitchingTabs) {
+                       MAYBE_CancelButtonStatePreservedWhenSwitchingTabs) {
   RunTestSequence(
       InstrumentTab(kFirstTabContents, 0),
       NavigateWebContents(kFirstTabContents, GetURL("a.test", "/title1.html")),
diff --git a/chrome/browser/ui/views/plus_addresses/DEPS b/chrome/browser/ui/views/plus_addresses/DEPS
deleted file mode 100644
index 52fb1865..0000000
--- a/chrome/browser/ui/views/plus_addresses/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+components/plus_addresses",
-]
diff --git a/chrome/browser/ui/views/plus_addresses/DIR_METADATA b/chrome/browser/ui/views/plus_addresses/DIR_METADATA
deleted file mode 100644
index a8bf562e..0000000
--- a/chrome/browser/ui/views/plus_addresses/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-mixins: "//components/plus_addresses/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/plus_addresses/OWNERS b/chrome/browser/ui/views/plus_addresses/OWNERS
deleted file mode 100644
index 82cf094..0000000
--- a/chrome/browser/ui/views/plus_addresses/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/plus_addresses/OWNERS
diff --git a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc
index 25f4f18..065c825 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc
@@ -81,7 +81,7 @@
   // called yet).
   if (callback_) {
     if (IsInitialized()) {
-      contents()->SetDelegate(nullptr);
+      ResetWebContentsDelegates();
     }
 
     ProfileMetrics::LogProfileAddSignInFlowOutcome(
@@ -306,7 +306,7 @@
     const CoreAccountInfo& account_info) {
   DCHECK(IsInitialized());
   host_->SetNativeToolbarVisible(false);
-  contents()->SetDelegate(nullptr);
+  ResetWebContentsDelegates();
   std::move(callback_).Run(profile_.get(), account_info, std::move(contents_));
 }
 
@@ -320,6 +320,12 @@
   FinishFlow(account_info);
 }
 
+void ProfilePickerDiceSignInProvider::ResetWebContentsDelegates() {
+  contents()->SetDelegate(nullptr);
+  web_modal::WebContentsModalDialogManager::FromWebContents(contents())
+      ->SetDelegate(nullptr);
+}
+
 GURL ProfilePickerDiceSignInProvider::BuildSigninURL() const {
   // Use the Emebedded flow if we are in the context of ForceSignin.
   signin::Flow signin_flow = signin_util::IsForceSigninEnabled()
diff --git a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h
index 8be7a07..b50c0e41 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h
+++ b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h
@@ -119,6 +119,8 @@
 
   void OnSignInContentsFreedUp();
 
+  void ResetWebContentsDelegates();
+
   GURL BuildSigninURL() const;
 
   // The sync confirmation screen is triggered by the `DiceTabHelper`. This can
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h
index e2574cc..aa3dcda6 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h
@@ -106,7 +106,7 @@
  private:
   using InfoBars = std::map<content::WebContents*,
                             raw_ptr<infobars::InfoBar, CtnExperimental>>;
-  friend class TabSharingUIViewsBrowserTest;
+  friend class TabSharingUIViewsBrowserTestBase;
 
   // Used to identify |TabSharingUIViews| instances to
   // |TabCaptureContentsBorderHelper|, without passing pointers,
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
index 36df2576..ddcb8261 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
@@ -47,6 +47,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image_unittest_util.h"
+#include "ui/views/controls/button/button_controller.h"
 #include "ui/views/widget/widget.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -106,6 +107,20 @@
   NOTREACHED();
 }
 
+std::vector<views::MdTextButton*> GetMessageLinks(Browser* browser, int tab) {
+  const views::View& status_message_view =
+      *GetInfoBar(browser, tab)->GetStatusMessageViewForTesting();
+  CHECK_EQ(status_message_view.GetClassName(), "TabSharingStatusMessageView");
+
+  std::vector<views::MdTextButton*> buttons;
+  for (views::View* child_view : status_message_view.children()) {
+    if (child_view->GetClassName() == "MdTextButton") {
+      buttons.emplace_back(static_cast<views::MdTextButton*>(child_view));
+    }
+  }
+  return buttons;
+}
+
 bool HasShareThisTabInsteadButton(Browser* browser, int tab) {
   return GetDelegate(browser, tab)->GetButtons() &
          TabSharingInfoBarButton::kShareThisTabInstead;
@@ -197,6 +212,11 @@
   base::RunLoop().RunUntilIdle();
 }
 
+bool IsActive(Browser* browser, int tab) {
+  return browser->tab_strip_model()->GetActiveWebContents() ==
+         GetWebContents(browser, tab);
+}
+
 constexpr int kNullTabIndex = -1;
 const std::u16string kShareThisTabInsteadMessage = u"Share this tab instead";
 const std::u16string kViewTabMessage = u"View tab:";
@@ -210,12 +230,15 @@
 
 }  // namespace
 
-class TabSharingUIViewsBrowserTest
-    : public InProcessBrowserTest,
-      public ::testing::WithParamInterface<bool> {
+class TabSharingUIViewsBrowserTestBase : public InProcessBrowserTest {
  public:
-  TabSharingUIViewsBrowserTest()
-      : enable_tab_capture_infobar_links_(GetParam()) {
+  struct Features {
+    bool enable_tab_capture_infobar_links;
+  };
+
+  explicit TabSharingUIViewsBrowserTestBase(Features features)
+      : enable_tab_capture_infobar_links_(
+            features.enable_tab_capture_infobar_links) {
     // TODO(crbug.com/40248833): Use HTTPS URLs in tests to avoid having to
     // disable kHttpsUpgrades feature.
 #if BUILDFLAG(IS_CHROMEOS)
@@ -251,16 +274,17 @@
     // Explicitly activate the shared tab in testing.
     ActivateTab(browser, captured_tab);
 
-    tab_sharing_ui_ = TabSharingUI::Create(
-        GetGlobalId(browser, capturing_tab),
-        GetDesktopMediaID(browser, captured_tab), u"example-sharing.com",
-        /*app_preferred_current_tab=*/false,
-        TabSharingInfoBarDelegate::TabShareType::CAPTURE,
-        /*captured_surface_control_active=*/false);
+    tab_sharing_ui_ =
+        TabSharingUI::Create(GetGlobalId(browser, capturing_tab),
+                             GetDesktopMediaID(browser, captured_tab),
+                             /*capturer_name=*/u"capturer.com",
+                             /*app_preferred_current_tab=*/false,
+                             TabSharingInfoBarDelegate::TabShareType::CAPTURE,
+                             /*captured_surface_control_active=*/false);
 
     tab_sharing_ui_->OnStarted(
         base::OnceClosure(),
-        base::BindRepeating(&TabSharingUIViewsBrowserTest::OnSourceChange,
+        base::BindRepeating(&TabSharingUIViewsBrowserTestBase::OnSourceChange,
                             base::Unretained(this)),
         std::vector<content::DesktopMediaID>{});
 
@@ -359,12 +383,15 @@
     }
   }
 
+  void AddTab(Browser* browser, const GURL& url) {
+    const int next_index = browser->tab_strip_model()->count();
+    ASSERT_TRUE(AddTabAtIndexToBrowser(browser, next_index, url,
+                                       ui::PAGE_TRANSITION_LINK, true));
+  }
+
   void AddTabs(Browser* browser, int tab_count) {
     for (int i = 0; i < tab_count; ++i) {
-      const int next_index = browser->tab_strip_model()->count();
-      ASSERT_TRUE(AddTabAtIndexToBrowser(browser, next_index,
-                                         GURL(chrome::kChromeUINewTabURL),
-                                         ui::PAGE_TRANSITION_LINK, true));
+      AddTab(browser, GURL(chrome::kChromeUINewTabURL));
     }
 
     base::RunLoop().RunUntilIdle();
@@ -393,6 +420,15 @@
   std::unique_ptr<TabSharingUI> tab_sharing_ui_;
 };
 
+class TabSharingUIViewsBrowserTest
+    : public TabSharingUIViewsBrowserTestBase,
+      public ::testing::WithParamInterface<bool> {
+ public:
+  TabSharingUIViewsBrowserTest()
+      : TabSharingUIViewsBrowserTestBase(
+            {.enable_tab_capture_infobar_links = GetParam()}) {}
+};
+
 INSTANTIATE_TEST_SUITE_P(All, TabSharingUIViewsBrowserTest, testing::Bool());
 
 IN_PROC_BROWSER_TEST_P(TabSharingUIViewsBrowserTest, StartSharing) {
@@ -741,6 +777,99 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
+class TabSharingMessageLinksBrowserTest
+    : public TabSharingUIViewsBrowserTestBase,
+      public ::testing::WithParamInterface<bool> {
+ public:
+  TabSharingMessageLinksBrowserTest()
+      : TabSharingUIViewsBrowserTestBase(
+            {.enable_tab_capture_infobar_links = true}) {}
+
+  void SetUpOnMainThread() override {
+    TabSharingUIViewsBrowserTestBase::SetUpOnMainThread();
+    // The existing initial tab is used for the capturer. Two new tabs are added
+    // for the capturee and a third-party tab.
+    AddTab(browser(), kCapturedTabUrl);
+    AddTab(browser(), kOtherTabUrl);
+    ASSERT_EQ(browser()->tab_strip_model()->count(), 3);
+  }
+
+ protected:
+  const int kCapturingTab = 0;
+  const int kCapturedTab = 1;
+  const int kOtherTab = 2;
+  const GURL kCapturedTabUrl = GURL(chrome::kChromeUINewTabURL);
+  const GURL kOtherTabUrl = GURL(chrome::kChromeUIAboutURL);
+  const std::string kCapturingTabLinkText = "capturer.com";
+  const std::string kCapturedTabLinkText = "chrome://new-tab-page";
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+                         TabSharingMessageLinksBrowserTest,
+                         ::testing::Bool());
+
+IN_PROC_BROWSER_TEST_P(TabSharingMessageLinksBrowserTest,
+                       ClickingOnLinkInCapturingTabActivatesCapturedTab) {
+  CreateUiAndStartSharing(browser(), kCapturingTab, kCapturedTab);
+  ActivateTab(browser(), kCapturingTab);
+
+  std::vector<views::MdTextButton*> links =
+      GetMessageLinks(browser(), /*tab=*/kCapturingTab);
+  ASSERT_EQ(links.size(), 1u);
+  EXPECT_EQ(base::UTF16ToUTF8(links[0]->GetText()), kCapturedTabLinkText);
+
+  EXPECT_TRUE(IsActive(browser(), kCapturingTab));
+  links[0]->button_controller()->NotifyClick();
+  EXPECT_TRUE(IsActive(browser(), kCapturedTab));
+}
+
+IN_PROC_BROWSER_TEST_P(TabSharingMessageLinksBrowserTest,
+                       ClickingOnLinkInCapturedTabActivatesCapturingTab) {
+  CreateUiAndStartSharing(browser(), kCapturingTab, kCapturedTab);
+  ActivateTab(browser(), kCapturedTab);
+
+  std::vector<views::MdTextButton*> links =
+      GetMessageLinks(browser(), /*tab=*/kCapturedTab);
+  ASSERT_EQ(links.size(), 1u);
+  EXPECT_EQ(base::UTF16ToUTF8(links[0]->GetText()), kCapturingTabLinkText);
+
+  EXPECT_TRUE(IsActive(browser(), kCapturedTab));
+  links[0]->button_controller()->NotifyClick();
+  EXPECT_TRUE(IsActive(browser(), kCapturingTab));
+}
+
+IN_PROC_BROWSER_TEST_P(TabSharingMessageLinksBrowserTest,
+                       ClickingOnCaptureeLinkInOtherTabActivatesCapturedTab) {
+  CreateUiAndStartSharing(browser(), kCapturingTab, kCapturedTab);
+  ActivateTab(browser(), kOtherTab);
+
+  std::vector<views::MdTextButton*> links =
+      GetMessageLinks(browser(), /*tab=*/kOtherTab);
+  ASSERT_EQ(links.size(), 2u);
+  EXPECT_EQ(base::UTF16ToUTF8(links[0]->GetText()), kCapturedTabLinkText);
+  EXPECT_EQ(base::UTF16ToUTF8(links[1]->GetText()), kCapturingTabLinkText);
+
+  EXPECT_TRUE(IsActive(browser(), kOtherTab));
+  links[0]->button_controller()->NotifyClick();
+  EXPECT_TRUE(IsActive(browser(), kCapturedTab));
+}
+
+IN_PROC_BROWSER_TEST_P(TabSharingMessageLinksBrowserTest,
+                       ClickingOnCapturerLinkInOtherTabActivatesCapturingTab) {
+  CreateUiAndStartSharing(browser(), kCapturingTab, kCapturedTab);
+  ActivateTab(browser(), kOtherTab);
+
+  std::vector<views::MdTextButton*> links =
+      GetMessageLinks(browser(), /*tab=*/kOtherTab);
+  ASSERT_EQ(links.size(), 2u);
+  EXPECT_EQ(base::UTF16ToUTF8(links[0]->GetText()), kCapturedTabLinkText);
+  EXPECT_EQ(base::UTF16ToUTF8(links[1]->GetText()), kCapturingTabLinkText);
+
+  EXPECT_TRUE(IsActive(browser(), kOtherTab));
+  links[1]->button_controller()->NotifyClick();
+  EXPECT_TRUE(IsActive(browser(), kCapturingTab));
+}
+
 class MultipleTabSharingUIViewsBrowserTest : public InProcessBrowserTest {
  public:
 #if BUILDFLAG(IS_CHROMEOS)
@@ -762,7 +891,7 @@
       ActivateTab(browser, captured_tab);
       tab_sharing_ui_views_.push_back(TabSharingUI::Create(
           GetGlobalId(browser, capturing_tab),
-          GetDesktopMediaID(browser, captured_tab), u"example-sharing.com",
+          GetDesktopMediaID(browser, captured_tab), u"capturer.com",
           /*app_preferred_current_tab=*/false,
           TabSharingInfoBarDelegate::TabShareType::CAPTURE,
           /*captured_surface_control_active=*/false));
@@ -1014,7 +1143,7 @@
     ActivateTab(browser(), kTab0);
     tab_sharing_ui_views_ = TabSharingUI::Create(
         GetGlobalId(browser(), kTab0),
-        GetDesktopMediaID(browser(), captured_tab), u"example-sharing.com",
+        GetDesktopMediaID(browser(), captured_tab), u"capturer.com",
         /*app_preferred_current_tab=*/true,
         TabSharingInfoBarDelegate::TabShareType::CAPTURE,
         /*captured_surface_control_active=*/false);
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 9dbbcc6..0e70124a 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -831,8 +831,7 @@
     content::WebContents* new_contents = selection.new_contents;
     std::optional<size_t> index = selection.new_model.active();
     if (new_contents && index.has_value()) {
-      TabUIHelper::FromWebContents(new_contents)
-          ->set_was_active_at_least_once();
+      TabUIHelper::FromWebContents(new_contents)->SetWasActiveAtLeastOnce();
       SetTabDataAt(new_contents, index.value());
     }
   }
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
index f693ba94..f67a951 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
@@ -8,6 +8,7 @@
 #include <optional>
 
 #include "base/callback_list.h"
+#include "base/check.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
@@ -263,6 +264,8 @@
       target_tab_observation_.Observe(tab);
     }
     target_tab_ = tab;
+    DUMP_WILL_BE_CHECK(!in_show_hover_card_)
+        << "Changing target tab to " << (tab ? "non-null" : "null");
   }
 
   // If there's nothing to attach to then there's no point in creating a card.
@@ -395,15 +398,17 @@
   // For some reason, `target_tab_` can be rendered invalid before the next
   // call. There may be an asynchronous operation buried deep within
   // CreateHoverCard() above. Regardless, the validity needs to be checked
-  // before the next call.
+  // before the next call. Note that this check helps, but isn't sufficient,
+  // as subsequent calls are also vulnerable.
   // See: crbug.com/1295601, crbug.com/1322117, crbug.com/1348956
-  // TODO(crbug.com/40865488): look into this and figure out what is actually
-  // happening.
   if (!TargetTabIsValid()) {
     HideHoverCard();
     return;
   }
 
+  // TODO(crbug.com/40865488): See below. Remove this after crash diagnosis.
+  base::AutoReset<bool> auto_resetter(&in_show_hover_card_, true);
+
   UpdateCardContent(target_tab_);
   slide_animator_->UpdateTargetBounds();
   MaybeStartThumbnailObservation(target_tab_, is_initial);
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller.h b/chrome/browser/ui/views/tabs/tab_hover_card_controller.h
index 9213fdb..93b757af 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller.h
@@ -185,6 +185,9 @@
   bool hover_card_image_previews_enabled_ = false;
   bool hover_card_memory_usage_enabled_ = false;
 
+  // TODO(crbug.com/40865488): Remove after diagnosing crashes.
+  bool in_show_hover_card_ = false;
+
   // Ensure that this timer is destroyed before anything else is cleaned up.
   base::OneShotTimer delayed_show_timer_;
   base::WeakPtrFactory<TabHoverCardController> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/views/tabs/tab_strip_layout.cc b/chrome/browser/ui/views/tabs/tab_strip_layout.cc
index 94f16c5d..6e6ccbb86 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_layout.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_layout.cc
@@ -94,6 +94,11 @@
   if (space_fraction_available_ == 0.0f || space_fraction_available_ == 1.0f) {
     return false;
   }
+  // To avoid the two halves of a split being different widths and having
+  // inconsistent rendering of favicons, don't accept extra space.
+  if (tab.get_state().split().has_value()) {
+    return false;
+  }
   switch (domain_) {
     case LayoutDomain::kInactiveWidthBelowActiveWidth:
       return tab.GetMinimumWidth() < tab.GetLayoutCrossoverWidth();
@@ -120,24 +125,14 @@
     return;
   }
 
-  // Extra space will only be given to the first tab in a split encountered.
-  std::set<split_tabs::SplitTabId> splits_with_extra_space;
-
   int allocated_extra_space = 0;
   for (size_t i = 0; i < tabs.size(); i++) {
     const TabWidthConstraints& tab = tabs[i];
     bounds->at(i).set_x(bounds->at(i).x() + allocated_extra_space);
-    std::optional<split_tabs::SplitTabId> split_id = tab.get_state().split();
     if (allocated_extra_space < extra_space &&
-        tab_sizer.TabAcceptsExtraSpace(tab) &&
-        (!split_id.has_value() ||
-         !splits_with_extra_space.contains(split_id.value()))) {
+        tab_sizer.TabAcceptsExtraSpace(tab)) {
       allocated_extra_space++;
       bounds->at(i).set_width(bounds->at(i).width() + 1);
-
-      if (split_id.has_value()) {
-        splits_with_extra_space.emplace(split_id.value());
-      }
     }
   }
 }
diff --git a/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc
index c104b3a..87929c04 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc
@@ -96,6 +96,21 @@
   return CalculateTabBounds(tab_states, test_case.tabstrip_width);
 }
 
+void ExpectTabsNarrowerThanTabStrip(const std::vector<gfx::Rect>& bounds,
+                                    int tabstrip_width) {
+  EXPECT_LT(bounds.back().right(), tabstrip_width);
+}
+
+void ExpectTabsFillTabStrip(const std::vector<gfx::Rect>& bounds,
+                            int tabstrip_width) {
+  EXPECT_EQ(bounds.back().right(), tabstrip_width);
+}
+
+void ExpectTabsWiderThanTabStrip(const std::vector<gfx::Rect>& bounds,
+                                 int tabstrip_width) {
+  EXPECT_GT(bounds.back().right(), tabstrip_width);
+}
+
 }  // namespace
 
 // These tests verify that layout behaves correctly in various situations. In
@@ -120,6 +135,7 @@
     EXPECT_EQ(0, b.y());
     EXPECT_EQ(kTabHeight, b.height());
   }
+  ExpectTabsNarrowerThanTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, AllPinnedTabs) {
@@ -130,6 +146,7 @@
   auto bounds = CalculateTabBounds(test_case);
   EXPECT_EQ("64 64 64", TabWidthsAsString(bounds));
   EXPECT_EQ("0 46 92", TabXPositionsAsString(bounds));
+  ExpectTabsNarrowerThanTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, MixedPinnedAndNormalTabs) {
@@ -141,6 +158,7 @@
   auto bounds = CalculateTabBounds(test_case);
   EXPECT_EQ("64 256 256", TabWidthsAsString(bounds));
   EXPECT_EQ("0 46 284", TabXPositionsAsString(bounds));
+  ExpectTabsNarrowerThanTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, MiddleWidth) {
@@ -151,6 +169,7 @@
   auto bounds = CalculateTabBounds(test_case);
   EXPECT_EQ("163 163 163 163", TabWidthsAsString(bounds));
   EXPECT_EQ("0 145 290 435", TabXPositionsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, MiddleWidthAndPinnedTab) {
@@ -162,6 +181,7 @@
   auto bounds = CalculateTabBounds(test_case);
   EXPECT_EQ("64 186 186", TabWidthsAsString(bounds));
   EXPECT_EQ("0 46 214", TabXPositionsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, MiddleWidthRounded) {
@@ -172,6 +192,7 @@
   auto bounds = CalculateTabBounds(test_case);
   EXPECT_EQ("164 164 163 163", TabWidthsAsString(bounds));
   EXPECT_EQ("0 146 292 437", TabXPositionsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, MiddleWidthRoundedAndPinnedTab) {
@@ -183,6 +204,7 @@
   auto bounds = CalculateTabBounds(test_case);
   EXPECT_EQ("64 187 186", TabWidthsAsString(bounds));
   EXPECT_EQ("0 46 215", TabXPositionsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, MiddleWidthRoundedAndSplitTab) {
@@ -192,17 +214,20 @@
   test_case.split_tabs = {0, 1};
 
   auto bounds = CalculateTabBounds(test_case);
-  EXPECT_EQ("116 115 213 212", TabWidthsAsString(bounds));
+  EXPECT_EQ("115 115 213 213", TabWidthsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
-TEST(TabStripLayoutTest, BelowMinActiveWidthOneTab) {
+TEST(TabStripLayoutTest, MiddleWidthAndMinWidthSplitTab) {
   TestCase test_case;
-  test_case.tabstrip_width = 15;
-  test_case.num_tabs = 1;
+  test_case.tabstrip_width = 138;
+  test_case.num_tabs = 4;
+  test_case.split_tabs = {0, 1};
+  test_case.active_index = 2;
 
   auto bounds = CalculateTabBounds(test_case);
-  EXPECT_EQ("56", TabWidthsAsString(bounds));
-  EXPECT_EQ("0", TabXPositionsAsString(bounds));
+  EXPECT_EQ("38 38 58 58", TabWidthsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, BelowMinActiveWidth) {
@@ -214,6 +239,7 @@
   auto bounds = CalculateTabBounds(test_case);
   EXPECT_EQ("46 46 46 56 46 46", TabWidthsAsString(bounds));
   EXPECT_EQ("0 28 56 84 122 150", TabXPositionsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, BelowMinActiveWidthRounded) {
@@ -222,8 +248,9 @@
   test_case.num_tabs = 6;
   test_case.active_index = 3;
 
-  EXPECT_EQ("47 47 47 56 47 46",
-            TabWidthsAsString(CalculateTabBounds(test_case)));
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("47 47 47 56 47 46", TabWidthsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, BelowMinActiveWidthActivePinnedTab) {
@@ -232,8 +259,9 @@
   test_case.num_tabs = 6;
   test_case.num_pinned_tabs = 1;
 
-  EXPECT_EQ("64 55 55 55 55 55",
-            TabWidthsAsString(CalculateTabBounds(test_case)));
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("64 55 55 55 55 55", TabWidthsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, BelowMinActiveWidthInactivePinnedTab) {
@@ -243,8 +271,9 @@
   test_case.num_pinned_tabs = 1;
   test_case.active_index = 2;
 
-  EXPECT_EQ("64 55 56 55 55 55",
-            TabWidthsAsString(CalculateTabBounds(test_case)));
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("64 55 56 55 55 55", TabWidthsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, BelowMinActiveWidthActivePinnedTabRounded) {
@@ -253,8 +282,23 @@
   test_case.num_tabs = 6;
   test_case.num_pinned_tabs = 1;
 
-  EXPECT_EQ("64 56 55 55 55 55",
-            TabWidthsAsString(CalculateTabBounds(test_case)));
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("64 56 55 55 55 55", TabWidthsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
+}
+
+TEST(TabStripLayoutTest, BelowMinActiveWidthSplitTab) {
+  TestCase test_case;
+  test_case.tabstrip_width = 200;
+  test_case.num_tabs = 6;
+  test_case.split_tabs = {0, 1};
+  test_case.active_index = 2;
+
+  // Can't avoid rounding with split tabs unless there is a large number of tabs
+  // because regular tabs grow faster.
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("36 36 56 54 54 54", TabWidthsAsString(bounds));
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, NotEnoughSpace) {
@@ -262,7 +306,20 @@
   test_case.tabstrip_width = 10;
   test_case.num_tabs = 3;
 
-  EXPECT_EQ("56 32 32", TabWidthsAsString(CalculateTabBounds(test_case)));
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("56 32 32", TabWidthsAsString(bounds));
+  ExpectTabsWiderThanTabStrip(bounds, test_case.tabstrip_width);
+}
+
+TEST(TabStripLayoutTest, NotEnoughSpaceOneTab) {
+  TestCase test_case;
+  test_case.tabstrip_width = 15;
+  test_case.num_tabs = 1;
+
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("56", TabWidthsAsString(bounds));
+  EXPECT_EQ("0", TabXPositionsAsString(bounds));
+  ExpectTabsWiderThanTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, NotEnoughSpaceAllPinnedTabs) {
@@ -271,7 +328,9 @@
   test_case.num_tabs = 3;
   test_case.num_pinned_tabs = 3;
 
-  EXPECT_EQ("64 64 64", TabWidthsAsString(CalculateTabBounds(test_case)));
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("64 64 64", TabWidthsAsString(bounds));
+  ExpectTabsWiderThanTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, NotEnoughSpaceMixedPinnedAndNormalTabs) {
@@ -280,7 +339,9 @@
   test_case.num_tabs = 3;
   test_case.num_pinned_tabs = 1;
 
-  EXPECT_EQ("64 32 32", TabWidthsAsString(CalculateTabBounds(test_case)));
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("64 32 32", TabWidthsAsString(bounds));
+  ExpectTabsWiderThanTabStrip(bounds, test_case.tabstrip_width);
 }
 
 TEST(TabStripLayoutTest, ExactlyEnoughSpaceAllPinnedTabs) {
@@ -297,5 +358,5 @@
 
   // Validate that the tabstrip width is indeeed exactly enough to hold two
   // pinned tabs.
-  EXPECT_EQ(test_case.tabstrip_width, bounds[1].right());
+  ExpectTabsFillTabStrip(bounds, test_case.tabstrip_width);
 }
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index 8d5add7e..9cbc486ed 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -843,12 +843,6 @@
 }
 
 void NewTabPageHandler::OnModuleUsed(const std::string& module_id) {
-  auto* tab = web_contents_.get();
-  // Close the associated IPH promo if open, as interaction with a module
-  // indicates the user is aware of how to interact with modules.
-  feature_promo_helper_->RecordPromoFeatureUsageAndClosePromo(
-      feature_engagement::kIPHDesktopNewTabPageModulesCustomizeFeature, tab);
-
   IncrementDictPrefKeyCount(prefs::kNtpModulesInteractedCountDict, module_id);
   MaybeLaunchInteractionSurvey(kUseInteraction, module_id);
 }
@@ -984,11 +978,6 @@
           feature_engagement::kIPHDesktopCustomizeChromeRefreshFeature,
           web_contents_.get());
     } break;
-    case new_tab_page::mojom::IphFeature::kCustomizeModules: {
-      feature_promo_helper_->MaybeShowFeaturePromo(
-          feature_engagement::kIPHDesktopNewTabPageModulesCustomizeFeature,
-          web_contents_.get());
-    } break;
     default:
       NOTREACHED();
   }
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
index d9169dd..060fa18 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
@@ -1316,18 +1316,6 @@
   mock_page_.FlushForTesting();
 }
 
-TEST_F(NewTabPageHandlerTest, MaybeShowFeaturePromo_CustomizeModules) {
-  EXPECT_CALL(*mock_feature_promo_helper_, IsSigninModalDialogOpen)
-      .WillRepeatedly(testing::Return(false));
-  EXPECT_CALL(*mock_feature_promo_helper_,
-              MaybeShowFeaturePromo(_, web_contents_.get()))
-      .Times(1);
-
-  handler_->MaybeShowFeaturePromo(
-      new_tab_page::mojom::IphFeature::kCustomizeModules);
-  mock_page_.FlushForTesting();
-}
-
 TEST_F(NewTabPageHandlerTest,
        DontShowCustomizeChromeFeaturePromoWhenModalDialogIsOpen) {
   EXPECT_CALL(*mock_feature_promo_helper_, IsSigninModalDialogOpen)
@@ -1343,18 +1331,6 @@
   mock_page_.FlushForTesting();
 }
 
-TEST_F(NewTabPageHandlerTest, OnModuleUsedRecordFeatureUsageAndClosePromo) {
-  EXPECT_CALL(
-      *mock_feature_promo_helper_,
-      RecordPromoFeatureUsageAndClosePromo(
-          testing::Ref(
-              feature_engagement::kIPHDesktopNewTabPageModulesCustomizeFeature),
-          web_contents_.get()))
-      .Times(1);
-
-  handler_->OnModuleUsed("module_id");
-}
-
 TEST_F(NewTabPageHandlerTest, ShowWebstoreToast) {
   profile_->GetPrefs()->SetInteger(prefs::kSeedColorChangeCount, 1);
 
diff --git a/chrome/browser/ui/webui/search_engine_choice/icon_utils.cc b/chrome/browser/ui/webui/search_engine_choice/icon_utils.cc
deleted file mode 100644
index 56bce72..0000000
--- a/chrome/browser/ui/webui/search_engine_choice/icon_utils.cc
+++ /dev/null
@@ -1,26 +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 "chrome/browser/ui/webui/search_engine_choice/icon_utils.h"
-
-#include <string_view>
-
-#include "base/containers/fixed_flat_map.h"
-#include "build/branding_buildflags.h"
-
-namespace {
-
-// Generated code defining `kSearchEngineIconPathMap`.
-#include "chrome/browser/ui/webui/search_engine_choice/generated_icon_utils-inc.cc"
-
-}  // namespace
-
-std::string_view GetSearchEngineGeneratedIconPath(
-    const std::u16string& engine_keyword) {
-  const base::fixed_flat_map<std::u16string_view, std::string_view,
-                             kSearchEngineIconPathMap.size()>::const_iterator
-      iterator = kSearchEngineIconPathMap.find(engine_keyword);
-  return iterator == kSearchEngineIconPathMap.cend() ? std::string_view()
-                                                     : iterator->second;
-}
diff --git a/chrome/browser/ui/webui/search_engine_choice/icon_utils.h b/chrome/browser/ui/webui/search_engine_choice/icon_utils.h
deleted file mode 100644
index 14f70ee..0000000
--- a/chrome/browser/ui/webui/search_engine_choice/icon_utils.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_SEARCH_ENGINE_CHOICE_ICON_UTILS_H_
-#define CHROME_BROWSER_UI_WEBUI_SEARCH_ENGINE_CHOICE_ICON_UTILS_H_
-
-#include <string>
-#include <string_view>
-
-// Returns the path of the icon for the search engine, or the empty string if
-// not found. Search engines prepopulated in EEA countries are guaranteed to
-// have an icon.
-// The definition of this function is generated in `generated_icon_utils.cc` by
-// the script `tools/search_engine_choice/generate_search_engine_icons.py`.
-std::string_view GetSearchEngineGeneratedIconPath(
-    const std::u16string& engine_keyword);
-
-#endif  // CHROME_BROWSER_UI_WEBUI_SEARCH_ENGINE_CHOICE_ICON_UTILS_H_
diff --git a/chrome/browser/ui/webui/search_engine_choice/icon_utils_unittest.cc b/chrome/browser/ui/webui/search_engine_choice/icon_utils_unittest.cc
deleted file mode 100644
index 07b08b67..0000000
--- a/chrome/browser/ui/webui/search_engine_choice/icon_utils_unittest.cc
+++ /dev/null
@@ -1,55 +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 "chrome/browser/ui/webui/search_engine_choice/icon_utils.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/command_line.h"
-#include "chrome/browser/browser_process.h"
-#include "components/country_codes/country_codes.h"
-#include "components/regional_capabilities/regional_capabilities_switches.h"
-#include "components/regional_capabilities/regional_capabilities_test_utils.h"
-#include "components/search_engines/search_engines_test_environment.h"
-#include "components/search_engines/template_url_prepopulate_data.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::country_codes::CountryId;
-
-class IconUtilsTest : public ::testing::Test {
- public:
-  ~IconUtilsTest() override = default;
-  PrefService* pref_service() {
-    return &search_engines_test_environment_.pref_service();
-  }
-  search_engines::SearchEngineChoiceService* search_engine_choice_service() {
-    return &search_engines_test_environment_.search_engine_choice_service();
-  }
-  TemplateURLPrepopulateData::Resolver& prepopulate_data_resolver() {
-    return search_engines_test_environment_.prepopulate_data_resolver();
-  }
-
- private:
-  search_engines::SearchEnginesTestEnvironment search_engines_test_environment_;
-};
-
-TEST_F(IconUtilsTest, GetSearchEngineGeneratedIconPath) {
-  // Make sure the country is not forced.
-  ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kSearchEngineChoiceCountry));
-
-  for (CountryId country_id : regional_capabilities::kEeaChoiceCountriesIds) {
-    search_engine_choice_service()->ClearCountryIdCacheForTesting();
-    pref_service()->SetInteger(country_codes::kCountryIDAtInstall,
-                               country_id.Serialize());
-    std::vector<std::unique_ptr<TemplateURLData>> urls =
-        prepopulate_data_resolver().GetPrepopulatedEngines();
-    for (const std::unique_ptr<TemplateURLData>& url : urls) {
-      EXPECT_FALSE(GetSearchEngineGeneratedIconPath(url->keyword()).empty())
-          << "Missing icon for " << url->keyword() << ". Try re-running "
-          << "`tools/search_engine_choice/generate_search_engine_icons.py`.";
-    }
-  }
-}
diff --git a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc
index d0c3d5f..c4a27bc2c 100644
--- a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc
+++ b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service.h"
 #include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service_factory.h"
 #include "chrome/browser/search_engine_choice/search_engine_choice_service_factory.h"
-#include "chrome/browser/ui/webui/search_engine_choice/icon_utils.h"
 #include "chrome/browser/ui/webui/search_engine_choice/search_engine_choice_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
@@ -42,14 +41,11 @@
   for (const auto& choice : choices) {
     base::Value::Dict choice_value;
 
-    std::string_view icon_path =
-        GetSearchEngineGeneratedIconPath(choice->keyword());
-    if (icon_path.empty()) {
-      icon_path = "chrome://theme/IDR_DEFAULT_FAVICON";
-    }
     choice_value.Set("prepopulateId", choice->prepopulate_id());
     choice_value.Set("name", choice->short_name());
-    choice_value.Set("iconPath", icon_path);
+    choice_value.Set(
+        "iconPath", base::StrCat({"chrome://theme/",
+                                  choice->data().GetBuiltinImageResourceId()}));
     choice_value.Set("url", choice->url());
     choice_value.Set("marketingSnippet",
                      search_engines::GetMarketingSnippetString(choice->data()));
diff --git a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc
index fbfb63b..7fc6f67 100644
--- a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc
@@ -95,9 +95,12 @@
         if (i % 2 == 0) {
           // The bing icon should be bundled with Chrome.
           choice.SetKeyword(TemplateURLPrepopulateData::bing.keyword);
+          choice.base_builtin_resource_id =
+              TemplateURLPrepopulateData::bing.base_builtin_resource_id;
         } else {
           // Uses the default generic favicon.
           choice.SetKeyword(u"incredibar");
+          choice.base_builtin_resource_id = "";
         }
         choices_.push_back(std::make_unique<TemplateURL>(choice));
       }
diff --git a/chrome/browser/ui/webui/settings/search_engines_handler.cc b/chrome/browser/ui/webui/settings/search_engines_handler.cc
index 4a6c6c6c..da08d08 100644
--- a/chrome/browser/ui/webui/settings/search_engines_handler.cc
+++ b/chrome/browser/ui/webui/settings/search_engines_handler.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/browser/ui/search_engines/template_url_table_model.h"
-#include "chrome/browser/ui/webui/search_engine_choice/icon_utils.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
@@ -269,16 +268,15 @@
       regional_capabilities::RegionalCapabilitiesServiceFactory::GetForProfile(
           profile);
   const bool is_eea_region = regional_capabilities->IsInEeaCountry();
-  if (is_eea_region && template_url->prepopulate_id() != 0) {
-    std::string_view icon_path =
-        GetSearchEngineGeneratedIconPath(template_url->keyword());
-    if (!icon_path.empty()) {
-      // The search engine icon path are 24px, but displayed at 16px, or 32px on
-      // HiDPI screens. Use the 2x version (48px) for a large enough icon.
-      // Note that this icon path is used in `site-favicon` which does not
-      // support `image-set`.
-      dict.Set("iconPath", base::StrCat({icon_path, "@2x"}));
-    }
+  if (is_eea_region) {
+    // The search engine icon path are 24px, but displayed at 16px, or 32px on
+    // HiDPI screens. Use the 2x version (48px) for a large enough icon.
+    // Note that this icon path is used in `site-favicon` which does not
+    // support `image-set`.
+    dict.Set("iconPath",
+             base::StrCat({"chrome://theme/",
+                           template_url->data().GetBuiltinImageResourceId(),
+                           "@2x"}));
   }
 
   dict.Set("modelIndex", base::checked_cast<int>(index));
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 1aa8ba5..f843418 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -54,7 +54,6 @@
 #include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/browser/ui/webui/plural_string_handler.h"
 #include "chrome/browser/ui/webui/sanitized_image_source.h"
-#include "chrome/browser/ui/webui/search_engine_choice/icon_utils.h"
 #include "chrome/browser/ui/webui/settings/about_handler.h"
 #include "chrome/browser/ui/webui/settings/accessibility_main_handler.h"
 #include "chrome/browser/ui/webui/settings/appearance_handler.h"
diff --git a/chrome/browser/updater/browser_updater_client_mac.mm b/chrome/browser/updater/browser_updater_client_mac.mm
index b605f95..96f44ef1 100644
--- a/chrome/browser/updater/browser_updater_client_mac.mm
+++ b/chrome/browser/updater/browser_updater_client_mac.mm
@@ -16,7 +16,7 @@
 #include "components/version_info/version_info.h"
 
 std::string BrowserUpdaterClient::GetAppId() {
-  return base::apple::BaseBundleID();
+  return std::string(base::apple::BaseBundleID());
 }
 
 base::FilePath BrowserUpdaterClient::GetExpectedEcp() {
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.cc
index e6901c8..904c1f8 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "components/keep_alive_registry/keep_alive_types.h"
 #include "components/webapps/common/web_app_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/net_errors.h"
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.h
index 8f3422f0..86b9552 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.h
@@ -20,6 +20,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_fetcher.h"
 #include "components/webapps/common/web_app_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "net/base/net_errors.h"
 
 namespace web_app {
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task_unittest.cc
index 771150cb..65d5df8 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task_unittest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_constants.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/test_signed_web_bundle_builder.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/test/fake_web_app_provider.h"
 #include "chrome/browser/web_applications/test/fake_web_contents_manager.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
@@ -42,6 +41,7 @@
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
 #include "components/webapps/browser/installable/installable_logging.h"
 #include "components/webapps/browser/web_contents/web_app_url_loader.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/common/content_features.h"
 #include "net/http/http_status_code.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.cc
index 27a4936..ac57bb7 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.cc
@@ -55,6 +55,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
 #include "components/webapps/common/web_app_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/isolated_web_apps_policy.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.h
index 22b7c61..eb55b7b 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.h
@@ -31,10 +31,10 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_apply_waiter.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_discovery_task.h"
 #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/web_app_install_manager_observer.h"
 #include "components/webapps/common/web_app_id.h"
 #include "components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "net/base/backoff_entry.h"
 
 class GURL;
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_browsertest.cc
index 86c02ec..f9ed0c78 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_browsertest.cc
@@ -47,7 +47,6 @@
 #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/key_distribution/test_utils.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/test_signed_web_bundle_builder.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h"
 #include "chrome/browser/web_applications/test/web_app_test_observers.h"
 #include "chrome/browser/web_applications/test/web_app_test_utils.h"
@@ -58,6 +57,7 @@
 #include "components/component_updater/component_updater_paths.h"
 #include "components/prefs/pref_service.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/browser/browsing_data_remover.h"
 #include "content/public/browser/service_worker_context.h"
 #include "content/public/browser/service_worker_context_observer.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc
index fe4183e..337efcc 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc
@@ -53,7 +53,6 @@
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_generator.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/test_signed_web_bundle_builder.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/test/fake_web_app_database_factory.h"
 #include "chrome/browser/web_applications/test/fake_web_app_provider.h"
 #include "chrome/browser/web_applications/test/fake_web_app_ui_manager.h"
@@ -76,6 +75,7 @@
 #include "components/webapps/browser/installable/installable_metrics.h"
 #include "components/webapps/browser/uninstall_result_code.h"
 #include "components/webapps/common/web_app_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/common/content_features.h"
 #include "net/http/http_status_code.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.cc
index 06e0202..69b2228 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 
 namespace web_app {
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.h
index 823af94..e288891f 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_server_mixin.h
@@ -11,9 +11,9 @@
 
 #include "base/version.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolation_data.cc b/chrome/browser/web_applications/isolated_web_apps/isolation_data.cc
index e5dcca45..3788ef86 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolation_data.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolation_data.cc
@@ -7,6 +7,7 @@
 #include "base/containers/to_value_list.h"
 #include "base/values.h"
 #include "base/version.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 
 namespace web_app {
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolation_data.h b/chrome/browser/web_applications/isolated_web_apps/isolation_data.h
index 2ee298e..5f67287 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolation_data.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolation_data.h
@@ -12,7 +12,7 @@
 #include "base/version.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_integrity_block_data.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "url/gurl.h"
 
 namespace web_app {
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc
index 311525dc..ee76eb0 100644
--- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc
@@ -12,8 +12,8 @@
 #include "base/values.h"
 #include "base/version.h"
 #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_constants.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 
 namespace web_app {
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.h b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.h
index eb666c3b..be45066 100644
--- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.h
+++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.h
@@ -5,19 +5,14 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_POLICY_ISOLATED_WEB_APP_EXTERNAL_INSTALL_OPTIONS_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_POLICY_ISOLATED_WEB_APP_EXTERNAL_INSTALL_OPTIONS_H_
 
+#include "base/values.h"
 #include "base/version.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "url/gurl.h"
 
-namespace base {
-class Value;
-}
-
 namespace web_app {
 
-class UpdateChannel;
-
 // This class contains all information to install an Isolated Web App via
 // enterprise policy.
 class IsolatedWebAppExternalInstallOptions final {
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options_unittest.cc
index 27dd4c59..2f5f19e7 100644
--- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_constants.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_generator.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace web_app {
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc
index 73f4f51..f9f9a64 100644
--- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc
@@ -25,13 +25,13 @@
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/test_iwa_installer_factory.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/test_signed_web_bundle_builder.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/common/chrome_features.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
 #include "components/web_package/test_support/signed_web_bundles/ed25519_key_pair.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager_ash_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager_ash_browsertest.cc
index 9b0185e..eb8bbb18 100644
--- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager_ash_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager_ash_browsertest.cc
@@ -66,6 +66,7 @@
 #include "components/policy/policy_constants.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/webapps/common/web_app_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/browser/browsing_data_remover.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.cc b/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.cc
index c8dd00b..8b85d8f 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.cc
@@ -14,6 +14,7 @@
 #include "base/types/expected_macros.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 
 namespace web_app::test {
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h b/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h
index 0332ac1..67e779fe 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h
+++ b/chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h
@@ -10,8 +10,8 @@
 #include "base/containers/flat_map.h"
 #include "base/version.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "url/gurl.h"
 
 namespace web_app::test {
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.cc b/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.cc
index f165065d..0eb64f87 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "services/network/test/test_utils.h"
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.h b/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.h
index 66fb390..270b426 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.h
+++ b/chrome/browser/web_applications/isolated_web_apps/test/iwa_test_server_configurator.h
@@ -9,8 +9,8 @@
 
 #include "chrome/browser/web_applications/isolated_web_apps/test/bundle_versions_storage.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "url/gurl.h"
 
 namespace network {
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.cc b/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.cc
index 7b456e2..bb5adcc1 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_generator.h"
 
 #include "chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 
 namespace web_app {
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.h b/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.h
index 95579950..b5b83742 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.h
+++ b/chrome/browser/web_applications/isolated_web_apps/test/policy_generator.h
@@ -8,8 +8,9 @@
 #include <optional>
 
 #include "base/values.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
+#include "base/version.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "url/gurl.h"
 namespace web_app {
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.cc b/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.cc
index 71e94d6e..0e8a6a08 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.cc
@@ -8,6 +8,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 
 namespace web_app::test {
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h b/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h
index 692acba..ca05cd3 100644
--- a/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h
+++ b/chrome/browser/web_applications/isolated_web_apps/test/policy_test_utils.h
@@ -11,8 +11,8 @@
 
 #include "base/values.h"
 #include "base/version.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "url/gurl.h"
 
 class PrefService;
diff --git a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.cc b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.cc
index 70add14..b78f074 100644
--- a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.cc
@@ -12,7 +12,6 @@
 #include <variant>
 #include <vector>
 
-#include "base/containers/contains.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/map_util.h"
 #include "base/containers/to_vector.h"
@@ -24,6 +23,7 @@
 #include "base/values.h"
 #include "base/version.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_version.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 
 namespace web_app {
@@ -93,42 +93,6 @@
 }  // namespace
 
 // static
-const UpdateChannel& UpdateChannel::default_channel() {
-  static const base::NoDestructor<UpdateChannel> kDefaultChannel(
-      [] { return *UpdateChannel::Create("default"); }());
-  return *kDefaultChannel;
-}
-
-// static
-base::expected<UpdateChannel, std::monostate> UpdateChannel::Create(
-    std::string input) {
-  if (input.empty() || !base::IsStringUTF8(input)) {
-    return base::unexpected(std::monostate());
-  }
-  return UpdateChannel(std::move(input));
-}
-
-void PrintTo(const UpdateChannel& channel, std::ostream* os) {
-  *os << channel.ToString();
-}
-
-UpdateChannel::UpdateChannel(std::string channel) : name_(std::move(channel)) {}
-
-UpdateChannel::UpdateChannel(const UpdateChannel&) = default;
-
-UpdateChannel::UpdateChannel(UpdateChannel&&) = default;
-
-UpdateChannel& UpdateChannel::operator=(const UpdateChannel&) = default;
-
-UpdateChannel& UpdateChannel::operator=(UpdateChannel&&) = default;
-
-UpdateChannel::~UpdateChannel() = default;
-
-bool UpdateChannel::operator==(const UpdateChannel& other) const = default;
-auto UpdateChannel::operator<=>(const UpdateChannel& other) const = default;
-bool UpdateChannel::operator<(const UpdateChannel& other) const = default;
-
-// static
 base::expected<UpdateManifest, UpdateManifest::JsonFormatError>
 UpdateManifest::CreateFromJson(const base::Value& json,
                                const GURL& update_manifest_url) {
diff --git a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h
index eeb2b5c..1ed455cd 100644
--- a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h
+++ b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h
@@ -14,12 +14,11 @@
 
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
-#include "base/no_destructor.h"
 #include "base/types/expected.h"
 #include "base/types/optional_ref.h"
-#include "base/types/strong_alias.h"
 #include "base/values.h"
 #include "base/version.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "url/gurl.h"
 
 namespace web_app {
@@ -31,36 +30,6 @@
 inline constexpr std::string_view kUpdateManifestSrcKey = "src";
 inline constexpr std::string_view kUpdateManifestChannelsKey = "channels";
 
-class UpdateChannel {
- public:
-  // Returns an instance of the "default" update channel.
-  static const UpdateChannel& default_channel();
-
-  static base::expected<UpdateChannel, std::monostate> Create(
-      std::string input);
-
-  UpdateChannel(const UpdateChannel&);
-  UpdateChannel(UpdateChannel&&);
-  UpdateChannel& operator=(const UpdateChannel&);
-  UpdateChannel& operator=(UpdateChannel&&);
-
-  ~UpdateChannel();
-
-  bool operator==(const UpdateChannel& other) const;
-  auto operator<=>(const UpdateChannel& other) const;
-  bool operator<(const UpdateChannel& other) const;
-
-  const std::string& ToString() const { return name_; }
-
-  // For gtest
-  friend void PrintTo(const UpdateChannel& channel, std::ostream* os);
-
- private:
-  explicit UpdateChannel(std::string name);
-
-  std::string name_;
-};
-
 // An Isolated Web App Update Manifest contains a list of versions and download
 // URLs of an Isolated Web App. The format is described in more detail here:
 // https://github.com/WICG/isolated-web-apps/blob/main/Updates.md#web-application-update-manifest
diff --git a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_fetcher_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_fetcher_unittest.cc
index 3aa9b81..ec054a2 100644
--- a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_fetcher_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_fetcher_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/test_future.h"
 #include "base/types/expected.h"
 #include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_unittest.cc
index fc8033e2..df375ce 100644
--- a/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/gmock_expected_support.h"
 #include "base/types/expected.h"
 #include "base/values.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/web_applications/os_integration/mac/shortcuts_versioning_mac_unittest.cc b/chrome/browser/web_applications/os_integration/mac/shortcuts_versioning_mac_unittest.cc
index 9bbf575e..868115b 100644
--- a/chrome/browser/web_applications/os_integration/mac/shortcuts_versioning_mac_unittest.cc
+++ b/chrome/browser/web_applications/os_integration/mac/shortcuts_versioning_mac_unittest.cc
@@ -31,7 +31,7 @@
 namespace web_app {
 
 namespace {
-const char kFakeChromeBundleId[] = "fake.cfbundleidentifier";
+constexpr char kFakeChromeBundleId[] = "fake.cfbundleidentifier";
 }
 
 class ShortcutsVersioningMacTest : public WebAppTest {
@@ -42,7 +42,7 @@
   void SetUp() override {
     WebAppTest::SetUp();
 
-    base::apple::SetBaseBundleID(kFakeChromeBundleId);
+    base::apple::SetBaseBundleIDOverride(kFakeChromeBundleId);
     // Put shortcuts somewhere under the home dir, as otherwise LaunchServices
     // won't be able to find them.
     override_registration_ =
diff --git a/chrome/browser/web_applications/os_integration/mac/web_app_run_on_os_login_mac_unittest.mm b/chrome/browser/web_applications/os_integration/mac/web_app_run_on_os_login_mac_unittest.mm
index a8bf00e..0699435b 100644
--- a/chrome/browser/web_applications/os_integration/mac/web_app_run_on_os_login_mac_unittest.mm
+++ b/chrome/browser/web_applications/os_integration/mac/web_app_run_on_os_login_mac_unittest.mm
@@ -79,7 +79,7 @@
  public:
   void SetUp() override {
     WebAppTest::SetUp();
-    base::apple::SetBaseBundleID(kFakeChromeBundleId);
+    base::apple::SetBaseBundleIDOverride(kFakeChromeBundleId);
 
     override_registration_ =
         OsIntegrationTestOverrideImpl::OverrideForTesting();
diff --git a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm
index 3f849cfa..fbcd122b 100644
--- a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm
+++ b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm
@@ -141,10 +141,11 @@
   NSString* outer_app_dir_ns = base::SysUTF8ToNSString(outer_app_dir.value());
   NSBundle* base_bundle = [NSBundle bundleWithPath:outer_app_dir_ns];
   // In tests we might not be running from inside an app bundle, in that case
-  // there is also no need to overide the bundle ID, as the default value should
-  // already match that of the caller process.
+  // there is also no need to override the bundle ID, as the default value
+  // should already match that of the caller process.
   if (base_bundle && base_bundle.bundleIdentifier) {
-    base::apple::SetBaseBundleID(base_bundle.bundleIdentifier.UTF8String);
+    base::apple::SetBaseBundleIDOverride(
+        base::SysNSStringToUTF8(base_bundle.bundleIdentifier));
   }
 
   auto requirement = CallerProcessRequirement();
diff --git a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator_unittest.mm b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator_unittest.mm
index 30fa433..7cc9628 100644
--- a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator_unittest.mm
+++ b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator_unittest.mm
@@ -17,6 +17,7 @@
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/strings/strcat.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
@@ -46,7 +47,7 @@
 
 namespace {
 
-const char kFakeChromeBundleId[] = "fake.cfbundleidentifier";
+constexpr char kFakeChromeBundleId[] = "fake.cfbundleidentifier";
 
 class WebAppShortcutCreatorMock : public WebAppShortcutCreator {
  public:
@@ -140,7 +141,7 @@
   WebAppShortcutCreatorTest() = default;
 
   void SetUp() override {
-    base::apple::SetBaseBundleID(kFakeChromeBundleId);
+    base::apple::SetBaseBundleIDOverride(kFakeChromeBundleId);
 
     override_registration_ =
         OsIntegrationTestOverrideImpl::OverrideForTesting();
@@ -446,8 +447,8 @@
 
     // Verify CFBundleURLName is set.
     EXPECT_NSEQ(protocol_types_dict[app_mode::kCFBundleURLNameKey],
-                base::SysUTF8ToNSString(base::apple::BaseBundleID() +
-                                        std::string(".app.") + info_->app_id));
+                base::SysUTF8ToNSString(base::StrCat(
+                    {base::apple::BaseBundleID(), ".app.", info_->app_id})));
 
     // Verify CFBundleURLSchemes is set, and contains the expected values.
     NSArray* handlers = protocol_types_dict[app_mode::kCFBundleURLSchemesKey];
@@ -480,8 +481,8 @@
 
     // Verify CFBundleURLName is set.
     EXPECT_NSEQ(protocol_types_dict[app_mode::kCFBundleURLNameKey],
-                base::SysUTF8ToNSString(base::apple::BaseBundleID() +
-                                        std::string(".app.") + info_->app_id));
+                base::SysUTF8ToNSString(base::StrCat(
+                    {base::apple::BaseBundleID(), ".app.", info_->app_id})));
 
     // Verify CFBundleURLSchemes is set, and contains the expected values.
     NSArray* handlers = protocol_types_dict[app_mode::kCFBundleURLSchemesKey];
diff --git a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_mac.mm b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_mac.mm
index 152bdff9..c3c1e54 100644
--- a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_mac.mm
+++ b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_mac.mm
@@ -15,6 +15,7 @@
 #include "base/files/file_util.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ref_counted.h"
+#include "base/strings/strcat.h"
 #include "base/task/task_runner.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/browser_process.h"
@@ -61,10 +62,10 @@
     std::string normalized_profile_path;
     base::ReplaceChars(profile_path.BaseName().value(), " ", "-",
                        &normalized_profile_path);
-    return base::apple::BaseBundleID() + std::string(".app.") +
-           normalized_profile_path + "-" + app_id;
+    return base::StrCat({base::apple::BaseBundleID(), ".app.",
+                         normalized_profile_path, "-", app_id});
   }
-  return base::apple::BaseBundleID() + std::string(".app.") + app_id;
+  return base::StrCat({base::apple::BaseBundleID(), ".app.", app_id});
 }
 
 bool UseAdHocSigningForWebAppShims() {
diff --git a/chrome/browser/web_applications/test/web_app_test_utils.cc b/chrome/browser/web_applications/test/web_app_test_utils.cc
index e7cbe0d..f261c55 100644
--- a/chrome/browser/web_applications/test/web_app_test_utils.cc
+++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -52,7 +52,6 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_integrity_block_data.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolation_data.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
 #include "chrome/browser/web_applications/proto/web_app.pb.h"
 #include "chrome/browser/web_applications/proto/web_app_isolation_data.pb.h"
@@ -84,6 +83,7 @@
 #include "components/sync/model/string_ordinal.h"
 #include "components/sync/protocol/web_app_specifics.pb.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/browser/service_worker_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "services/network/public/cpp/permissions_policy/origin_with_possible_wildcards.h"
diff --git a/chrome/browser/web_applications/web_app_database_serialization.cc b/chrome/browser/web_applications/web_app_database_serialization.cc
index f613cb4..c4ee51a 100644
--- a/chrome/browser/web_applications/web_app_database_serialization.cc
+++ b/chrome/browser/web_applications/web_app_database_serialization.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_version.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolation_data.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom-shared.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
 #include "chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h"
@@ -47,6 +46,7 @@
 #include "components/sync/base/time.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
 #include "components/webapps/common/web_app_id.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "services/network/public/cpp/permissions_policy/origin_with_possible_wildcards.h"
 #include "services/network/public/cpp/permissions_policy/permissions_policy_declaration.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc
index 33d5c6ef..1076a5a 100644
--- a/chrome/browser/web_applications/web_app_database_unittest.cc
+++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_integrity_block_data.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolation_data.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom-shared.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
 #include "chrome/browser/web_applications/proto/web_app.pb.h"
@@ -62,6 +61,7 @@
 #include "components/web_package/signed_web_bundles/ed25519_public_key.h"
 #include "components/web_package/signed_web_bundles/ed25519_signature.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "services/network/public/cpp/permissions_policy/origin_with_possible_wildcards.h"
 #include "services/network/public/cpp/permissions_policy/permissions_policy_declaration.h"
 #include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
diff --git a/chrome/browser/web_applications/web_app_internals_browsertest.cc b/chrome/browser/web_applications/web_app_internals_browsertest.cc
index 89309530..52df8ee 100644
--- a/chrome/browser/web_applications/web_app_internals_browsertest.cc
+++ b/chrome/browser/web_applications/web_app_internals_browsertest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
 #include "chrome/browser/web_applications/isolated_web_apps/test/test_signed_web_bundle_builder.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/test/web_app_test_utils.h"
@@ -40,6 +39,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/webapps/browser/install_result_code.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "content/public/test/browser_test.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc
index 4234896..ddcf718 100644
--- a/chrome/browser/web_applications/web_app_unittest.cc
+++ b/chrome/browser/web_applications/web_app_unittest.cc
@@ -20,7 +20,6 @@
 #include "base/values.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_integrity_block_data.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
-#include "chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest.h"
 #include "chrome/browser/web_applications/test/fake_web_app_provider.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/test/web_app_test.h"
@@ -35,6 +34,7 @@
 #include "components/web_package/signed_web_bundles/ecdsa_p256_public_key.h"
 #include "components/web_package/signed_web_bundles/ecdsa_p256_sha256_signature.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.h"
+#include "components/webapps/isolated_web_apps/update_channel.h"
 #include "services/network/public/cpp/permissions_policy/origin_with_possible_wildcards.h"
 #include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index d3940ff..bf98545 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1746532755-c61c8a4f293bcd6b2a3d88442e2659e3114d5ad4-494b8e90e23862cde023bbf172195f22d227a0f6.profdata
+chrome-android32-main-1746552233-58978cccbebf037a10c3dd2b5fd4cbc833b76c25-30165321783ced200f97bf7d0630e468c6dfecd0.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 27ac43af..2163d93 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1746531475-cd418da88fa445c0614cfe6c8ea105d79be9afde-ed7a74fe92874be4a431648cd0fe3b0362d11ffc.profdata
+chrome-android64-main-1746551424-0a92db44a4b5d6fb6dab47c5b2b8e6f331774811-0e99b96cdd6f28cdae67586273c5116547bc7c08.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 45a4450..80e163e 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1746510390-7a9f3d8019960a17d0a5f2bc209c1d006d3fb7d1-d34d80d0e5df7e43587a2fb485d60228efe44aec.profdata
+chrome-linux-main-1746532755-db4a6f3a971a04bbb04b92f04f08c9f1f214bfcb-494b8e90e23862cde023bbf172195f22d227a0f6.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 4af58aaf..b97b8a32 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1746532755-3ab0b4e9cc3cd93d8dfd8dde51750ab893a330db-494b8e90e23862cde023bbf172195f22d227a0f6.profdata
+chrome-mac-arm-main-1746552233-e3b77a96e6271f28332dc33ccb437ecc4584dda8-30165321783ced200f97bf7d0630e468c6dfecd0.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 7afb3d7..f24f15e 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1746510390-eee41a192073cb5943e9ed676d76977645bd6675-d34d80d0e5df7e43587a2fb485d60228efe44aec.profdata
+chrome-mac-main-1746532755-7c187b0b569358e12914392f48696317e7b01a9a-494b8e90e23862cde023bbf172195f22d227a0f6.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index b7cae85..35d19c78f 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1746510390-257bca6e0a8b548257676bac9d0f5d88000bf0f5-d34d80d0e5df7e43587a2fb485d60228efe44aec.profdata
+chrome-win-arm64-main-1746532755-6cdd90db30eeca99b8a7ee87af7d271881097780-494b8e90e23862cde023bbf172195f22d227a0f6.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 89696ee..1b9e1c1 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1746499744-7348fc89f91e0be80b62cec3999f458b57af0d58-02e1f674a6936cd721949e4ccffef13cb24844cd.profdata
+chrome-win32-main-1746532755-5ffa733f407730a139990d436115757e25f2f1ef-494b8e90e23862cde023bbf172195f22d227a0f6.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index d416595..f29635e 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1746499744-1bb95a0b06b8c475e2b6e9bc6f235fa28185181f-02e1f674a6936cd721949e4ccffef13cb24844cd.profdata
+chrome-win64-main-1746510390-3d3d31f355983ee63806e7b06169f5f00494da46-d34d80d0e5df7e43587a2fb485d60228efe44aec.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 845b473..dc3255d 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -70,6 +70,10 @@
         "//ui/views/resources",
       ]
     }
+    if (!is_android) {
+      sources += [ "$root_gen_dir/third_party/search_engines_data/search_engines_resources_${percent}_percent.pak" ]
+      deps += [ "//third_party/search_engines_data:resources" ]
+    }
     if (is_chromeos) {
       sources += [
         "$root_gen_dir/ash/login/resources/login_resources_${percent}_percent.pak",
diff --git a/chrome/installer/mac/internal b/chrome/installer/mac/internal
index e5018549..6460c6c 160000
--- a/chrome/installer/mac/internal
+++ b/chrome/installer/mac/internal
@@ -1 +1 @@
-Subproject commit e5018549ab93c778b4d89049c662cf9b35645f97
+Subproject commit 6460c6c38734ceabe0bb49c02640b6c2040b1e63
diff --git a/chrome/release_scripts b/chrome/release_scripts
deleted file mode 160000
index 088710b..0000000
--- a/chrome/release_scripts
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 088710b5c1f11a40e005e1b4a09cd6bb3a754fe6
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
index 03836c6..d1af751 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
@@ -638,7 +638,7 @@
   // has been added to the tree list in AccessibilityEventReceived. In that
   // case, do not distill.
   if (model_.active_tree_id() != ui::AXTreeIDUnknown() &&
-      model_.ContainsTree(model_.active_tree_id())) {
+      model_.ContainsActiveTree()) {
     Distill();
   }
 }
@@ -687,7 +687,7 @@
 
   model_.set_requires_distillation(false);
 
-  ui::AXSerializableTree* tree = model_.GetTreeFromId(model_.active_tree_id());
+  ui::AXSerializableTree* tree = model_.GetActiveTree();
   std::unique_ptr<
       ui::AXTreeSource<const ui::AXNode*, ui::AXTreeData*, ui::AXNodeData>>
       tree_source(tree->CreateTreeSource());
@@ -782,8 +782,7 @@
 
   // AXNode's language code is BCP 47. Only the base language is needed to
   // record the metric.
-  std::string language =
-      model_.GetTreeFromId(model_.active_tree_id())->root()->GetLanguage();
+  std::string language = model_.GetActiveTree()->root()->GetLanguage();
   if (!language.empty()) {
     base::UmaHistogramSparse(
         "Accessibility.ReadAnything.Language",
@@ -807,8 +806,8 @@
   // when it takes a long time to compute the display nodes. If this happens,
   // return false rather than trying to continue to process information on a
   // destroyed tree.
-  DUMP_WILL_BE_CHECK(model_.ContainsTree(model_.active_tree_id()));
-  if (!model_.ContainsTree(model_.active_tree_id())) {
+  DUMP_WILL_BE_CHECK(model_.ContainsActiveTree());
+  if (!model_.ContainsActiveTree()) {
     return false;
   }
   bool did_draw = false;
@@ -1065,7 +1064,7 @@
 }
 
 ui::AXNodeID ReadAnythingAppController::RootId() const {
-  ui::AXSerializableTree* tree = model_.GetTreeFromId(model_.active_tree_id());
+  ui::AXSerializableTree* tree = model_.GetActiveTree();
   DCHECK(tree);
   DCHECK(tree->root());
   return tree->root()->id();
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc
index df0cc49..c066a2ac 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc
@@ -358,6 +358,10 @@
   }
 }
 
+ui::AXSerializableTree* ReadAnythingAppModel::GetActiveTree() const {
+  return GetTreeFromId(active_tree_id_);
+}
+
 ui::AXSerializableTree* ReadAnythingAppModel::GetTreeFromId(
     const ui::AXTreeID& tree_id) const {
   // If the tree id is unknown or not associated with a tree, fail gracefully,
@@ -377,6 +381,10 @@
   return base::Contains(tree_infos_, tree_id);
 }
 
+bool ReadAnythingAppModel::ContainsActiveTree() const {
+  return ContainsTree(active_tree_id_);
+}
+
 void ReadAnythingAppModel::SetUrlInformationCallback(
     base::OnceCallback<void()> callback) {
   // If the given tree already has its url information set, run the callback
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_model.h b/chrome/renderer/accessibility/read_anything/read_anything_app_model.h
index 4d2c0e7..8e7f301d 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_model.h
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_model.h
@@ -286,10 +286,12 @@
   // displayed in the Read Anything app.ts by default.
   void ComputeDisplayNodeIdsForDistilledTree();
 
-  ui::AXSerializableTree* GetTreeFromId(const ui::AXTreeID& tree_id) const;
+  ui::AXSerializableTree* GetActiveTree() const;
 
   bool ContainsTree(const ui::AXTreeID& tree_id) const;
 
+  bool ContainsActiveTree() const;
+
   void UnserializePendingUpdates(const ui::AXTreeID& tree_id);
 
   void ClearPendingUpdates();
@@ -338,6 +340,8 @@
     int offset = -1;
   };
 
+  ui::AXSerializableTree* GetTreeFromId(const ui::AXTreeID& tree_id) const;
+
   void ResetSelection();
 
   bool ContentNodesOnlyContainHeadings();
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0857191..1764e0d2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -778,6 +778,7 @@
       "//chrome/browser/ui/webui/top_chrome",
       "//components/constrained_window",
       "//components/segmentation_platform/public:public",
+      "//components/webapps/isolated_web_apps:isolated_web_apps",
     ]
     if (!is_chromeos) {
       deps += [ "//chrome/browser/ui/webui/signin:profile" ]
@@ -1672,8 +1673,8 @@
       "../browser/ui/android/autofill/save_update_address_profile_flow_manager_browsertest.cc",
       "../browser/ui/android/hats/hats_service_android_browsertest.cc",
       "../browser/ui/android/hats/survey_client_android_browsertest.cc",
-      "../browser/ui/android/plus_addresses/all_plus_addresses_bottom_sheet_view_browsertest.cc",
-      "../browser/ui/android/plus_addresses/plus_address_creation_view_android_browsertest.cc",
+      "../browser/ui/plus_addresses/android/all_plus_addresses_bottom_sheet_view_browsertest.cc",
+      "../browser/ui/plus_addresses/android/plus_address_creation_view_android_browsertest.cc",
       "../browser/ui/webui/policy/policy_test_ui_browsertest.cc",
       "../browser/ui/webui/policy/policy_ui_browsertest.cc",
       "../browser/user_agent/android_user_agent_browsertest.cc",
@@ -7521,10 +7522,10 @@
       "../browser/ui/android/device_dialog/usb_chooser_dialog_android_unittest.cc",
       "../browser/ui/android/fast_checkout/ui_view_android_utils_unittest.cc",
       "../browser/ui/android/hats/survey_client_android_unittest.cc",
-      "../browser/ui/android/plus_addresses/plus_address_creation_controller_android_unittest.cc",
       "../browser/ui/android/tab_model/tab_model_list_unittest.cc",
       "../browser/ui/android/toolbar/adaptive_toolbar_bridge_unittest.cc",
       "../browser/ui/android/toolbar/location_bar_model_android_unittest.cc",
+      "../browser/ui/plus_addresses/android/plus_address_creation_controller_android_unittest.cc",
       "../browser/wallet/android/boarding_pass_detector_unittest.cc",
       "../browser/webauthn/android/cable_module_android_unittest.cc",
       "../browser/webauthn/android/cable_registration_state_unittest.cc",
@@ -7984,7 +7985,6 @@
       "../browser/ui/webui/password_manager/sync_handler_unittest.cc",
       "../browser/ui/webui/privacy_sandbox/privacy_sandbox_dialog_handler_unittest.cc",
       "../browser/ui/webui/sanitized_image_source_unittest.cc",
-      "../browser/ui/webui/search_engine_choice/icon_utils_unittest.cc",
       "../browser/ui/webui/searchbox/searchbox_handler_unittest.cc",
       "../browser/ui/webui/searchbox/searchbox_test_utils.cc",
       "../browser/ui/webui/searchbox/searchbox_test_utils.h",
@@ -10895,6 +10895,7 @@
       "../browser/ui/omnibox/omnibox_view_browsertest.cc",
       "../browser/ui/performance_controls/tab_resource_usage_tab_helper_interactive_uitest.cc",
       "../browser/ui/plus_addresses/plus_address_error_dialog_interactive_uitest.cc",
+      "../browser/ui/plus_addresses/views/plus_address_creation_dialog_interactive_uitest.cc",
       "../browser/ui/search/instant_extended_interactive_uitest.cc",
       "../browser/ui/search/instant_test_base.cc",
       "../browser/ui/search/instant_test_base.h",
@@ -10928,7 +10929,6 @@
       "../browser/ui/views/page_info/page_info_bubble_view_interactive_uitest.cc",
       "../browser/ui/views/permissions/midi_permissions_flow_interactive_uitest.cc",
       "../browser/ui/views/permissions/permission_rhs_indicators_interactive_uitest.cc",
-      "../browser/ui/views/plus_addresses/plus_address_creation_dialog_interactive_uitest.cc",
       "../browser/ui/views/privacy_sandbox/privacy_sandbox_dialog_view_interactive_ui_test.cc",
       "../browser/ui/views/side_panel/read_anything/read_anything_service_interactive_uitest.cc",
       "../browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller_interactive_uitest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
index 3f4708f..1c3fb70 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
@@ -125,6 +125,7 @@
      * @return The {@link AppMenuCoordinator} for the activity.
      */
     public AppMenuCoordinator getAppMenuCoordinator() {
+        if (getActivity().getRootUiCoordinatorForTesting() == null) return null;
         return getActivity().getRootUiCoordinatorForTesting().getAppMenuCoordinatorForTesting();
     }
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java
index 4277496..7c7250a 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.test.transit.hub.TabSwitcherListEditorFacility;
 import org.chromium.chrome.test.transit.hub.TabSwitcherStation;
 import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.transit.tabmodel.TabThumbnailCondition;
 import org.chromium.chrome.test.util.TabBinningUtil;
 import org.chromium.chrome.test.util.tabmodel.TabBinList;
@@ -49,11 +50,13 @@
             int numIncognitoTabs,
             String url,
             Supplier<PageStation.Builder<T>> pageStationFactory) {
+        List<String> regularTabs = getListOfIdenticalUrls(numRegularTabs, url);
+        List<String> incognitoTabs = getListOfIdenticalUrls(numIncognitoTabs, url);
+
         return doPrepareTabs(
                 startingStation,
-                numRegularTabs,
-                numIncognitoTabs,
-                url,
+                regularTabs,
+                incognitoTabs,
                 pageStationFactory,
                 /* captureThumbnails= */ false);
     }
@@ -68,54 +71,31 @@
             int numIncognitoTabs,
             String url,
             Supplier<PageStation.Builder<T>> pageStationFactory) {
+        List<String> regularTabs = getListOfIdenticalUrls(numRegularTabs, url);
+        List<String> incognitoTabs = getListOfIdenticalUrls(numIncognitoTabs, url);
+
         return doPrepareTabs(
                 startingStation,
-                numRegularTabs,
-                numIncognitoTabs,
-                url,
+                regularTabs,
+                incognitoTabs,
                 pageStationFactory,
                 /* captureThumbnails= */ true);
     }
 
-    private static <T extends PageStation> T doPrepareTabs(
-            PageStation startingStation,
-            int numRegularTabs,
-            int numIncognitoTabs,
-            String url,
-            Supplier<PageStation.Builder<T>> pageStationFactory,
-            boolean captureThumbnails) {
-        assert numRegularTabs >= 1;
-        assert url != null;
-        TabModelSelector tabModelSelector =
-                ThreadUtils.runOnUiThreadBlocking(
-                        () -> startingStation.getActivity().getTabModelSelector());
-        int currentTabCount = tabModelSelector.getModel(/* incognito= */ false).getCount();
-        int currentIncognitoTabCount = tabModelSelector.getModel(/* incognito= */ true).getCount();
-        assert currentTabCount == 1;
-        assert currentIncognitoTabCount == 0;
-        T station = startingStation.loadPageProgrammatically(url, pageStationFactory.get());
-        // One tab already exists.
-        if (numRegularTabs > 1) {
-            station =
-                    doCreateTabs(
-                            station,
-                            numRegularTabs - 1,
-                            url,
-                            /* isIncognito= */ false,
-                            pageStationFactory,
-                            captureThumbnails);
-        }
-        if (numIncognitoTabs > 0) {
-            station =
-                    doCreateTabs(
-                            station,
-                            numIncognitoTabs,
-                            url,
-                            /* isIncognito= */ true,
-                            pageStationFactory,
-                            captureThumbnails);
-        }
-        return station;
+    /**
+     * Open and display multiple web pages in regular tabs, return the last page.
+     *
+     * <p>The first URL will be opened in the current active tab, the rest of the URLs will be
+     * opened in new tabs.
+     */
+    public static WebPageStation prepareRegularTabsWithWebPages(
+            WebPageStation webPageStation, List<String> urlsToOpen) {
+        return doPrepareTabs(
+                webPageStation,
+                urlsToOpen,
+                List.of(),
+                WebPageStation::newBuilder,
+                /* captureThumbnails= */ false);
     }
 
     /**
@@ -123,66 +103,124 @@
      *
      * @param <T> specific type of PageStation for all opened tabs.
      * @param startingPage The current active station.
-     * @param numTabs The number of tabs to create.
-     * @param url The URL to load.
+     * @param urls The URLs to load.
      * @param isIncognito Whether to open an incognito tab.
      * @param pageStationFactory A factory method to create the PageStations for each tab.
      * @return the last opened tab's PageStation.
      */
-    public static <T extends PageStation> T createTabs(
+    @SuppressWarnings("unused")
+    private static <T extends PageStation> T createTabs(
             final PageStation startingPage,
-            int numTabs,
-            String url,
+            List<String> urls,
             boolean isIncognito,
             Supplier<PageStation.Builder<T>> pageStationFactory) {
         return doCreateTabs(
                 startingPage,
-                numTabs,
-                url,
+                urls,
                 isIncognito,
                 pageStationFactory,
                 /* captureThumbnails= */ false);
     }
 
-    /**
-     * Same as {@link #createTabs(PageStation, int, String, boolean, Supplier)}, but ensures tab
-     * thumbnails are captured to disk.
-     */
+    /** Creates identical tabs and ensures tab thumbnails are captured to disk. */
     public static <T extends PageStation> T createTabsWithThumbnails(
             final PageStation startingPage,
             int numTabs,
             String url,
             boolean isIncognito,
             Supplier<PageStation.Builder<T>> pageStationFactory) {
+        List<String> urls = getListOfIdenticalUrls(numTabs, url);
+        return doCreateTabs(
+                startingPage, urls, isIncognito, pageStationFactory, /* captureThumbnails= */ true);
+    }
+
+    /** Open and display multiple web pages in regular tabs, return the last page. */
+    public static WebPageStation createRegularTabsWithWebPages(
+            final PageStation startingPage, List<String> urls) {
         return doCreateTabs(
                 startingPage,
-                numTabs,
-                url,
-                isIncognito,
-                pageStationFactory,
-                /* captureThumbnails= */ true);
+                urls,
+                /* isIncognito= */ false,
+                WebPageStation::newBuilder,
+                /* captureThumbnails= */ false);
+    }
+
+    /** Open and display multiple web pages in incognito tabs, return the last page. */
+    public static WebPageStation createIncognitoTabsWithWebPages(
+            final PageStation startingPage, List<String> urls) {
+        return doCreateTabs(
+                startingPage,
+                urls,
+                /* isIncognito= */ true,
+                () -> WebPageStation.newBuilder().withIncognito(true),
+                /* captureThumbnails= */ false);
+    }
+
+    // TODO(crbug.com/411430975): Open all tabs at once instead of one by one.
+    private static <T extends PageStation> T doPrepareTabs(
+            PageStation startingStation,
+            List<String> urlsForRegularTabs,
+            List<String> urlsForIncognitoTabs,
+            Supplier<PageStation.Builder<T>> pageStationFactory,
+            boolean captureThumbnails) {
+        assert urlsForRegularTabs.size() >= 1;
+        TabModelSelector tabModelSelector =
+                ThreadUtils.runOnUiThreadBlocking(
+                        () -> startingStation.getActivity().getTabModelSelector());
+        int currentTabCount = tabModelSelector.getModel(/* incognito= */ false).getCount();
+        int currentIncognitoTabCount = tabModelSelector.getModel(/* incognito= */ true).getCount();
+        assert currentTabCount == 1;
+        assert currentIncognitoTabCount == 0;
+        T station =
+                startingStation.loadPageProgrammatically(
+                        urlsForRegularTabs.get(0), pageStationFactory.get());
+        // One tab already exists.
+        if (urlsForRegularTabs.size() > 1) {
+            var urlsForRegularTabsMinusFirst = new ArrayList<>(urlsForRegularTabs);
+            urlsForRegularTabsMinusFirst.remove(0);
+            station =
+                    doCreateTabs(
+                            station,
+                            urlsForRegularTabsMinusFirst,
+                            /* isIncognito= */ false,
+                            pageStationFactory,
+                            captureThumbnails);
+        }
+        if (urlsForIncognitoTabs.size() > 0) {
+            station =
+                    doCreateTabs(
+                            station,
+                            urlsForIncognitoTabs,
+                            /* isIncognito= */ true,
+                            pageStationFactory,
+                            captureThumbnails);
+        }
+        return station;
     }
 
     private static <T extends PageStation> T doCreateTabs(
             final PageStation startingPage,
-            int numTabs,
-            String url,
+            List<String> urls,
             boolean isIncognito,
             Supplier<PageStation.Builder<T>> pageStationFactory,
             boolean captureThumbnails) {
-        assert numTabs > 0;
+        assert !urls.isEmpty();
 
         TabModelSelector tabModelSelector = startingPage.getActivity().getTabModelSelector();
 
         PageStation currentPage = startingPage;
-        for (int i = 0; i < numTabs; i++) {
+        for (int i = 0; i < urls.size(); i++) {
+            String url = urls.get(i);
             PageStation previousPage = currentPage;
             Tab previousTab = previousPage.loadedTabElement.get();
-            currentPage =
-                    isIncognito
-                            ? currentPage.openNewIncognitoTabFast()
-                            : currentPage.openNewTabFast();
-            currentPage = currentPage.loadPageProgrammatically(url, pageStationFactory.get());
+            if (i == 0 && startingPage.isIncognito() && !isIncognito) {
+                currentPage = currentPage.openNewTabFast().loadWebPageProgrammatically(url);
+            } else if (i == 0 && !startingPage.isIncognito() && isIncognito) {
+                currentPage =
+                        currentPage.openNewIncognitoTabFast().loadWebPageProgrammatically(url);
+            } else {
+                currentPage = currentPage.openFakeLinkToWebPage(url);
+            }
 
             if (!captureThumbnails) {
                 continue;
@@ -287,4 +325,12 @@
             assert Objects.equals(baseToken, token);
         }
     }
+
+    private static List<String> getListOfIdenticalUrls(int n, String url) {
+        List<String> regularTabs = new ArrayList<>();
+        for (int i = 0; i < n; i++) {
+            regularTabs.add(url);
+        }
+        return regularTabs;
+    }
 }
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 5b761f4..0afc2966 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -59,8 +59,8 @@
 #include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 #include "components/crx_file/crx_verifier.h"
 #include "components/embedder_support/switches.h"
-#include "crypto/rsa_private_key.h"
-#include "crypto/sha2.h"
+#include "crypto/hash.h"
+#include "crypto/keypair.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "third_party/zlib/google/zip.h"
 #include "url/gurl.h"
@@ -1011,10 +1011,10 @@
   }
 }
 
-std::string GenerateExtensionId(const std::string& input) {
-  uint8_t hash[16];
-  crypto::SHA256HashString(input, hash, sizeof(hash));
-  std::string output = base::ToLowerASCII(base::HexEncode(hash));
+std::string GenerateExtensionId(std::string_view input) {
+  auto hash = crypto::hash::Sha256(input);
+  auto hash_first16 = base::span<uint8_t>(hash).first<16>();
+  std::string output = base::ToLowerASCII(base::HexEncode(hash_first16));
   ConvertHexadecimalToIDAlphabet(output);
   return output;
 }
@@ -1086,19 +1086,13 @@
                                        static_cast<int>(result)));
     }
   } else {
-    // Not a CRX file. Generate RSA keypair to get a valid extension id.
-    std::unique_ptr<crypto::RSAPrivateKey> key_pair(
-        crypto::RSAPrivateKey::Create(2048));
-    if (!key_pair)
-      return Status(kUnknownError, "cannot generate RSA key pair");
-    std::vector<uint8_t> public_key_vector;
-    if (!key_pair->ExportPublicKey(&public_key_vector))
-      return Status(kUnknownError, "cannot extract public key");
-    std::string public_key =
-        std::string(reinterpret_cast<char*>(&public_key_vector.front()),
-                    public_key_vector.size());
-    id = GenerateExtensionId(public_key);
-    public_key_base64 = base::Base64Encode(public_key);
+    // Not a CRX file. Generate a fresh RSA key pair and use its public key as
+    // the extension's signing key. Note that the private key is discarded
+    // immediately so this key can never be used to actually sign anything.
+    std::vector<uint8_t> pubkey =
+        crypto::keypair::PrivateKey::GenerateRsa2048().ToSubjectPublicKeyInfo();
+    id = GenerateExtensionId(base::as_string_view(pubkey));
+    public_key_base64 = base::Base64Encode(pubkey);
   }
 
   // Unzip the crx file.
diff --git a/chrome/test/chromedriver/test/run_py_tests.pydeps b/chrome/test/chromedriver/test/run_py_tests.pydeps
index a3d6407b..af399c7c 100644
--- a/chrome/test/chromedriver/test/run_py_tests.pydeps
+++ b/chrome/test/chromedriver/test/run_py_tests.pydeps
@@ -53,7 +53,6 @@
 ../../../../third_party/catapult/devil/devil/devil_env.py
 ../../../../third_party/catapult/devil/devil/utils/__init__.py
 ../../../../third_party/catapult/devil/devil/utils/cmd_helper.py
-../../../../third_party/catapult/devil/devil/utils/host_utils.py
 ../../../../third_party/catapult/devil/devil/utils/lazy/__init__.py
 ../../../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py
 ../../../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/chrome/test/data/extensions/api_test/instance_id/get_creation_time_format/get_creation_time.js b/chrome/test/data/extensions/api_test/instance_id/get_creation_time_format/get_creation_time.js
new file mode 100644
index 0000000..8af6620
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/instance_id/get_creation_time_format/get_creation_time.js
@@ -0,0 +1,32 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.test.runTests([
+
+  // Regression test for crbug.com/400486346.
+  async function getCreationTimeInMilliseconds() {
+    // Record time just before the call.
+    const timeBeforeGetCreationTimeCall = Date.now();
+    // getID() must be called first in order to generate an instanceID with a
+    // valid epoch value. Otherwise getCreationTime() === 0.
+    chrome.instanceID.getID(function(id) {
+      chrome.instanceID.getCreationTime(function(creationTime) {
+        // Record time just after the call.
+        const timeAfterGetCreationTimeCall = Date.now();
+
+        // If the time was in a different unit (like seconds) this should fail.
+        if (typeof creationTime === 'number' &&
+            creationTime > timeBeforeGetCreationTimeCall &&
+            creationTime <= timeAfterGetCreationTimeCall) {
+          chrome.test.succeed();
+        } else {
+          chrome.test.fail(
+              `Creation time should be a number in milliseconds since the epoch,
+             and not in the future. Got: ${creationTime}`);
+        }
+      });
+    });
+  }
+
+]);
diff --git a/chrome/test/data/extensions/api_test/instance_id/get_creation_time_format/manifest.json b/chrome/test/data/extensions/api_test/instance_id/get_creation_time_format/manifest.json
new file mode 100644
index 0000000..6953d21f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/instance_id/get_creation_time_format/manifest.json
@@ -0,0 +1,10 @@
+{
+  "manifest_version": 2,
+  "name": "Test InstanceID App",
+  "version": "1.0",
+  "description": "Tests InstanceID API",
+  "background": {
+    "scripts": ["get_creation_time.js"]
+  },
+  "permissions": ["gcm"]
+}
diff --git a/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts b/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts
index 75601e8f..2ca228d 100644
--- a/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts
+++ b/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import type {Module, ModuleWrapperElement, NamedWidth} from 'chrome://new-tab-page/lazy_load.js';
-import {MODULE_CUSTOMIZE_ELEMENT_ID, ModuleDescriptor, ModuleRegistry, ModulesV2Element, SUPPORTED_MODULE_WIDTHS} from 'chrome://new-tab-page/lazy_load.js';
+import {ModuleDescriptor, ModuleRegistry, ModulesV2Element, SUPPORTED_MODULE_WIDTHS} from 'chrome://new-tab-page/lazy_load.js';
 import {NewTabPageProxy} from 'chrome://new-tab-page/new_tab_page.js';
 import type {PageRemote} from 'chrome://new-tab-page/new_tab_page.mojom-webui.js';
 import {PageCallbackRouter, PageHandlerRemote} from 'chrome://new-tab-page/new_tab_page.mojom-webui.js';
@@ -282,31 +282,6 @@
             0, metrics.count('NewTabPage.Modules.LoadedWith.bar', 'bar'));
       });
 
-  test('help bubble can correctly find anchor elements', async () => {
-    const fooDescriptor = new ModuleDescriptor('foo', initNullModule);
-    handler.setResultFor('getModulesIdNames', {
-      data: [
-        {id: fooDescriptor.id, name: fooDescriptor.id},
-      ],
-    });
-
-    const modulesElement = await createModulesElement(
-        [
-          {
-            descriptor: fooDescriptor,
-            elements: [createElement()],
-          },
-        ],
-        true, SAMPLE_SCREEN_WIDTH);
-
-    assertDeepEquals(
-        modulesElement.getSortedAnchorStatusesForTesting(),
-        [
-          [MODULE_CUSTOMIZE_ELEMENT_ID, true],
-        ],
-    );
-  });
-
   test('modules maxium instance count works correctly', async () => {
     const SAMPLE_MAX_MODULE_INSTANCE_COUNT = 2;
     loadTimeData.overrideValues({
diff --git a/chrome/test/data/webui/settings/clear_browsing_data_dialog_v2_test.ts b/chrome/test/data/webui/settings/clear_browsing_data_dialog_v2_test.ts
index d3db130e..1237017 100644
--- a/chrome/test/data/webui/settings/clear_browsing_data_dialog_v2_test.ts
+++ b/chrome/test/data/webui/settings/clear_browsing_data_dialog_v2_test.ts
@@ -5,10 +5,11 @@
 // clang-format off
 import 'chrome://settings/lazy_load.js';
 
-import type {SettingsClearBrowsingDataDialogV2Element} from 'chrome://settings/lazy_load.js';
+import type {SettingsCheckboxElement, SettingsClearBrowsingDataDialogV2Element} from 'chrome://settings/lazy_load.js';
+import {BrowsingDataType, getDataTypePrefName} from 'chrome://settings/lazy_load.js';
 import type {SettingsPrefsElement} from 'chrome://settings/settings.js';
 import {CrSettingsPrefs} from 'chrome://settings/settings.js';
-import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';
 
@@ -24,12 +25,70 @@
   });
 
   setup(function() {
+    setClearBrowsingDataPrefs(false);
+    return createDialog();
+  });
+
+  function setClearBrowsingDataPrefs(enableCheckboxes: boolean) {
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.HISTORY)}.value`,
+        enableCheckboxes);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.SITE_DATA)}.value`,
+        enableCheckboxes);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.CACHE)}.value`,
+        enableCheckboxes);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.DOWNLOADS)}.value`,
+        enableCheckboxes);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.FORM_DATA)}.value`,
+        enableCheckboxes);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.SITE_SETTINGS)}.value`,
+        enableCheckboxes);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.HOSTED_APPS_DATA)}.value`,
+        enableCheckboxes);
+  }
+
+  async function createDialog() {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     dialog = document.createElement('settings-clear-browsing-data-dialog-v2');
-    dialog.prefs = settingsPrefs.prefs;
+    dialog.set('prefs', settingsPrefs.prefs);
     document.body.appendChild(dialog);
     return flushTasks();
-  });
+  }
+
+  function verifyCheckboxesVisibleForDataTypesInOrder(
+      datatypes: BrowsingDataType[]) {
+    const visibleCheckboxes =
+        dialog.shadowRoot!.querySelectorAll<SettingsCheckboxElement>(
+            'settings-checkbox');
+    assertTrue(!!visibleCheckboxes);
+    assertEquals(datatypes.length, visibleCheckboxes.length);
+
+    for (let i = 0; i < visibleCheckboxes.length; ++i) {
+      assertEquals(
+          getDataTypePrefName(datatypes[i]!), visibleCheckboxes[i]!.pref!.key);
+    }
+  }
+
+  function getCheckboxForDataType(datatype: BrowsingDataType):
+      SettingsCheckboxElement|undefined {
+    const visibleCheckboxes =
+        dialog.shadowRoot!.querySelectorAll<SettingsCheckboxElement>(
+            'settings-checkbox');
+    assertTrue(!!visibleCheckboxes);
+
+    for (const checkbox of visibleCheckboxes) {
+      if (checkbox.pref!.key === getDataTypePrefName(datatype)) {
+        return checkbox;
+      }
+    }
+    return undefined;
+  }
 
   test('CancelButton', async function() {
     dialog.$.cancelButton.click();
@@ -42,4 +101,221 @@
     dialog.$.showMoreButton.click();
     assertFalse(isVisible(dialog.$.showMoreButton));
   });
+
+  test('ExpandableCheckboxes', async function() {
+    // Case 1, no checkbox is selected, only default checkboxes should be
+    // expanded by default.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+    ]);
+
+    dialog.$.showMoreButton.click();
+    await flushTasks();
+    // On show more click, all checkboxes should be visible in default order.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+      BrowsingDataType.FORM_DATA,
+      BrowsingDataType.SITE_SETTINGS,
+      BrowsingDataType.HOSTED_APPS_DATA,
+    ]);
+
+    // Case 2, some checkboxes are selected, default and selected checkboxes
+    // should be expanded by default.
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.CACHE)}.value`, true);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.DOWNLOADS)}.value`, true);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.HOSTED_APPS_DATA)}.value`,
+        true);
+    await createDialog();
+
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+      BrowsingDataType.HOSTED_APPS_DATA,
+    ]);
+
+    dialog.$.showMoreButton.click();
+    await flushTasks();
+    // On show more click, all checkboxes should be visible with the unselected
+    // checkboxes at the bottom.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+      BrowsingDataType.HOSTED_APPS_DATA,
+      BrowsingDataType.FORM_DATA,
+      BrowsingDataType.SITE_SETTINGS,
+    ]);
+
+    // Case 3, All checkboxes are selected, all checkboxes should be expanded by
+    // default and "Show more" button should be hidden.
+    setClearBrowsingDataPrefs(true);
+    await createDialog();
+
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+      BrowsingDataType.FORM_DATA,
+      BrowsingDataType.SITE_SETTINGS,
+      BrowsingDataType.HOSTED_APPS_DATA,
+    ]);
+    assertFalse(isVisible(dialog.$.showMoreButton));
+  });
+
+  test('CheckboxSelection', async function() {
+    // Case 1, selection from expanded checkboxes.
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.DOWNLOADS)}.value`, true);
+    await createDialog();
+
+    // Only Downloads Checkbox is selected, only default and the Downloads
+    // checkboxes should be visible.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+    ]);
+
+    const expandedCheckbox = getCheckboxForDataType(BrowsingDataType.DOWNLOADS);
+    assertTrue(!!expandedCheckbox);
+    assertTrue(expandedCheckbox.pref!.value);
+
+    expandedCheckbox.$.checkbox.click();
+    await expandedCheckbox.$.checkbox.updateComplete;
+
+    // Checkbox should now be unselected.
+    assertFalse(expandedCheckbox.checked);
+    // Associated pref should not change on checkbox selection.
+    assertTrue(expandedCheckbox.pref!.value);
+
+    // Checkboxes order should remain unchanged.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+    ]);
+
+    // Case 2, selection from more checkboxes.
+    dialog.$.showMoreButton.click();
+    await flushTasks();
+
+    // All checkboxes should be visible.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+      BrowsingDataType.FORM_DATA,
+      BrowsingDataType.SITE_SETTINGS,
+      BrowsingDataType.HOSTED_APPS_DATA,
+    ]);
+
+    const moreCheckbox =
+        getCheckboxForDataType(BrowsingDataType.HOSTED_APPS_DATA);
+    assertTrue(!!moreCheckbox);
+    assertFalse(moreCheckbox.pref!.value);
+
+    moreCheckbox.$.checkbox.click();
+    await moreCheckbox.$.checkbox.updateComplete;
+
+    // Checkbox should now be selected.
+    assertTrue(moreCheckbox.checked);
+    // Associated pref should not change on checkbox selection.
+    assertFalse(moreCheckbox.pref!.value);
+
+    // Checkboxes order should remain unchanged.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+      BrowsingDataType.FORM_DATA,
+      BrowsingDataType.SITE_SETTINGS,
+      BrowsingDataType.HOSTED_APPS_DATA,
+    ]);
+  });
+
+  test('PrefChangeDoesNotUpdateCheckboxOrder', async function() {
+    // No checkbox is selected, only default checkboxes are visible.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+    ]);
+
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.FORM_DATA)}.value`, true);
+    settingsPrefs.set(
+        `prefs.${getDataTypePrefName(BrowsingDataType.HOSTED_APPS_DATA)}.value`,
+        true);
+    await flushTasks();
+
+    // Pref changes should not change checkbox expansion state.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+    ]);
+
+    dialog.$.showMoreButton.click();
+    await flushTasks();
+
+    const formDataCheckbox = getCheckboxForDataType(BrowsingDataType.FORM_DATA);
+    assertTrue(!!formDataCheckbox);
+    assertTrue(formDataCheckbox.checked);
+
+    const hostedAppsDataCheckbox =
+        getCheckboxForDataType(BrowsingDataType.HOSTED_APPS_DATA);
+    assertTrue(!!hostedAppsDataCheckbox);
+    assertTrue(hostedAppsDataCheckbox.checked);
+
+    // Checkbox order should not change on pref changes.
+    verifyCheckboxesVisibleForDataTypesInOrder([
+      BrowsingDataType.HISTORY,
+      BrowsingDataType.SITE_DATA,
+      BrowsingDataType.CACHE,
+      BrowsingDataType.DOWNLOADS,
+      BrowsingDataType.FORM_DATA,
+      BrowsingDataType.SITE_SETTINGS,
+      BrowsingDataType.HOSTED_APPS_DATA,
+    ]);
+  });
+
+  test('BrowsingDataTypePrefs', function() {
+    assertEquals(
+        'browser.clear_data.browsing_history',
+        getDataTypePrefName(BrowsingDataType.HISTORY));
+    assertEquals(
+        'browser.clear_data.cookies',
+        getDataTypePrefName(BrowsingDataType.SITE_DATA));
+    assertEquals(
+        'browser.clear_data.cache',
+        getDataTypePrefName(BrowsingDataType.CACHE));
+    assertEquals(
+        'browser.clear_data.form_data',
+        getDataTypePrefName(BrowsingDataType.FORM_DATA));
+    assertEquals(
+        'browser.clear_data.site_settings',
+        getDataTypePrefName(BrowsingDataType.SITE_SETTINGS));
+    assertEquals(
+        'browser.clear_data.download_history',
+        getDataTypePrefName(BrowsingDataType.DOWNLOADS));
+    assertEquals(
+        'browser.clear_data.hosted_apps_data',
+        getDataTypePrefName(BrowsingDataType.HOSTED_APPS_DATA));
+  });
 });
diff --git a/chrome/test/data/webui/side_panel/read_anything/image_test.ts b/chrome/test/data/webui/side_panel/read_anything/image_test.ts
index 6b36e55..58e53990 100644
--- a/chrome/test/data/webui/side_panel/read_anything/image_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/image_test.ts
@@ -5,7 +5,7 @@
 
 import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
 import type {AppElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import {IMAGES_TOGGLE_BUTTON_ID, SpeechBrowserProxyImpl, VoicePackController} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+import {IMAGES_TOGGLE_BUTTON_ID, SpeechBrowserProxyImpl, SpeechController, VoicePackController} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
 import {microtasksFinished} from 'chrome-untrusted://webui-test/test_util.js';
 
@@ -44,6 +44,7 @@
     chrome.readingMode.onConnected = () => {};
     speech = new TestSpeechBrowserProxy();
     SpeechBrowserProxyImpl.setInstance(speech);
+    SpeechController.setInstance(new SpeechController());
     VoicePackController.setInstance(new VoicePackController());
 
     // Override chrome.readingMode.requestImageData to avoid the cross-process
diff --git a/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts b/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts
index e4e90a1..47bd14c5 100644
--- a/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts
@@ -1,10 +1,10 @@
 // Copyright 2025 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-import {BrowserProxy, PauseActionSource, SpeechBrowserProxyImpl, SpeechController} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+import {BrowserProxy, PauseActionSource, SpeechBrowserProxyImpl, SpeechController, SpeechEngineState} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
 import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
 
-import {mockMetrics} from './common.js';
+import {createSpeechSynthesisVoice, mockMetrics} from './common.js';
 import {FakeReadingMode} from './fake_reading_mode.js';
 import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js';
 import type {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js';
@@ -16,6 +16,8 @@
   let onPause: boolean;
   let isSpeechActiveChanged: boolean;
   let isAudioCurrentlyPlayingChanged: boolean;
+  let onPreviewVoicePlaying: boolean;
+  let onEngineStateChange: boolean;
   let metrics: TestMetricsBrowserProxy;
 
   setup(() => {
@@ -30,6 +32,8 @@
     isSpeechActiveChanged = false;
     isAudioCurrentlyPlayingChanged = false;
     onPause = false;
+    onPreviewVoicePlaying = false;
+    onEngineStateChange = false;
     const speechListener = {
       onPause() {
         onPause = true;
@@ -42,6 +46,14 @@
       onIsAudioCurrentlyPlayingChange() {
         isAudioCurrentlyPlayingChanged = true;
       },
+
+      onEngineStateChange() {
+        onEngineStateChange = true;
+      },
+
+      onPreviewVoicePlaying() {
+        onPreviewVoicePlaying = true;
+      },
     };
 
     speechController = new SpeechController();
@@ -148,6 +160,94 @@
     assertTrue(isAudioCurrentlyPlayingChanged);
   });
 
+  test('setEngineState notifies listeners if value changes', () => {
+    speechController.setEngineState(SpeechEngineState.NONE);
+
+    assertFalse(onEngineStateChange);
+    assertFalse(speechController.isEngineLoaded());
+
+    speechController.setEngineState(SpeechEngineState.LOADED);
+
+    assertTrue(onEngineStateChange);
+    assertTrue(speechController.isEngineLoaded());
+  });
+
+  test('setPreviewVoicePlaying notifies listeners if value changes', () => {
+    speechController.setPreviewVoicePlaying(null);
+
+    assertFalse(onPreviewVoicePlaying);
+    assertFalse(!!speechController.getPreviewVoicePlaying());
+
+    const voice = createSpeechSynthesisVoice({lang: 'it', name: 'June'});
+    speechController.setPreviewVoicePlaying(voice);
+
+    assertTrue(onPreviewVoicePlaying);
+    assertEquals(voice, speechController.getPreviewVoicePlaying());
+  });
+
+  test('speakMessage waits for engine load', async () => {
+    const msg =
+        new SpeechSynthesisUtterance('Sorry not sorry bout what I said');
+    speechController.setOnSpeechSynthesisUtteranceStart(msg);
+
+    speechController.speakMessage(msg);
+    assertEquals(msg, await speech.whenCalled('speak'));
+    assertFalse(speechController.isEngineLoaded());
+    assertFalse(speechController.isAudioCurrentlyPlaying());
+
+    assertTrue(!!msg.onstart);
+    msg.onstart(new SpeechSynthesisEvent('type', {utterance: msg}));
+    assertTrue(speechController.isEngineLoaded());
+    assertTrue(speechController.isAudioCurrentlyPlaying());
+  });
+
+  test('speakMessage uses current language and speech rate', async () => {
+    const rate = 1.5;
+    const lang = 'hi';
+    const msg = new SpeechSynthesisUtterance('I\'m just tryna have some fun');
+    chrome.readingMode.speechRate = rate;
+    chrome.readingMode.baseLanguageForSpeech = lang;
+    speechController.setOnSpeechSynthesisUtteranceStart(msg);
+
+    speechController.speakMessage(msg);
+
+    const spoken = await speech.whenCalled('speak');
+    assertEquals(msg, spoken);
+    assertEquals(rate, msg.rate);
+    assertEquals(lang, msg.lang);
+  });
+
+  test('previewVoice stops speech', () => {
+    speechController.setIsSpeechActive(true);
+    speechController.setIsAudioCurrentlyPlaying(true);
+
+    speechController.previewVoice(null);
+
+    assertFalse(speechController.isSpeechActive());
+    assertFalse(speechController.isAudioCurrentlyPlaying());
+    assertEquals(
+        PauseActionSource.VOICE_PREVIEW, speechController.getPauseSource());
+  });
+
+  test('previewVoice plays preview with voice', () => {
+    const voice = createSpeechSynthesisVoice({lang: 'yue', name: 'August'});
+    speechController.previewVoice(voice);
+    assertEquals(1, speech.getCallCount('speak'));
+  });
+
+  test('previewVoice sets preview voice playing', async () => {
+    const voice = createSpeechSynthesisVoice({lang: 'yue', name: 'November'});
+
+    speechController.previewVoice(voice);
+
+    const spoken = await speech.whenCalled('speak');
+    spoken.onstart(new SpeechSynthesisEvent('type', {utterance: spoken}));
+    assertEquals(voice, speechController.getPreviewVoicePlaying());
+
+    spoken.onend();
+    assertFalse(!!speechController.getPreviewVoicePlaying());
+  });
+
   suite('initializeSpeechTree', () => {
     let initAxPositionWithNode: number;
     let startedPreprocess: boolean = false;
diff --git a/chrome/test/data/webui/side_panel/read_anything/speech_model_test.ts b/chrome/test/data/webui/side_panel/read_anything/speech_model_test.ts
index 310c52d..3da56a7 100644
--- a/chrome/test/data/webui/side_panel/read_anything/speech_model_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/speech_model_test.ts
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {BrowserProxy, PauseActionSource, SpeechModel} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+import {BrowserProxy, PauseActionSource, SpeechEngineState, SpeechModel} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
 import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
 
+import {createSpeechSynthesisVoice} from './common.js';
 import {FakeReadingMode} from './fake_reading_mode.js';
 import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js';
 
@@ -109,4 +110,30 @@
     speechModel.setPauseSource(source3);
     assertEquals(source3, speechModel.getPauseSource());
   });
+
+  test('setPreviewVoicePlaying', () => {
+    const voice1 = createSpeechSynthesisVoice({lang: 'en', name: 'April'});
+    const voice2 = null;
+    const voice3 = createSpeechSynthesisVoice({lang: 'fr', name: 'May'});
+
+    speechModel.setPreviewVoicePlaying(voice1);
+    assertEquals(voice1, speechModel.getPreviewVoicePlaying());
+    speechModel.setPreviewVoicePlaying(voice2);
+    assertEquals(voice2, speechModel.getPreviewVoicePlaying());
+    speechModel.setPreviewVoicePlaying(voice3);
+    assertEquals(voice3, speechModel.getPreviewVoicePlaying());
+  });
+
+  test('setEngineState', () => {
+    const state1 = SpeechEngineState.LOADING;
+    const state2 = SpeechEngineState.NONE;
+    const state3 = SpeechEngineState.LOADED;
+
+    speechModel.setEngineState(state1);
+    assertEquals(state1, speechModel.getEngineState());
+    speechModel.setEngineState(state2);
+    assertEquals(state2, speechModel.getEngineState());
+    speechModel.setEngineState(state3);
+    assertEquals(state3, speechModel.getEngineState());
+  });
 });
diff --git a/chrome/test/data/webui/side_panel/read_anything/speech_test.ts b/chrome/test/data/webui/side_panel/read_anything/speech_test.ts
index c897f6b..97f73c8 100644
--- a/chrome/test/data/webui/side_panel/read_anything/speech_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/speech_test.ts
@@ -643,7 +643,13 @@
 
     suite('and voice preview is played', () => {
       setup(() => {
-        emitEvent(app, 'preview-voice', {detail: {previewVoice: null}});
+        const voice =
+            createSpeechSynthesisVoice({lang: 'en', name: 'December'});
+        emitEvent(app, 'preview-voice', {
+          detail: {
+            previewVoice: voice,
+          },
+        });
       });
 
       test('cancels speech and plays preview', () => {
diff --git a/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts b/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts
index 6b86a3e..927293d 100644
--- a/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts
@@ -392,7 +392,7 @@
       await openVoiceMenu();
       voiceSelectionMenu.previewVoicePlaying = previewVoice;
       await microtasksFinished();
-      voiceSelectionMenu.previewVoicePlaying = undefined;
+      voiceSelectionMenu.previewVoicePlaying = null;
       await microtasksFinished();
 
       const playIconVoice0 =
diff --git a/chrome/test/interaction/interactive_browser_test_internal.h b/chrome/test/interaction/interactive_browser_test_internal.h
index 6edfb824..c295e40 100644
--- a/chrome/test/interaction/interactive_browser_test_internal.h
+++ b/chrome/test/interaction/interactive_browser_test_internal.h
@@ -102,9 +102,6 @@
   // that a base::Value can be constructed from. This is also required for a lot
   // of gtest and gmock logic to work properly.
   bool operator==(const MatchableValue& other) const;
-  bool operator!=(const MatchableValue& other) const {
-    return !(*this == other);
-  }
   bool operator<(const MatchableValue& other) const;
   bool operator>(const MatchableValue& other) const;
   bool operator<=(const MatchableValue& other) const;
diff --git a/chrome/updater/app/app_server.cc b/chrome/updater/app/app_server.cc
index 089822e..8c5ff594 100644
--- a/chrome/updater/app/app_server.cc
+++ b/chrome/updater/app/app_server.cc
@@ -92,7 +92,8 @@
     if (!local_prefs->GetQualified()) {
       global_prefs = nullptr;
       prefs_ = local_prefs;
-      config_ = base::MakeRefCounted<Configurator>(prefs_, external_constants_);
+      config_ = base::MakeRefCounted<Configurator>(prefs_, external_constants_,
+                                                   updater_scope());
       if (IsInternalService()) {
         return base::BindOnce(
             &AppServer::ActiveDutyInternal, this,
@@ -129,7 +130,7 @@
   server_starts_ = global_prefs->CountServerStarts();
   prefs_ = global_prefs;
   config_ = base::MakeRefCounted<Configurator>(
-      prefs_, external_constants_,
+      prefs_, external_constants_, updater_scope(),
       CreateLocalPrefs(updater_scope())->GetCecaExperimentEnabled());
   return base::BindOnce(
       &AppServer::ActiveDuty, this,
diff --git a/chrome/updater/app/app_uninstall.cc b/chrome/updater/app/app_uninstall.cc
index 527ace2c..8d9cda4 100644
--- a/chrome/updater/app/app_uninstall.cc
+++ b/chrome/updater/app/app_uninstall.cc
@@ -222,8 +222,8 @@
       CreateScopedLock(kSetupMutex, updater_scope(), kWaitForSetupLock);
   global_prefs_ = CreateGlobalPrefs(updater_scope());
   if (global_prefs_) {
-    config_ = base::MakeRefCounted<Configurator>(global_prefs_,
-                                                 CreateExternalConstants());
+    config_ = base::MakeRefCounted<Configurator>(
+        global_prefs_, CreateExternalConstants(), updater_scope());
   }
   return kErrorOk;
 }
diff --git a/chrome/updater/cleanup_task.cc b/chrome/updater/cleanup_task.cc
index c916968..5b0192938 100644
--- a/chrome/updater/cleanup_task.cc
+++ b/chrome/updater/cleanup_task.cc
@@ -5,6 +5,7 @@
 #include "chrome/updater/cleanup_task.h"
 
 #include <optional>
+#include <utility>
 
 #include "base/check_op.h"
 #include "base/files/file_enumerator.h"
@@ -21,8 +22,11 @@
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/updater/app/app_uninstall.h"
+#include "chrome/updater/configurator.h"
+#include "chrome/updater/persisted_data.h"
 #include "chrome/updater/updater_version.h"
 #include "chrome/updater/util/util.h"
+#include "components/update_client/crx_cache.h"
 
 #if BUILDFLAG(IS_WIN)
 #include "chrome/updater/util/win_util.h"
@@ -75,7 +79,8 @@
 
 }  // namespace
 
-CleanupTask::CleanupTask(UpdaterScope scope) : scope_(scope) {}
+CleanupTask::CleanupTask(UpdaterScope scope, scoped_refptr<Configurator> config)
+    : scope_(scope), config_(config) {}
 
 CleanupTask::~CleanupTask() = default;
 
@@ -94,7 +99,13 @@
 #endif  // IS_MAC
           },
           scope_),
-      std::move(callback));
+      base::BindOnce(
+          [](scoped_refptr<Configurator> config, base::OnceClosure callback) {
+            config->GetCrxCache()->RemoveIfNot(
+                config->GetUpdaterPersistedData()->GetAppIds(),
+                std::move(callback));
+          },
+          config_, std::move(callback)));
 }
 
 }  // namespace updater
diff --git a/chrome/updater/cleanup_task.h b/chrome/updater/cleanup_task.h
index 1d24407..a0d31be 100644
--- a/chrome/updater/cleanup_task.h
+++ b/chrome/updater/cleanup_task.h
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/sequence_checker.h"
 #include "build/build_config.h"
+#include "chrome/updater/configurator.h"
 #include "chrome/updater/updater_scope.h"
 
 namespace updater {
@@ -20,7 +21,7 @@
 // setup ran but can be cleaned up now.
 class CleanupTask : public base::RefCountedThreadSafe<CleanupTask> {
  public:
-  explicit CleanupTask(UpdaterScope scope);
+  CleanupTask(UpdaterScope scope, scoped_refptr<Configurator> config);
   void Run(base::OnceClosure callback);
 
  private:
@@ -29,6 +30,7 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
   UpdaterScope scope_;
+  scoped_refptr<Configurator> config_;
 };
 
 #if BUILDFLAG(IS_MAC)
diff --git a/chrome/updater/cleanup_task_mac_unittest.mm b/chrome/updater/cleanup_task_mac_unittest.mm
index aa671c8..f8652f2 100644
--- a/chrome/updater/cleanup_task_mac_unittest.mm
+++ b/chrome/updater/cleanup_task_mac_unittest.mm
@@ -14,6 +14,9 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
+#include "chrome/updater/configurator.h"
+#include "chrome/updater/external_constants.h"
+#include "chrome/updater/prefs.h"
 #include "chrome/updater/test/test_scope.h"
 #include "chrome/updater/updater_branding.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -21,6 +24,11 @@
 namespace updater {
 
 TEST(CleanupTaskMacTest, CleansOldCache) {
+  const UpdaterScope scope = GetUpdaterScopeForTesting();
+  VLOG(2) << __func__ << scope;
+  if (scope == UpdaterScope::kSystem) {
+    GTEST_SKIP() << "Cannot create system prefs as user.";
+  }
   base::test::TaskEnvironment task_environment;
 
   base::FilePath cache;
@@ -36,8 +44,9 @@
   EXPECT_TRUE(base::CreateDirectory(crx_cache));
   EXPECT_TRUE(base::WriteFile(file, "contents"));
 
-  auto cleanup_task =
-      base::MakeRefCounted<CleanupTask>(GetUpdaterScopeForTesting());
+  auto cleanup_task = base::MakeRefCounted<CleanupTask>(
+      scope, base::MakeRefCounted<Configurator>(
+                 CreateLocalPrefs(scope), CreateExternalConstants(), scope));
   base::RunLoop run_loop;
   cleanup_task->Run(run_loop.QuitClosure());
   run_loop.Run();
@@ -49,6 +58,10 @@
 }
 
 TEST(CleanupTaskMacTest, CleansOldCacheSymlinkSafe) {
+  const UpdaterScope scope = GetUpdaterScopeForTesting();
+  if (scope == UpdaterScope::kSystem) {
+    GTEST_SKIP() << "Cannot create system prefs as user.";
+  }
   base::test::TaskEnvironment task_environment;
 
   base::ScopedTempDir temp;
@@ -62,8 +75,9 @@
   ASSERT_TRUE(base::DeletePathRecursively(cache));
   ASSERT_FALSE(symlink(temp.GetPath().value().c_str(), cache.value().c_str()));
 
-  auto cleanup_task =
-      base::MakeRefCounted<CleanupTask>(GetUpdaterScopeForTesting());
+  auto cleanup_task = base::MakeRefCounted<CleanupTask>(
+      scope, base::MakeRefCounted<Configurator>(
+                 CreateLocalPrefs(scope), CreateExternalConstants(), scope));
   base::RunLoop run_loop;
   cleanup_task->Run(run_loop.QuitClosure());
   run_loop.Run();
diff --git a/chrome/updater/cleanup_task_unittest.cc b/chrome/updater/cleanup_task_unittest.cc
index f06282f..f3833dc 100644
--- a/chrome/updater/cleanup_task_unittest.cc
+++ b/chrome/updater/cleanup_task_unittest.cc
@@ -12,6 +12,9 @@
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "base/version.h"
+#include "chrome/updater/configurator.h"
+#include "chrome/updater/external_constants.h"
+#include "chrome/updater/prefs.h"
 #include "chrome/updater/test/test_scope.h"
 #include "chrome/updater/test/unit_test_util.h"
 #include "chrome/updater/updater_version.h"
@@ -59,8 +62,10 @@
   ASSERT_TRUE(folder_path_current);
   ASSERT_TRUE(base::CreateDirectory(*folder_path_current));
 
-  auto cleanup_task =
-      base::MakeRefCounted<CleanupTask>(GetUpdaterScopeForTesting());
+  const UpdaterScope scope = GetUpdaterScopeForTesting();
+  auto cleanup_task = base::MakeRefCounted<CleanupTask>(
+      scope, base::MakeRefCounted<Configurator>(
+                 CreateGlobalPrefs(scope), CreateExternalConstants(), scope));
   base::RunLoop run_loop;
   cleanup_task->Run(run_loop.QuitClosure());
   run_loop.Run();
diff --git a/chrome/updater/configurator.cc b/chrome/updater/configurator.cc
index 3e85868c4..dc93d15 100644
--- a/chrome/updater/configurator.cc
+++ b/chrome/updater/configurator.cc
@@ -34,6 +34,7 @@
 #include "components/crash/core/common/crash_key.h"
 #include "components/crx_file/crx_verifier.h"
 #include "components/prefs/pref_service.h"
+#include "components/update_client/crx_cache.h"
 #include "components/update_client/network.h"
 #include "components/update_client/patch/in_process_patcher.h"
 #include "components/update_client/patcher.h"
@@ -64,13 +65,14 @@
 
 Configurator::Configurator(scoped_refptr<UpdaterPrefs> prefs,
                            scoped_refptr<ExternalConstants> external_constants,
+                           UpdaterScope scope,
                            bool is_ceca_experiment_enabled)
     : prefs_(prefs),
       external_constants_(external_constants),
       persisted_data_(base::MakeRefCounted<PersistedData>(
-          GetUpdaterScope(),
+          scope,
           prefs->GetPrefService(),
-          std::make_unique<ActivityDataService>(GetUpdaterScope()))),
+          std::make_unique<ActivityDataService>(scope))),
       policy_service_(
           base::MakeRefCounted<PolicyService>(external_constants,
                                               persisted_data_,
@@ -80,6 +82,8 @@
               unzipper_symlink_option)),
       patch_factory_(
           base::MakeRefCounted<update_client::InProcessPatcherFactory>()),
+      crx_cache_(base::MakeRefCounted<update_client::CrxCache>(
+          GetCrxCacheDirectory(scope))),
       is_managed_device_([] {
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
         return base::IsManagedOrEnterpriseDevice();
@@ -279,9 +283,9 @@
   });
 }
 
-std::optional<base::FilePath> Configurator::GetCrxCachePath() const {
+scoped_refptr<update_client::CrxCache> Configurator::GetCrxCache() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return updater::GetCrxCacheDirectory(GetUpdaterScope());
+  return crx_cache_;
 }
 
 bool Configurator::IsConnectionMetered() const {
diff --git a/chrome/updater/configurator.h b/chrome/updater/configurator.h
index 4681338..58cc0cc 100644
--- a/chrome/updater/configurator.h
+++ b/chrome/updater/configurator.h
@@ -21,7 +21,6 @@
 
 namespace base {
 class Version;
-class FilePath;
 }  // namespace base
 
 namespace crx_file {
@@ -30,6 +29,7 @@
 
 namespace update_client {
 class NetworkFetcherFactory;
+class CrxCache;
 class CrxDownloaderFactory;
 class ProtocolHandlerFactory;
 }  // namespace update_client
@@ -40,11 +40,13 @@
 class PersistedData;
 class PolicyService;
 class UpdaterPrefs;
+enum class UpdaterScope;
 
 class Configurator : public update_client::Configurator {
  public:
   Configurator(scoped_refptr<UpdaterPrefs> prefs,
                scoped_refptr<ExternalConstants> external_constants,
+               UpdaterScope scope,
                bool is_ceca_experiment_enabled = false);
   Configurator(const Configurator&) = delete;
   Configurator& operator=(const Configurator&) = delete;
@@ -78,7 +80,7 @@
   GetProtocolHandlerFactory() const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   update_client::UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<update_client::CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
   scoped_refptr<PersistedData> GetUpdaterPersistedData() const;
@@ -102,6 +104,7 @@
   scoped_refptr<update_client::CrxDownloaderFactory> crx_downloader_factory_;
   scoped_refptr<update_client::UnzipperFactory> unzip_factory_;
   scoped_refptr<update_client::PatcherFactory> patch_factory_;
+  scoped_refptr<update_client::CrxCache> crx_cache_;
   const std::optional<bool> is_managed_device_;
 };
 
diff --git a/chrome/updater/ping_configurator.cc b/chrome/updater/ping_configurator.cc
index 5b250b3b..9a6a5e23 100644
--- a/chrome/updater/ping_configurator.cc
+++ b/chrome/updater/ping_configurator.cc
@@ -20,6 +20,7 @@
 #include "chrome/updater/ping_persisted_data.h"
 #include "chrome/updater/util/util.h"
 #include "components/prefs/pref_service.h"
+#include "components/update_client/crx_cache.h"
 #include "components/update_client/network.h"
 #include "components/update_client/patcher.h"
 #include "components/update_client/protocol_handler.h"
@@ -67,7 +68,7 @@
   GetProtocolHandlerFactory() const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   update_client::UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<update_client::CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
  private:
@@ -223,9 +224,9 @@
   NOTREACHED();
 }
 
-std::optional<base::FilePath> PingConfigurator::GetCrxCachePath() const {
+scoped_refptr<update_client::CrxCache> PingConfigurator::GetCrxCache() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return {};
+  NOTREACHED();
 }
 
 bool PingConfigurator::IsConnectionMetered() const {
diff --git a/chrome/updater/tools/updater_util.cc b/chrome/updater/tools/updater_util.cc
index a495a91e..e158dbb 100644
--- a/chrome/updater/tools/updater_util.cc
+++ b/chrome/updater/tools/updater_util.cc
@@ -702,7 +702,8 @@
       FROM_HERE, {base::MayBlock(), base::WithBaseSyncPrimitives()},
       base::BindOnce([] {
         auto configurator = base::MakeRefCounted<Configurator>(
-            CreateGlobalPrefs(Scope()), CreateDefaultExternalConstants());
+            CreateGlobalPrefs(Scope()), CreateDefaultExternalConstants(),
+            Scope());
         if (OutputInJSONFormat()) {
           std::cout << ValueToJSONString(
                            configurator->GetPolicyService()->GetAllPolicies())
diff --git a/chrome/updater/update_service_impl_impl.cc b/chrome/updater/update_service_impl_impl.cc
index 512cb42..d7c80d7 100644
--- a/chrome/updater/update_service_impl_impl.cc
+++ b/chrome/updater/update_service_impl_impl.cc
@@ -892,7 +892,8 @@
       base::MakeRefCounted<AutoRunOnOsUpgradeTask>(
           GetUpdaterScope(), config_->GetUpdaterPersistedData())));
   new_tasks.push_back(base::BindOnce(
-      &CleanupTask::Run, base::MakeRefCounted<CleanupTask>(GetUpdaterScope())));
+      &CleanupTask::Run,
+      base::MakeRefCounted<CleanupTask>(GetUpdaterScope(), config_)));
 
   const auto barrier_closure =
       base::BarrierClosure(new_tasks.size(), std::move(callback));
diff --git a/chrome/updater/update_service_internal_impl_qualifying.cc b/chrome/updater/update_service_internal_impl_qualifying.cc
index 7cbff46b..629db71 100644
--- a/chrome/updater/update_service_internal_impl_qualifying.cc
+++ b/chrome/updater/update_service_internal_impl_qualifying.cc
@@ -26,6 +26,7 @@
 #include "chrome/updater/update_service_impl.h"
 #include "chrome/updater/update_service_internal.h"
 #include "components/prefs/pref_service.h"
+#include "components/update_client/crx_cache.h"
 
 namespace updater {
 namespace {
@@ -151,7 +152,13 @@
     VLOG(1) << "Qualification complete, qualified = " << qualified;
     local_prefs_->SetQualified(qualified);
     local_prefs_->GetPrefService()->CommitPendingWrite();
-    std::move(callback).Run();
+    if (qualified) {
+      config_->GetCrxCache()->RemoveAll(kQualificationAppId,
+                                        std::move(callback));
+      return;
+    }
+    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+        FROM_HERE, std::move(callback));
   }
 
   scoped_refptr<Configurator> config_;
diff --git a/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.cc b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.cc
index 3c2d87b..c5efb05 100644
--- a/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.cc
+++ b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.cc
@@ -22,12 +22,12 @@
 namespace {
 
 CastStarboardApiAdapterImpl* g_instance = nullptr;
-std::mutex g_instance_mutex;
+base::Lock g_instance_mutex;
 
 }  // namespace
 
 CastStarboardApiAdapter* CastStarboardApiAdapter::GetInstance() {
-  std::unique_lock<std::mutex> lock(g_instance_mutex);
+  base::AutoLock lock(g_instance_mutex);
   if (!g_instance) {
     // The instance is assigned by the class's constructor.
     new CastStarboardApiAdapterImpl();
@@ -48,8 +48,7 @@
   return g_instance;
 }
 
-CastStarboardApiAdapterImpl::CastStarboardApiAdapterImpl()
-    : initialized_(false) {
+CastStarboardApiAdapterImpl::CastStarboardApiAdapterImpl() {
   CHECK(!g_instance);
   g_instance = this;
 }
@@ -71,62 +70,97 @@
   switch (event->type) {
     case kSbEventTypeStart:
       LOG(INFO) << "Received kSbEventTypeStart event";
-      init_p_.set_value(true);
+      starboard_started_.Signal();
       break;
     case kSbEventTypeStop:
       LOG(INFO) << "Received kSbEventTypeStop event";
-      init_p_.set_value(false);
+      starboard_stopped_.Signal();
       break;
-    default:
+    default: {
+      base::AutoLock autolock(lock_);
       for (const auto p : subscribers_) {
         if (p.second) {
           p.second(p.first, event);
         }
       }
       break;
+    }
   }
 }
 
-void CastStarboardApiAdapterImpl::Initialize() {
-  LOG(INFO) << "CastStarboardApiAdapterImpl::Initialize";
-  init_p_ = {};
+void CastStarboardApiAdapterImpl::EnsureInitialized() {
+  LOG(INFO) << "CastStarboardApiAdapterImpl::EnsureInitialized";
 
+  bool need_to_start_starboard = false;
+  {
+    base::AutoLock autolock(lock_);
+    CHECK(!released_) << "Starboard should not be re-initialized after the the "
+                         "AtExitManager has run.";
+    if (!initialized_) {
+      need_to_start_starboard = true;
+    }
+    initialized_ = true;
+  }
+
+  if (need_to_start_starboard) {
+    LOG(INFO) << "Starting starboard";
 #if SB_API_VERSION >= 15
-  sb_main_ = std::make_unique<std::thread>(
-      &SbRunStarboardMain, /*argc=*/0, /*argv=*/nullptr,
-      &CastStarboardApiAdapterImpl::SbEventHandle);
-  sb_main_->detach();
+    sb_main_ = std::make_unique<std::thread>(
+        &SbRunStarboardMain, /*argc=*/0, /*argv=*/nullptr,
+        &CastStarboardApiAdapterImpl::SbEventHandle);
+    sb_main_->detach();
 #else   // SB_API_VERSION >=15
-  CastStarboardApiInitialize(/*argc=*/0, /*argv=*/nullptr,
-                             &CastStarboardApiAdapterImpl::SbEventHandle);
+    CastStarboardApiInitialize(/*argc=*/0, /*argv=*/nullptr,
+                               &CastStarboardApiAdapterImpl::SbEventHandle);
 #endif  // SB_API_VERSION >= 15
-  init_f_ = init_p_.get_future();
-  initialized_ = init_f_.get();
+  }
+
+  // If starboard was started earlier, this will return immediately. Regardless
+  // of whether we start starboard in this function call, we still need to call
+  // this (e.g. if another thread started starboard but starboard has not yet
+  // sent the kSbEventTypeStart event).
+  starboard_started_.Wait();
 }
 
 void CastStarboardApiAdapterImpl::Release() {
   LOG(INFO) << "CastStarboardApiAdapterImpl::Release";
+  bool need_to_stop_starboard = false;
   {
-    std::lock_guard<decltype(lock_)> lock(lock_);
+    base::AutoLock autolock(lock_);
     released_ = true;
+
     if (!subscribers_.empty()) {
       LOG(WARNING) << "Not stopping Starboard yet, because there are still "
                    << subscribers_.size() << " subscribers.";
       return;
     }
+
+    if (initialized_) {
+      need_to_stop_starboard = true;
+    }
+    initialized_ = false;
   }
 
-  LOG(INFO) << "Stopping Starboard";
-  init_p_ = {};
+  if (need_to_stop_starboard) {
+    if (!starboard_stopped_.IsSignaled()) {
+      LOG(INFO) << "Stopping Starboard";
 #if SB_API_VERSION >= 15
-  SbSystemRequestStop(0);
+      SbSystemRequestStop(0);
 #else   // SB_API_VERSION >=15
-  CastStarboardApiFinalize();
+      CastStarboardApiFinalize();
 #endif  // SB_API_VERSION >= 15
-  init_f_ = init_p_.get_future();
-  initialized_ = init_f_.get();
+    }
+    LOG(INFO) << "Waiting for starboard to stop.";
+    starboard_stopped_.Wait();
+    LOG(INFO) << "Done waiting for starboard to stop.";
+  } else {
+    LOG(WARNING)
+        << "CastStarboardApiAdapterImpl was not initialized before being "
+           "released.";
+  }
 
-  std::unique_lock<std::mutex> lock(g_instance_mutex);
+  base::AutoLock lock(g_instance_mutex);
+  LOG(INFO) << "Destroying CastStarboardApiAdapterImpl instance.";
   delete g_instance;
   g_instance = nullptr;
 }
@@ -134,14 +168,9 @@
 void CastStarboardApiAdapterImpl::Subscribe(void* context,
                                             CastStarboardApiAdapterImplCB cb) {
   LOG(INFO) << "CastStarboardApiAdapterImpl::Subscribe, context=" << context;
+  EnsureInitialized();
 
-  std::lock_guard<decltype(lock_)> lock(lock_);
-  CHECK(!released_)
-      << "Subscribe should not be called after the AtExitManager has run";
-
-  if (!initialized_) {
-    Initialize();
-  }
+  base::AutoLock autolock(lock_);
   subscribers_.insert({context, cb});
 }
 
@@ -150,11 +179,14 @@
 
   bool do_release = false;
   {
-    std::lock_guard<decltype(lock_)> lock(lock_);
+    base::AutoLock autolock(lock_);
     subscribers_.erase(context);
     if (released_ && subscribers_.empty()) {
       do_release = true;
     }
+
+    LOG(INFO) << "After Unsubscribe, there are " << subscribers_.size()
+              << " remaining subscribers";
   }
 
   // Release() must be called while lock_ is not held.
@@ -167,6 +199,9 @@
 
 SbWindow CastStarboardApiAdapterImpl::GetWindow(
     const SbWindowOptions* options) {
+  EnsureInitialized();
+
+  base::AutoLock autolock(lock_);
   if (!SbWindowIsValid(window_)) {
     window_ = SbWindowCreate(options);
   }
diff --git a/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.h b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.h
index 4eca70e..681538ab 100644
--- a/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.h
+++ b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.h
@@ -5,11 +5,12 @@
 #ifndef CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_SRC_CAST_STARBOARD_API_ADAPTER_IMPL_H_
 #define CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_SRC_CAST_STARBOARD_API_ADAPTER_IMPL_H_
 
-#include <future>
-#include <mutex>
 #include <thread>
 #include <unordered_map>
 
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/thread_annotations.h"
 #include "chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h"
 
 namespace chromecast {
@@ -35,14 +36,16 @@
   ~CastStarboardApiAdapterImpl() override;
 
   void SbEventHandleInternal(const SbEvent* event);
-  void Initialize();
+
+  // Initializes starboard if necessary, and blocks until starboard has started.
+  void EnsureInitialized() LOCKS_EXCLUDED(lock_);
 
   // Signals that the runtime is shutting down, and that this object should be
   // destructed if there are no remaining subscribers.
   //
   // If there are remaining subscribers, the object will be destructed once the
   // last subscriber unsubscribes.
-  void Release();
+  void Release() LOCKS_EXCLUDED(lock_);
 
   // CastStarboardApiAdapter implementation:
   void Subscribe(void* context,
@@ -54,16 +57,18 @@
 #if SB_API_VERSION >= 15
   std::unique_ptr<std::thread> sb_main_;
 #endif  // SB_API_VERSION >= 15
-  std::promise<bool> init_p_;
-  std::future<bool> init_f_;
-  SbWindow window_ = kSbWindowInvalid;
-  std::mutex lock_;
-  bool initialized_;
-  std::unordered_map<void*, CastStarboardApiAdapterImplCB> subscribers_;
+  base::WaitableEvent starboard_started_;
+  base::WaitableEvent starboard_stopped_;
+
+  base::Lock lock_;
+  SbWindow window_ GUARDED_BY(lock_) = kSbWindowInvalid;
+  bool initialized_ GUARDED_BY(lock_) = false;
+  std::unordered_map<void*, CastStarboardApiAdapterImplCB> subscribers_
+      GUARDED_BY(lock_);
 
   // Tracks whether Release() has been called (meaning the runtime is shutting
   // down).
-  bool released_ = false;
+  bool released_ GUARDED_BY(lock_) = false;
 };
 
 }  // namespace chromecast
diff --git a/chromecast/starboard/media/BUILD.gn b/chromecast/starboard/media/BUILD.gn
index 18b07edc..08250a3 100644
--- a/chromecast/starboard/media/BUILD.gn
+++ b/chromecast/starboard/media/BUILD.gn
@@ -8,6 +8,7 @@
   tests = [
     "//chromecast/starboard/media/cdm:starboard_decryptor_cast_test",
     "//chromecast/starboard/media/cdm:starboard_drm_key_tracker_test",
+    "//chromecast/starboard/media/cdm:starboard_drm_wrapper_test",
     "//chromecast/starboard/media/media:media_pipeline_backend_starboard_test",
     "//chromecast/starboard/media/media:mime_utils_test",
     "//chromecast/starboard/media/media:starboard_audio_decoder_test",
diff --git a/chromecast/starboard/media/cdm/BUILD.gn b/chromecast/starboard/media/cdm/BUILD.gn
index 96981d4..d29c0a03 100644
--- a/chromecast/starboard/media/cdm/BUILD.gn
+++ b/chromecast/starboard/media/cdm/BUILD.gn
@@ -13,6 +13,7 @@
 
   deps = [
     ":starboard_drm_key_tracker",
+    ":starboard_drm_wrapper",
     "//base",
     "//chromecast/media/base",
     "//chromecast/media/cdm",
@@ -23,6 +24,18 @@
   ]
 }
 
+cast_source_set("starboard_drm_wrapper") {
+  sources = [
+    "starboard_drm_wrapper.cc",
+    "starboard_drm_wrapper.h",
+  ]
+  public_deps = [
+    "//base",
+    "//chromecast/starboard/media/media:starboard_api_wrapper",
+  ]
+  deps = [ "//chromecast/starboard/chromecast/starboard_adapter" ]
+}
+
 cast_source_set("starboard_drm_key_tracker") {
   sources = [
     "starboard_drm_key_tracker.cc",
@@ -37,6 +50,7 @@
   deps = [
     ":starboard_decryptor_cast",
     ":starboard_drm_key_tracker",
+    ":starboard_drm_wrapper",
     "//base",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
@@ -59,3 +73,16 @@
     "//testing/gtest",
   ]
 }
+
+test("starboard_drm_wrapper_test") {
+  sources = [ "starboard_drm_wrapper_test.cc" ]
+  deps = [
+    ":starboard_drm_wrapper",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//chromecast/starboard/media/media:mock_starboard_api_wrapper",
+    "//chromecast/starboard/media/media:starboard_api_wrapper",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc b/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc
index 17b43ff..576dde2c 100644
--- a/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc
+++ b/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc
@@ -142,16 +142,7 @@
     ::media::CreateFetcherCB create_provision_fetcher_cb,
     MediaResourceTracker* media_resource_tracker)
     : CastCdm(media_resource_tracker),
-      create_provision_fetcher_cb_(std::move(create_provision_fetcher_cb)),
-      callback_handler_{
-          this,
-          &CallOnSessionUpdateRequest,
-          &CallOnSessionUpdated,
-          &CallOnKeyStatusesChanged,
-          &CallOnCertificateUpdated,
-          &CallOnSessionClosed,
-      },
-      starboard_(GetStarboardApiWrapper()) {
+      create_provision_fetcher_cb_(std::move(create_provision_fetcher_cb)) {
   CHECK(base::SequencedTaskRunner::HasCurrentDefault());
   task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
   LOG(INFO) << "StarboardDecryptorCast constructor, this=" << this;
@@ -192,7 +183,6 @@
     std::unique_ptr<::media::NewSessionCdmPromise> promise) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!pending_session_setup_);
-  DCHECK(drm_system_);
 
   pending_session_setup_ = true;
   std::string init_type;
@@ -217,9 +207,8 @@
 
   const int ticket = current_ticket_++;
   ticket_to_new_session_promise_[ticket] = std::move(promise);
-  starboard_->DrmGenerateSessionUpdateRequest(
-      drm_system_, ticket, init_type.c_str(), init_data.data(),
-      init_data.size());
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      this, ticket, init_type, init_data);
 }
 
 void StarboardDecryptorCast::LoadSession(
@@ -238,7 +227,6 @@
     const std::vector<uint8_t>& response,
     std::unique_ptr<::media::SimpleCdmPromise> promise) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(drm_system_);
 
   LOG(INFO) << "StarboardDecryptorCast::UpdateSession, web session id = "
             << web_session_id;
@@ -246,16 +234,14 @@
   const int ticket = current_ticket_++;
   ticket_to_simple_cdm_promise_[ticket] = std::move(promise);
   // This will eventually call OnSessionUpdated.
-  starboard_->DrmUpdateSession(drm_system_, ticket, response.data(),
-                               response.size(), web_session_id.c_str(),
-                               web_session_id.size());
+  StarboardDrmWrapper::GetInstance().UpdateSession(this, ticket, web_session_id,
+                                                   response);
 }
 
 void StarboardDecryptorCast::CloseSession(
     const std::string& web_session_id,
     std::unique_ptr<::media::SimpleCdmPromise> promise) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(drm_system_);
 
   LOG(INFO) << "StarboardDecryptorCast::CloseSession, web session id = "
             << web_session_id;
@@ -277,8 +263,7 @@
     // This is the first request to close the session; mark the session as
     // removed and call starboard to perform the close logic
     StarboardDrmKeyTracker::GetInstance().RemoveKeysForSession(web_session_id);
-    starboard_->DrmCloseSession(drm_system_, web_session_id.c_str(),
-                                web_session_id.size());
+    StarboardDrmWrapper::GetInstance().CloseSession(this, web_session_id);
   } else {
     LOG(INFO) << "Session " << web_session_id << " is currently closing.";
   }
@@ -288,7 +273,6 @@
     const std::string& session_id,
     std::unique_ptr<::media::SimpleCdmPromise> promise) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(drm_system_);
 
   LOG(INFO)
       << "StarboardDecryptorCast::RemoveSession (implemented as CloseSession), "
@@ -301,7 +285,6 @@
     const std::vector<uint8_t>& certificate_data,
     std::unique_ptr<::media::SimpleCdmPromise> promise) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(drm_system_);
 
   LOG(INFO) << "StarboardDecryptorCast::SetServerCertificate";
 
@@ -315,8 +298,8 @@
 
   const int ticket = current_ticket_++;
   ticket_to_simple_cdm_promise_[ticket] = std::move(promise);
-  starboard_->DrmUpdateServerCertificate(
-      drm_system_, ticket, certificate_data.data(), certificate_data.size());
+  StarboardDrmWrapper::GetInstance().UpdateServerCertificate(this, ticket,
+                                                             certificate_data);
 }
 
 std::unique_ptr<DecryptContextImpl> StarboardDecryptorCast::GetDecryptContext(
@@ -342,37 +325,17 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   LOG(INFO) << "StarboardDecryptorCast destructor, this=" << this;
-
-  if (drm_system_) {
-    LOG(INFO) << "Destroying DRM system with address " << drm_system_;
-    // Once this call returns, all DRM-related callbacks from Starboard are
-    // guaranteed to be finished.
-    starboard_->DrmDestroySystem(drm_system_);
-
-    for (const std::string& session_id : session_ids_) {
-      StarboardDrmKeyTracker::GetInstance().RemoveKeysForSession(session_id);
-    }
+  for (const std::string& session_id : session_ids_) {
+    StarboardDrmKeyTracker::GetInstance().RemoveKeysForSession(session_id);
   }
-
   RejectPendingPromises();
 }
 
 void StarboardDecryptorCast::InitializeInternal() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  // This just calls EnsureStarboardInitialized in production, but in tests the
-  // behavior can be overridden to prevent relying on a real Starboard
-  // implementation.
-  starboard_->EnsureInitialized();
-
-  drm_system_ = starboard_->CreateDrmSystem(
-      /*key_system=*/"com.widevine.alpha",
-      /*callback_handler=*/&callback_handler_);
-  CHECK(drm_system_) << "Failed to create an SbDrmSystem";
-  LOG(INFO) << "Created DRM system with address " << drm_system_;
-
   server_certificate_updatable_ =
-      starboard_->DrmIsServerCertificateUpdatable(drm_system_);
+      StarboardDrmWrapper::GetInstance().IsServerCertificateUpdatable();
 }
 
 void StarboardDecryptorCast::RejectPendingPromises() {
@@ -432,7 +395,6 @@
 }
 
 void StarboardDecryptorCast::OnSessionUpdateRequest(
-    void* drm_system,
     int ticket,
     StarboardDrmStatus status,
     StarboardDrmSessionRequestType type,
@@ -575,8 +537,7 @@
 
 // Called by starboard (via CallOnSessionUpdated) once a session has been
 // updated.
-void StarboardDecryptorCast::OnSessionUpdated(void* drm_system,
-                                              int ticket,
+void StarboardDecryptorCast::OnSessionUpdated(int ticket,
                                               StarboardDrmStatus status,
                                               std::string error_message,
                                               std::string session_id) {
@@ -617,7 +578,6 @@
 // Called by starboard (via CallOnKeyStatusesChanged) when the status of keys
 // change.
 void StarboardDecryptorCast::OnKeyStatusesChanged(
-    void* drm_system,
     std::string session_id,
     std::vector<StarboardDrmKeyId> key_ids,
     std::vector<StarboardDrmKeyStatus> key_statuses) {
@@ -646,8 +606,7 @@
             .first(static_cast<size_t>(key_id.identifier_size));
     const size_t key_hash = base::FastHash(identifier_span);
     LOG(INFO) << "DRM key (hash) " << key_hash << " changed status to "
-              << DrmKeyStatusToString(status) << " for DRM system with address "
-              << drm_system << ", for session " << session_id;
+              << DrmKeyStatusToString(status) << ", for session " << session_id;
 
     auto key_info = std::make_unique<::media::CdmKeyInformation>();
     key_info->key_id.assign(identifier_span.begin(), identifier_span.end());
@@ -683,8 +642,7 @@
 
 // Called by starboard (via CallOnCertificateUpdated) when a certificate has
 // been updated.
-void StarboardDecryptorCast::OnCertificateUpdated(void* drm_system,
-                                                  int ticket,
+void StarboardDecryptorCast::OnCertificateUpdated(int ticket,
                                                   StarboardDrmStatus status,
                                                   std::string error_message) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -712,8 +670,7 @@
 }
 
 // Called by starboard (via CallOnSessionClosed) when a session has closed.
-void StarboardDecryptorCast::OnSessionClosed(void* drm_system,
-                                             std::string session_id) {
+void StarboardDecryptorCast::OnSessionClosed(std::string session_id) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   LOG(INFO) << "StarboardDecryptorCast::OnSessionClosed, session_id: "
@@ -762,95 +719,5 @@
   session_id_to_simple_cdm_promises_.erase(it);
 }
 
-void StarboardDecryptorCast::CallOnSessionUpdateRequest(
-    void* drm_system,
-    void* context,
-    int ticket,
-    StarboardDrmStatus status,
-    StarboardDrmSessionRequestType type,
-    std::string error_message,
-    std::string session_id,
-    std::vector<uint8_t> content,
-    std::string url) {
-  if (!url.empty()) {
-    LOG(ERROR)
-        << "Non-empty URL was specified in SessionUpdateRequest callback: "
-        << url;
-  }
-
-  auto* decryptor = reinterpret_cast<StarboardDecryptorCast*>(context);
-  decryptor->task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&StarboardDecryptorCast::OnSessionUpdateRequest,
-                     decryptor->weak_factory_.GetWeakPtr(), drm_system, ticket,
-                     status, type, std::move(error_message),
-                     std::move(session_id), std::move(content)));
-}
-
-void StarboardDecryptorCast::CallOnSessionUpdated(void* drm_system,
-                                                  void* context,
-                                                  int ticket,
-                                                  StarboardDrmStatus status,
-                                                  std::string error_message,
-                                                  std::string session_id) {
-  auto* decryptor = reinterpret_cast<StarboardDecryptorCast*>(context);
-  decryptor->task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&StarboardDecryptorCast::OnSessionUpdated,
-                     decryptor->weak_factory_.GetWeakPtr(), drm_system, ticket,
-                     status, std::move(error_message), std::move(session_id)));
-}
-
-void StarboardDecryptorCast::CallOnKeyStatusesChanged(
-    void* drm_system,
-    void* context,
-    std::string session_id,
-    std::vector<StarboardDrmKeyId> key_ids,
-    std::vector<StarboardDrmKeyStatus> key_statuses) {
-  if (session_id.empty()) {
-    LOG(ERROR) << "StarboardDecryptorCast::CallOnKeyStatusesChanged was called "
-                  "by starboard with an empty session_id. Ignoring the call.";
-    return;
-  }
-
-  auto* decryptor = reinterpret_cast<StarboardDecryptorCast*>(context);
-  decryptor->task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&StarboardDecryptorCast::OnKeyStatusesChanged,
-                                decryptor->weak_factory_.GetWeakPtr(),
-                                drm_system, std::move(session_id),
-                                std::move(key_ids), std::move(key_statuses)));
-}
-
-void StarboardDecryptorCast::CallOnCertificateUpdated(
-    void* drm_system,
-    void* context,
-    int ticket,
-    StarboardDrmStatus status,
-    std::string error_message) {
-  auto* decryptor = reinterpret_cast<StarboardDecryptorCast*>(context);
-  decryptor->task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&StarboardDecryptorCast::OnCertificateUpdated,
-                     decryptor->weak_factory_.GetWeakPtr(), drm_system, ticket,
-                     status, std::move(error_message)));
-}
-
-void StarboardDecryptorCast::CallOnSessionClosed(void* drm_system,
-                                                 void* context,
-                                                 std::string session_id) {
-  auto* decryptor = reinterpret_cast<StarboardDecryptorCast*>(context);
-  decryptor->task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&StarboardDecryptorCast::OnSessionClosed,
-                                decryptor->weak_factory_.GetWeakPtr(),
-                                drm_system, std::move(session_id)));
-}
-
-void StarboardDecryptorCast::SetStarboardApiWrapperForTest(
-    std::unique_ptr<StarboardApiWrapper> starboard) {
-  LOG(INFO) << "Replacing the StarboardApiWrapper used by "
-               "StarboardDecryptorCast. This should only happen in tests.";
-  starboard_ = std::move(starboard);
-}
-
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/starboard/media/cdm/starboard_decryptor_cast.h b/chromecast/starboard/media/cdm/starboard_decryptor_cast.h
index d51711f..c2474cb 100644
--- a/chromecast/starboard/media/cdm/starboard_decryptor_cast.h
+++ b/chromecast/starboard/media/cdm/starboard_decryptor_cast.h
@@ -21,7 +21,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
 #include "chromecast/media/cdm/cast_cdm.h"
-#include "chromecast/starboard/media/media/starboard_api_wrapper.h"
+#include "chromecast/starboard/media/cdm/starboard_drm_wrapper.h"
 #include "media/base/cdm_promise.h"
 #include "media/base/provision_fetcher.h"
 
@@ -32,9 +32,12 @@
 // SbDrmSystem. Currently only supports widevine (the key system passed to
 // starboard is hardcoded, as is the provisioning server URL).
 //
-// The constructor, destructor, and all functions (except the Call* callbacks
-// stored in callback_handler_) must be called on the same sequence.
-class StarboardDecryptorCast : public CastCdm {
+// Calls to starboard go through the StarboardDrmWrapper singleton.
+//
+// The constructor, destructor, and all functions must be called on the same
+// sequence.
+class StarboardDecryptorCast : public CastCdm,
+                               public StarboardDrmWrapper::Client {
  public:
   explicit StarboardDecryptorCast(
       ::media::CreateFetcherCB create_provision_fetcher_cb,
@@ -44,10 +47,6 @@
   StarboardDecryptorCast(const StarboardDecryptorCast&) = delete;
   StarboardDecryptorCast& operator=(const StarboardDecryptorCast&) = delete;
 
-  // For testing purposes, `starboard` will be used to call starboard functions.
-  void SetStarboardApiWrapperForTest(
-      std::unique_ptr<StarboardApiWrapper> starboard);
-
   // ::media::ContentDecryptionModule implementation:
   void CreateSessionAndGenerateRequest(
       ::media::CdmSessionType session_type,
@@ -113,84 +112,25 @@
                             std::string session_id,
                             const std::string& content);
 
-  // Called by starboard (via CallOnSessionUpdateRequest) once a new session has
-  // been created.
-  void OnSessionUpdateRequest(void* drm_system,
-                              int ticket,
+  // StarboardDrmWrapper::Client implementation:
+  void OnSessionUpdateRequest(int ticket,
                               StarboardDrmStatus status,
                               StarboardDrmSessionRequestType type,
                               std::string error_message,
                               std::string session_id,
-                              std::vector<uint8_t> content);
-
-  // Called by starboard (via CallOnSessionUpdated) once a session has been
-  // updated.
-  void OnSessionUpdated(void* drm_system,
-                        int ticket,
+                              std::vector<uint8_t> content) override;
+  void OnSessionUpdated(int ticket,
                         StarboardDrmStatus status,
                         std::string error_message,
-                        std::string session_id);
-
-  // Called by starboard (via CallOnKeyStatusesChanged) when the status of keys
-  // change.
-  void OnKeyStatusesChanged(void* drm_system,
-                            std::string session_id,
-                            std::vector<StarboardDrmKeyId> key_ids,
-                            std::vector<StarboardDrmKeyStatus> key_statuses);
-
-  // Called by starboard (via CallOnCertificateUpdated) when a certificate has
-  // been updated.
-  void OnCertificateUpdated(void* drm_system,
-                            int ticket,
-                            StarboardDrmStatus status,
-                            std::string error_message);
-
-  // Called by starboard (via CallOnSessionClosed) when a session has closed.
-  void OnSessionClosed(void* drm_system, std::string session_id);
-
-  // Calls OnSessionUpdateRequest for `context`, which is an instance of
-  // StarboardDecryptorCast.
-  static void CallOnSessionUpdateRequest(void* drm_system,
-                                         void* context,
-                                         int ticket,
-                                         StarboardDrmStatus status,
-                                         StarboardDrmSessionRequestType type,
-                                         std::string error_message,
-                                         std::string session_id,
-                                         std::vector<uint8_t> content,
-                                         std::string url);
-
-  // Calls OnSessionUpdated for `context`, which is an instance of
-  // StarboardDecryptorCast.
-  static void CallOnSessionUpdated(void* drm_system,
-                                   void* context,
-                                   int ticket,
-                                   StarboardDrmStatus status,
-                                   std::string error_message,
-                                   std::string session_id);
-
-  // Calls OnKeyStatusesChanged for `context`, which is an instance of
-  // StarboardDecryptorCast.
-  static void CallOnKeyStatusesChanged(
-      void* drm_system,
-      void* context,
+                        std::string session_id) override;
+  void OnKeyStatusesChanged(
       std::string session_id,
       std::vector<StarboardDrmKeyId> key_ids,
-      std::vector<StarboardDrmKeyStatus> key_statuses);
-
-  // Calls OnCertificateUpdated for `context`, which is an instance of
-  // StarboardDecryptorCast.
-  static void CallOnCertificateUpdated(void* drm_system,
-                                       void* context,
-                                       int ticket,
-                                       StarboardDrmStatus status,
-                                       std::string error_message);
-
-  // Calls OnSessionClosed for `context`, which is an instance of
-  // StarboardDecryptorCast.
-  static void CallOnSessionClosed(void* drm_system,
-                                  void* context,
-                                  std::string session_id);
+      std::vector<StarboardDrmKeyStatus> key_statuses) override;
+  void OnCertificateUpdated(int ticket,
+                            StarboardDrmStatus status,
+                            std::string error_message) override;
+  void OnSessionClosed(std::string session_id) override;
 
   // Called when provisioning the device, in response to an individualization
   // request.
@@ -201,8 +141,6 @@
 
   THREAD_CHECKER(thread_checker_);
   ::media::CreateFetcherCB create_provision_fetcher_cb_;
-  StarboardDrmSystemCallbackHandler callback_handler_;
-  std::unique_ptr<StarboardApiWrapper> starboard_;
   bool server_certificate_updatable_ = false;
   std::queue<SessionRequest> queued_session_requests_;
 
@@ -220,8 +158,6 @@
   // create/load operations should be queued.
   bool pending_session_setup_ = false;
 
-  // An opaque handle to an SbDrmSystem instance.
-  void* drm_system_ = nullptr;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   std::unique_ptr<::media::ProvisionFetcher> provision_fetcher_;
 
diff --git a/chromecast/starboard/media/cdm/starboard_decryptor_cast_test.cc b/chromecast/starboard/media/cdm/starboard_decryptor_cast_test.cc
index a26e86f2..13052bf 100644
--- a/chromecast/starboard/media/cdm/starboard_decryptor_cast_test.cc
+++ b/chromecast/starboard/media/cdm/starboard_decryptor_cast_test.cc
@@ -7,11 +7,13 @@
 #include <algorithm>
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include "base/functional/callback.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "chromecast/starboard/media/cdm/starboard_drm_key_tracker.h"
+#include "chromecast/starboard/media/cdm/starboard_drm_wrapper.h"
 #include "chromecast/starboard/media/media/mock_starboard_api_wrapper.h"
 #include "chromecast/starboard/media/media/starboard_api_wrapper.h"
 #include "media/base/cdm_callback_promise.h"
@@ -50,8 +52,8 @@
 
 // Checks that a const void* arg matches a string.
 //
-// str is an std::string, arg is a const void*. Only the first str.length()
-// characters will be checked.
+// str is an std::string (or std::string_view), arg is a const void*. Only the
+// first str.length() characters will be checked.
 MATCHER_P(StrEqWhenCast, str, "") {
   const char* c_str_arg = static_cast<const char*>(arg);
   if (!c_str_arg) {
@@ -75,10 +77,12 @@
   return ExplainMatchResult(StartsWith(str), arg.spec(), result_listener);
 }
 
-// Returns the number of elements in a C array.
-template <typename T, size_t n>
-constexpr size_t NumElements(const T (&)[n]) {
-  return n;
+// Runs any currently-queued tasks.
+void RunQueuedTasks() {
+  base::RunLoop run_loop;
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE, run_loop.QuitClosure());
+  run_loop.Run();
 }
 
 class MockProvisionFetcher : public ProvisionFetcher {
@@ -150,11 +154,18 @@
           base::Unretained(this)),
       /*media_resource_tracker=*/nullptr);
 
-  const std::string provision_request_data = "request data";
+  const std::string license_request_data_str = "license request data";
+  base::span<const uint8_t> license_request_data =
+      base::as_byte_span(license_request_data_str);
+  const std::string provision_request_data = "provision_request data";
   const base::span<const uint8_t> provision_request_span =
       base::as_byte_span(provision_request_data);
-  const std::string provision_response_data = "response data";
+  const std::string provision_response_data = "provision_response data";
   const std::string session_id = "some_session";
+  const std::string error_message = "";
+  // This is generated by StarboardDrmWrapper; we capture the ticket in a
+  // callback below.
+  int ticket = StarboardDrmWrapper::kInvalidTicket;
 
   // This will get populated by decryptor.
   const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
@@ -163,6 +174,9 @@
   EXPECT_CALL(*starboard_, CreateDrmSystem("com.widevine.alpha", _))
       .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
                       Return(&fake_drm_system_)));
+  EXPECT_CALL(*starboard_, DrmGenerateSessionUpdateRequest(&fake_drm_system_, _,
+                                                           StrEq("cenc"), _, _))
+      .WillOnce(SaveArg<1>(&ticket));
   EXPECT_CALL(*starboard_,
               DrmUpdateSession(&fake_drm_system_, _,
                                StrEqWhenCast(provision_response_data),
@@ -170,7 +184,9 @@
                                StrEqWhenCast(session_id), session_id.size()))
       .Times(1);
 
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
+  std::string actual_session_id;
+  bool resolved_promise = false;
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
@@ -192,16 +208,45 @@
             std::move(response_callback).Run(true, provision_response_data);
           }));
 
-  // Trigger the provision request.
+  // First trigger the session creation.
+  decryptor->CreateSessionAndGenerateRequest(
+      ::media::CdmSessionType::kTemporary, ::media::EmeInitDataType::CENC,
+      /*init_data=*/{1, 2, 3, 4},
+      std::make_unique<::media::CdmCallbackPromise<std::string>>(
+          /*resolve_cb=*/base::BindOnce(
+              +[](bool* b, std::string* out_session_id,
+                  const std::string& session_id) {
+                CHECK(b != nullptr);
+                CHECK(out_session_id != nullptr);
+                *b = true;
+                *out_session_id = session_id;
+              },
+              &resolved_promise, &actual_session_id),
+          /*reject_cb=*/base::BindOnce(
+              +[](::media::CdmPromise::Exception exception_code,
+                  uint32_t system_code, const std::string& error_message) {
+                LOG(ERROR) << "Rejected promise with system code "
+                           << system_code << " and error message "
+                           << error_message;
+              })));
 
-  // This ticket does not need to match an existing ticket from decryptor, since
-  // Starboard initializes provisioning.
-  const int ticket = 123;
-  const std::string error_message = "";
+  // Now simulate the DRM system requesting provisioning from cast. In
+  // production scenarios, the DRM system first sends a license request for the
+  // given ticket, and then sends an individualization (provisioning) request
+  // with the invalid ticket ID (signifying that the request was triggered by
+  // the SbDrmSystem itself).
+  EXPECT_NE(ticket, StarboardDrmWrapper::kInvalidTicket);
   ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
   decryptor_provided_callbacks->update_request_fn(
       &fake_drm_system_, decryptor_provided_callbacks->context, ticket,
-      kStarboardDrmStatusSuccess,
+      kStarboardDrmStatusSuccess, kStarboardDrmSessionRequestTypeLicenseRequest,
+      error_message, session_id,
+      std::vector<uint8_t>(license_request_data.begin(),
+                           license_request_data.end()),
+      "");
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, decryptor_provided_callbacks->context,
+      StarboardDrmWrapper::kInvalidTicket, kStarboardDrmStatusSuccess,
       kStarboardDrmSessionRequestTypeIndividualizationRequest, error_message,
       session_id,
       std::vector<uint8_t>(provision_request_span.begin(),
@@ -210,14 +255,138 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
+}
+
+TEST_F(StarboardDecryptorCastTest,
+       DoesNotResolveProvisionPromiseUntilResponseIsReceived) {
+  auto decryptor = base::MakeRefCounted<StarboardDecryptorCast>(
+      /*create_provision_fetcher_cb=*/base::BindRepeating(
+          &StarboardDecryptorCastTest::CreateProvisionFetcher,
+          base::Unretained(this)),
+      /*media_resource_tracker=*/nullptr);
+
+  const std::string provision_request_data_str = "request data";
+  base::span<const uint8_t> provision_request_data =
+      base::as_byte_span(provision_request_data_str);
+  const std::string provision_response_data = "response data";
+  const std::string session_id = "some_session";
+  const ::media::EmeInitDataType init_type = ::media::EmeInitDataType::CENC;
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+
+  // This will get populated by decryptor.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+
+  EXPECT_CALL(*starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+
+  int update_session_ticket = -1;
+  EXPECT_CALL(*starboard_,
+              DrmUpdateSession(&fake_drm_system_, _,
+                               StrEqWhenCast(provision_response_data),
+                               provision_response_data.size(),
+                               StrEqWhenCast(session_id), session_id.size()))
+      .WillOnce(SaveArg<1>(&update_session_ticket));
+
+  int update_session_request_ticket = -1;
+  EXPECT_CALL(*starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq("cenc"),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&update_session_request_ticket));
+
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
+  decryptor->Initialize(
+      base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
+      base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
+      base::BindLambdaForTesting(session_keys_change_cb_.AsStdFunction()),
+      base::BindLambdaForTesting(
+          session_expiration_update_cb_.AsStdFunction()));
+
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+
+  base::OnceCallback<void(bool, const std::string&)> provision_callback;
+  // This provision fetcher will be returned when
+  // create_provision_fetcher_cb is called.
+  provision_fetcher_ = std::make_unique<MockProvisionFetcher>();
+  EXPECT_CALL(*provision_fetcher_,
+              Retrieve(GurlStartsWith(kProvisionServerUrl),
+                       StrEq(provision_request_data_str), _))
+      .WillOnce(WithArg<2>(
+          [&provision_callback](
+              base::OnceCallback<void(bool, const std::string&)> cb) {
+            provision_callback = std::move(cb);
+          }));
+
+  // These will be set to if the promise passed to
+  // CreateSessionAndGenerateRequest is resolved successfully.
+  bool resolved_promise = false;
+  std::string actual_session_id;
+
+  // Trigger the session creation.
+  decryptor->CreateSessionAndGenerateRequest(
+      ::media::CdmSessionType::kTemporary, init_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()),
+      std::make_unique<::media::CdmCallbackPromise<std::string>>(
+          /*resolve_cb=*/base::BindOnce(
+              +[](bool* b, std::string* out_session_id,
+                  const std::string& session_id) {
+                CHECK(b != nullptr);
+                CHECK(out_session_id != nullptr);
+                *b = true;
+                *out_session_id = session_id;
+              },
+              &resolved_promise, &actual_session_id),
+          /*reject_cb=*/base::BindOnce(
+              +[](::media::CdmPromise::Exception exception_code,
+                  uint32_t system_code, const std::string& error_message) {
+                LOG(ERROR) << "Rejected promise with system code "
+                           << system_code << " and error message "
+                           << error_message;
+              })));
+
+  // Trigger the provision request.
+
+  const std::string error_message = "";
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, decryptor_provided_callbacks->context,
+      update_session_request_ticket, kStarboardDrmStatusSuccess,
+      kStarboardDrmSessionRequestTypeIndividualizationRequest, error_message,
+      session_id,
+      std::vector<uint8_t>(provision_request_data.begin(),
+                           provision_request_data.end()),
+      "");
+
+  // The functions in decryptor_provided_callbacks post tasks to
+  // task_environment_.
+  RunQueuedTasks();
+
+  // Ensure that the session creation promise has not been resolved, since we
+  // did not receive a provisioning response yet.
+  EXPECT_FALSE(resolved_promise);
+
+  // Simulate a provisioning response. The promise should be resolved now.
+  ASSERT_FALSE(provision_callback.is_null());
+  std::move(provision_callback).Run(true, provision_response_data);
+
+  // Simulate starboard responding to the session update.
+  decryptor_provided_callbacks->session_updated_fn(
+      &fake_drm_system_, decryptor_provided_callbacks->context,
+      update_session_ticket, kStarboardDrmStatusSuccess, error_message,
+      session_id);
+
+  RunQueuedTasks();
+  EXPECT_TRUE(resolved_promise);
 }
 
 TEST_F(StarboardDecryptorCastTest, SendsSessionUpdateToStarboard) {
   const std::string session_id = "session_id";
-  const std::string key = "some_key";
-  std::vector<uint8_t> key_vec(key.size());
-  memcpy(key_vec.data(), key.c_str(), key_vec.size());
+  constexpr std::string_view key = "some_key";
+  base::span<const uint8_t> key_span = base::as_byte_span(key);
 
   auto decryptor = base::MakeRefCounted<StarboardDecryptorCast>(
       /*create_provision_fetcher_cb=*/base::BindRepeating(
@@ -241,7 +410,7 @@
                        StrEqWhenCast(session_id), session_id.size()))
       .WillOnce(SaveArg<1>(&ticket));
 
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
@@ -257,7 +426,7 @@
 
   // Trigger the session update.
   decryptor->UpdateSession(
-      session_id, key_vec,
+      session_id, std::vector<uint8_t>(key_span.begin(), key_span.end()),
       std::make_unique<::media::CdmCallbackPromise<>>(
           /*resolve_cb=*/base::BindOnce(
               +[](bool* b) {
@@ -281,22 +450,28 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
   EXPECT_TRUE(resolved_promise);
 }
 
 TEST_F(StarboardDecryptorCastTest, CallsKeyChangeCallbackOnKeyUpdate) {
   StarboardDrmKeyTracker::GetInstance().ClearStateForTesting();
 
-  const std::string session_id = "some_session";
   const std::vector<uint8_t> init_data = {0, 1, 2, 3};
-  const std::vector<uint8_t> key_id = {1, 2, 3, 4, 5, 6};
+  constexpr std::string_view key_id = "123456";
   const auto key_status = CdmKeyInformation::KeyStatus::USABLE;
   const uint32_t system_code = 0;
+  const std::string session_id = "some_session_id";
+  const std::string license_request_data_str = "license_data";
+  base::span<const uint8_t> license_request_data =
+      base::as_byte_span(license_request_data_str);
+
   // The starboard representation of key_id.
   StarboardDrmKeyId starboard_key_id;
-  CHECK_LE(key_id.size(), NumElements(starboard_key_id.identifier));
-  memcpy(starboard_key_id.identifier, key_id.data(), key_id.size());
+  // Safely copy the data from key_id into starboard_key_id.identifier.
+  base::span<uint8_t>(starboard_key_id.identifier)
+      .first<key_id.size()>()
+      .copy_from(base::as_byte_span(key_id));
   starboard_key_id.identifier_size = key_id.size();
   // The starboard representation of key_status.
   const StarboardDrmKeyStatus starboard_key_status =
@@ -312,12 +487,12 @@
   const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
       nullptr;
 
-  int actual_create_ticket = std::numeric_limits<int>::min();
+  int actual_create_ticket = StarboardDrmWrapper::kInvalidTicket;
   EXPECT_CALL(*starboard_, CreateDrmSystem("com.widevine.alpha", _))
       .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
                       Return(&fake_drm_system_)));
-  EXPECT_CALL(*starboard_,
-              DrmGenerateSessionUpdateRequest(&fake_drm_system_, _, _, _, _))
+  EXPECT_CALL(*starboard_, DrmGenerateSessionUpdateRequest(&fake_drm_system_, _,
+                                                           StrEq("cenc"), _, _))
       .WillOnce(SaveArg<1>(&actual_create_ticket));
 
   EXPECT_CALL(
@@ -329,7 +504,7 @@
                Field(&CdmKeyInformation::system_code, Eq(system_code)))))))
       .Times(1);
 
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
@@ -337,16 +512,19 @@
       base::BindLambdaForTesting(
           session_expiration_update_cb_.AsStdFunction()));
 
-  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
-  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
-  ASSERT_THAT(decryptor_provided_callbacks->key_statuses_changed_fn, NotNull());
+  // Trigger the session creation so that a session ID exists.
+  std::string actual_session_id;
 
   decryptor->CreateSessionAndGenerateRequest(
       ::media::CdmSessionType::kTemporary, ::media::EmeInitDataType::CENC,
       init_data,
       std::make_unique<::media::CdmCallbackPromise<std::string>>(
           /*resolve_cb=*/base::BindOnce(
-              +[](const std::string& /*session_id*/) {}),
+              +[](std::string* out_session_id, const std::string& session_id) {
+                CHECK(out_session_id != nullptr);
+                *out_session_id = session_id;
+              },
+              &actual_session_id),
           /*reject_cb=*/base::BindOnce(
               +[](::media::CdmPromise::Exception exception_code,
                   uint32_t system_code, const std::string& error_message) {
@@ -355,14 +533,19 @@
                            << error_message;
               })));
 
-  // Simulate a response for the session being created, so that the decryptor
-  // tracks the session ID.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->key_statuses_changed_fn, NotNull());
+
+  // Simulate the session creation.
+  EXPECT_NE(actual_create_ticket, StarboardDrmWrapper::kInvalidTicket);
   decryptor_provided_callbacks->update_request_fn(
       &fake_drm_system_, decryptor_provided_callbacks->context,
-      actual_create_ticket, StarboardDrmStatus::kStarboardDrmStatusSuccess,
-      StarboardDrmSessionRequestType::
-          kStarboardDrmSessionRequestTypeLicenseRequest,
-      "", session_id, {1}, "");
+      actual_create_ticket, kStarboardDrmStatusSuccess,
+      kStarboardDrmSessionRequestTypeLicenseRequest, "", session_id,
+      std::vector<uint8_t>(license_request_data.begin(),
+                           license_request_data.end()),
+      "");
 
   // Notify the decryptor that the key status changed. This should trigger the
   // expected call to session_keys_change_cb_ above.
@@ -372,7 +555,7 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
 
   // Verify that StarboardDrmKeyTracker was updated.
   const std::string key_str(reinterpret_cast<const char*>(key_id.data()),
@@ -382,6 +565,7 @@
   // Verify that the key is removed when the decryptor is destroyed.
   decryptor = nullptr;
   EXPECT_FALSE(StarboardDrmKeyTracker::GetInstance().HasKey(key_str));
+  EXPECT_EQ(actual_session_id, session_id);
 }
 
 TEST_F(StarboardDecryptorCastTest,
@@ -389,15 +573,22 @@
   StarboardDrmKeyTracker::GetInstance().ClearStateForTesting();
 
   const std::string session_id = "some_session";
-  const std::vector<uint8_t> key_id = {1, 2, 3, 4, 5, 6};
+  constexpr std::string_view key_id = "abcdef";
   const auto key_status = CdmKeyInformation::KeyStatus::USABLE;
   const auto key_released_status = CdmKeyInformation::KeyStatus::RELEASED;
   const uint32_t system_code = 0;
+  const std::string license_request_data_str = "license_request_data";
+  base::span<const uint8_t> license_request_data =
+      base::as_byte_span(license_request_data_str);
+
   // The starboard representation of key_id.
   StarboardDrmKeyId starboard_key_id;
-  CHECK_LE(key_id.size(), NumElements(starboard_key_id.identifier));
-  memcpy(starboard_key_id.identifier, key_id.data(), key_id.size());
+  // Safely copy the data from key_id into starboard_key_id.identifier.
+  base::span<uint8_t>(starboard_key_id.identifier)
+      .first<key_id.size()>()
+      .copy_from(base::as_byte_span(key_id));
   starboard_key_id.identifier_size = key_id.size();
+
   // The starboard representation of key_status.
   const StarboardDrmKeyStatus starboard_key_status =
       kStarboardDrmKeyStatusUsable;
@@ -414,15 +605,20 @@
   const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
       nullptr;
 
+  int ticket = StarboardDrmWrapper::kInvalidTicket;
   EXPECT_CALL(*starboard_, CreateDrmSystem("com.widevine.alpha", _))
       .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
                       Return(&fake_drm_system_)));
+  EXPECT_CALL(*starboard_, DrmGenerateSessionUpdateRequest(&fake_drm_system_, _,
+                                                           StrEq("cenc"), _, _))
+      .WillOnce(SaveArg<1>(&ticket));
 
   EXPECT_CALL(
       session_keys_change_cb_,
       Call(StrEq(session_id), true,
            ElementsAre(Pointee(AllOf(
-               Field(&CdmKeyInformation::key_id, ElementsAreArray(key_id)),
+               Field(&CdmKeyInformation::key_id,
+                     ElementsAreArray(base::as_byte_span(key_id))),
                Field(&CdmKeyInformation::status, Eq(key_status)),
                Field(&CdmKeyInformation::system_code, Eq(system_code)))))))
       .Times(1);
@@ -430,12 +626,13 @@
       session_keys_change_cb_,
       Call(StrEq(session_id), false,
            ElementsAre(Pointee(AllOf(
-               Field(&CdmKeyInformation::key_id, ElementsAreArray(key_id)),
+               Field(&CdmKeyInformation::key_id,
+                     ElementsAreArray(base::as_byte_span(key_id))),
                Field(&CdmKeyInformation::status, Eq(key_released_status)),
                Field(&CdmKeyInformation::system_code, Eq(system_code)))))))
       .Times(1);
 
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
@@ -443,8 +640,37 @@
       base::BindLambdaForTesting(
           session_expiration_update_cb_.AsStdFunction()));
 
+  // Trigger the session creation so that a session ID exists.
+  std::string actual_session_id;
+  decryptor->CreateSessionAndGenerateRequest(
+      ::media::CdmSessionType::kTemporary, ::media::EmeInitDataType::CENC,
+      /*init_data=*/{1, 2, 3, 4},
+      std::make_unique<::media::CdmCallbackPromise<std::string>>(
+          /*resolve_cb=*/base::BindOnce(
+              +[](std::string* out_session_id, const std::string& session_id) {
+                CHECK(out_session_id != nullptr);
+                *out_session_id = session_id;
+              },
+              &actual_session_id),
+          /*reject_cb=*/base::BindOnce(
+              +[](::media::CdmPromise::Exception exception_code,
+                  uint32_t system_code, const std::string& error_message) {
+                LOG(ERROR) << "Rejected promise with system code "
+                           << system_code << " and error message "
+                           << error_message;
+              })));
+
   ASSERT_THAT(decryptor_provided_callbacks, NotNull());
   ASSERT_THAT(decryptor_provided_callbacks->key_statuses_changed_fn, NotNull());
+  // Simulate the session creation.
+  EXPECT_NE(ticket, StarboardDrmWrapper::kInvalidTicket);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, decryptor_provided_callbacks->context, ticket,
+      kStarboardDrmStatusSuccess, kStarboardDrmSessionRequestTypeLicenseRequest,
+      "", session_id,
+      std::vector<uint8_t>(license_request_data.begin(),
+                           license_request_data.end()),
+      "");
   // Notify the decryptor that the key status changed. This should trigger the
   // expected call to session_keys_change_cb_ above.
   decryptor_provided_callbacks->key_statuses_changed_fn(
@@ -453,12 +679,11 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
 
   // Verify that StarboardDrmKeyTracker was updated.
-  const std::string key_str(reinterpret_cast<const char*>(key_id.data()),
-                            key_id.size());
-  EXPECT_TRUE(StarboardDrmKeyTracker::GetInstance().HasKey(key_str));
+  EXPECT_TRUE(
+      StarboardDrmKeyTracker::GetInstance().HasKey(std::string(key_id)));
 
   // Verify that the key is removed when the status changes to removed.
   decryptor_provided_callbacks->key_statuses_changed_fn(
@@ -467,9 +692,11 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
 
-  EXPECT_FALSE(StarboardDrmKeyTracker::GetInstance().HasKey(key_str));
+  EXPECT_FALSE(
+      StarboardDrmKeyTracker::GetInstance().HasKey(std::string(key_id)));
+  EXPECT_EQ(actual_session_id, session_id);
 }
 
 TEST_F(StarboardDecryptorCastTest, CreatesSessionAndGeneratesLicenseRequest) {
@@ -495,7 +722,7 @@
       .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
                       Return(&fake_drm_system_)));
   // This will be set when drm_generate_session_update_request_fn is called.
-  int ticket = -1;
+  int ticket = StarboardDrmWrapper::kInvalidTicket;
   EXPECT_CALL(*starboard_,
               DrmGenerateSessionUpdateRequest(
                   &fake_drm_system_, _, StrEq("cenc"),
@@ -509,7 +736,7 @@
                             content.size())))
       .Times(1);
 
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
@@ -548,6 +775,7 @@
 
   // Simulate starboard's response to drm_generate_session_update_request_fn.
   ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  EXPECT_NE(ticket, StarboardDrmWrapper::kInvalidTicket);
   decryptor_provided_callbacks->update_request_fn(
       &fake_drm_system_, decryptor_provided_callbacks->context, ticket,
       kStarboardDrmStatusSuccess, kStarboardDrmSessionRequestTypeLicenseRequest,
@@ -557,7 +785,7 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
   EXPECT_TRUE(resolved_promise);
   EXPECT_THAT(actual_session_id, StrEq(session_id));
 }
@@ -586,7 +814,7 @@
                       Return(&fake_drm_system_)));
 
   // This will be set when drm_generate_session_update_request_fn is called.
-  int ticket = -1;
+  int ticket = StarboardDrmWrapper::kInvalidTicket;
   EXPECT_CALL(*starboard_,
               DrmGenerateSessionUpdateRequest(
                   &fake_drm_system_, _, StrEq("cenc"),
@@ -600,7 +828,7 @@
                             content.size())))
       .Times(1);
 
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
@@ -639,6 +867,7 @@
 
   // Simulate starboard's response to drm_generate_session_update_request_fn.
   ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  EXPECT_NE(ticket, StarboardDrmWrapper::kInvalidTicket);
   decryptor_provided_callbacks->update_request_fn(
       &fake_drm_system_, decryptor_provided_callbacks->context, ticket,
       kStarboardDrmStatusSuccess, kStarboardDrmSessionRequestTypeLicenseRenewal,
@@ -648,7 +877,7 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
   EXPECT_TRUE(resolved_promise);
   EXPECT_THAT(actual_session_id, StrEq(session_id));
 }
@@ -679,7 +908,7 @@
       DrmCloseSession(&fake_drm_system_, session_id.c_str(), session_id.size()))
       .Times(1);
 
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
@@ -746,21 +975,21 @@
 
   // The functions in decryptor_provided_callbacks post tasks to
   // task_environment_.
-  task_environment_.RunUntilIdle();
+  RunQueuedTasks();
   EXPECT_TRUE(resolved_promise);
 }
 
-TEST_F(StarboardDecryptorCastTest, DestroysSbDrmSystemOnDestruction) {
+TEST_F(StarboardDecryptorCastTest, DoesNotDestroySbDrmSystemOnDestruction) {
   EXPECT_CALL(*starboard_, CreateDrmSystem("com.widevine.alpha", _))
       .WillOnce(Return(&fake_drm_system_));
-  EXPECT_CALL(*starboard_, DrmDestroySystem(&fake_drm_system_)).Times(1);
+  EXPECT_CALL(*starboard_, DrmDestroySystem).Times(0);
 
   auto decryptor = base::MakeRefCounted<StarboardDecryptorCast>(
       /*create_provision_fetcher_cb=*/base::BindRepeating(
           &StarboardDecryptorCastTest::CreateProvisionFetcher,
           base::Unretained(this)),
       /*media_resource_tracker=*/nullptr);
-  decryptor->SetStarboardApiWrapperForTest(std::move(starboard_));
+  StarboardDrmWrapper::SetSingletonForTesting(starboard_.get());
   decryptor->Initialize(
       base::BindLambdaForTesting(session_message_cb_.AsStdFunction()),
       base::BindLambdaForTesting(session_closed_cb_.AsStdFunction()),
diff --git a/chromecast/starboard/media/cdm/starboard_drm_wrapper.cc b/chromecast/starboard/media/cdm/starboard_drm_wrapper.cc
new file mode 100644
index 0000000..3a46b55
--- /dev/null
+++ b/chromecast/starboard/media/cdm/starboard_drm_wrapper.cc
@@ -0,0 +1,476 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/starboard/media/cdm/starboard_drm_wrapper.h"
+
+#include "base/at_exit.h"
+#include "base/check.h"
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+// For tests, this needs to be set/cleared in each test.
+StarboardDrmWrapper* g_test_drm_wrapper = nullptr;
+
+}  // namespace
+
+StarboardDrmWrapper::Client::~Client() {
+  StarboardDrmWrapper::GetInstance().RemoveClient(this);
+}
+
+void StarboardDrmWrapper::RemoveClient(Client* client) {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  LOG(INFO) << "StarboardDrmWrapper::RemoveClient(client=" << client << ")";
+
+  // Update session_id_to_client_.
+  {
+    auto it = session_id_to_client_.begin();
+    while (it != session_id_to_client_.end()) {
+      if (it->second == client) {
+        LOG(INFO) << "Removing session_id=" << it->first
+                  << " for client=" << client;
+        it = session_id_to_client_.erase(it);
+      } else {
+        ++it;
+      }
+    }
+  }
+
+  // Update ticket_to_client_.
+  {
+    auto it = ticket_to_client_.begin();
+    while (it != ticket_to_client_.end()) {
+      if (it->second == client) {
+        LOG(INFO) << "Removing internal ticket=" << it->first
+                  << " for client=" << client;
+        it = ticket_to_client_.erase(it);
+      } else {
+        ++it;
+      }
+    }
+  }
+}
+
+void StarboardDrmWrapper::CallOnSessionUpdateRequest(
+    void* drm_system,
+    void* context,
+    int ticket,
+    StarboardDrmStatus status,
+    StarboardDrmSessionRequestType type,
+    std::string error_message,
+    std::string session_id,
+    std::vector<uint8_t> content,
+    std::string url) {
+  reinterpret_cast<StarboardDrmWrapper*>(context)->OnSessionUpdateRequest(
+      ticket, status, type, std::move(error_message), std::move(session_id),
+      std::move(content));
+}
+
+void StarboardDrmWrapper::CallOnSessionUpdated(void* drm_system,
+                                               void* context,
+                                               int ticket,
+                                               StarboardDrmStatus status,
+                                               std::string error_message,
+                                               std::string session_id) {
+  reinterpret_cast<StarboardDrmWrapper*>(context)->OnSessionUpdated(
+      ticket, status, std::move(error_message), std::move(session_id));
+}
+
+void StarboardDrmWrapper::CallOnKeyStatusesChanged(
+    void* drm_system,
+    void* context,
+    std::string session_id,
+    std::vector<StarboardDrmKeyId> key_ids,
+    std::vector<StarboardDrmKeyStatus> key_statuses) {
+  reinterpret_cast<StarboardDrmWrapper*>(context)->OnKeyStatusesChanged(
+      std::move(session_id), std::move(key_ids), std::move(key_statuses));
+}
+
+void StarboardDrmWrapper::CallOnServerCertificateUpdated(
+    void* drm_system,
+    void* context,
+    int ticket,
+    StarboardDrmStatus status,
+    std::string error_message) {
+  reinterpret_cast<StarboardDrmWrapper*>(context)->OnServerCertificateUpdated(
+      ticket, status, std::move(error_message));
+}
+
+void StarboardDrmWrapper::CallOnSessionClosed(void* drm_system,
+                                              void* context,
+                                              std::string session_id) {
+  reinterpret_cast<StarboardDrmWrapper*>(context)->OnSessionClosed(
+      std::move(session_id));
+}
+
+void StarboardDrmWrapper::OnSessionUpdateRequest(
+    int ticket,
+    StarboardDrmStatus status,
+    StarboardDrmSessionRequestType type,
+    std::string error_message,
+    std::string session_id,
+    std::vector<uint8_t> content) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
+    // base::Unretained is safe here because this class is a singleton.
+    task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&StarboardDrmWrapper::OnSessionUpdateRequest,
+                                  base::Unretained(this), ticket, status, type,
+                                  std::move(error_message),
+                                  std::move(session_id), std::move(content)));
+    return;
+  }
+
+  LOG(INFO) << "StarboardDrmWrapper::OnSessionUpdateRequest(ticket=" << ticket
+            << ", status=" << status << ", type=" << type
+            << ", error_message=" << error_message
+            << ", session_id=" << session_id << ")";
+
+  Client* client = FindClient(ticket, session_id);
+  if (client == nullptr) {
+    LOG(ERROR) << "OnSessionUpdateRequest failed to find client for internal "
+                  "DRM ticket="
+               << ticket << ", session_id=" << session_id;
+    return;
+  }
+
+  auto it_and_was_inserted = session_id_to_client_.insert({session_id, client});
+  auto it = it_and_was_inserted.first;
+  const bool was_inserted = it_and_was_inserted.second;
+
+  if (!was_inserted) {
+    // This is normal, e.g. during provisioning. We may want to add a check if
+    // the client is different from the one in the map, though.
+    LOG(INFO) << "Client already exists for session ID=" << session_id
+              << ". Existing client=" << it->second
+              << ". New client=" << client;
+  }
+
+  client->OnSessionUpdateRequest(FindClientTicket(ticket), status, type,
+                                 std::move(error_message),
+                                 std::move(session_id), std::move(content));
+}
+
+void StarboardDrmWrapper::OnSessionUpdated(int ticket,
+                                           StarboardDrmStatus status,
+                                           std::string error_message,
+                                           std::string session_id) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
+    // base::Unretained is safe here because this class is a singleton.
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&StarboardDrmWrapper::OnSessionUpdated,
+                       base::Unretained(this), ticket, status,
+                       std::move(error_message), std::move(session_id)));
+    return;
+  }
+
+  LOG(INFO) << "StarboardDrmWrapper::OnSessionUpdated(ticket=" << ticket
+            << ", status=" << status << ", error_message=" << error_message
+            << ", session_id=" << session_id << ")";
+
+  Client* client = FindClient(ticket, session_id);
+  if (client == nullptr) {
+    LOG(ERROR)
+        << "OnSessionUpdated failed to find client for internal DRM ticket="
+        << ticket << ", session_id=" << session_id;
+    return;
+  }
+
+  client->OnSessionUpdated(FindClientTicket(ticket), status,
+                           std::move(error_message), std::move(session_id));
+}
+
+void StarboardDrmWrapper::OnKeyStatusesChanged(
+    std::string session_id,
+    std::vector<StarboardDrmKeyId> key_ids,
+    std::vector<StarboardDrmKeyStatus> key_statuses) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
+    // base::Unretained is safe here because this class is a singleton.
+    task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&StarboardDrmWrapper::OnKeyStatusesChanged,
+                                  base::Unretained(this), std::move(session_id),
+                                  std::move(key_ids), std::move(key_statuses)));
+    return;
+  }
+
+  LOG(INFO) << "StarboardDrmWrapper::OnKeyStatusesChanged(session_id="
+            << session_id << ", num_keys=" << key_ids.size() << ")";
+
+  Client* client = FindClient(/*ticket=*/kInvalidTicket, session_id);
+  if (client == nullptr) {
+    LOG(ERROR) << "OnKeyStatusesChanged failed to find client for session_id="
+               << session_id;
+    return;
+  }
+  client->OnKeyStatusesChanged(session_id, std::move(key_ids),
+                               std::move(key_statuses));
+}
+
+void StarboardDrmWrapper::OnServerCertificateUpdated(
+    int ticket,
+    StarboardDrmStatus status,
+    std::string error_message) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
+    // base::Unretained is safe here because this class is a singleton.
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&StarboardDrmWrapper::OnServerCertificateUpdated,
+                       base::Unretained(this), ticket, status,
+                       std::move(error_message)));
+    return;
+  }
+
+  LOG(INFO) << "StarboardDrmWrapper::OnServerCertificateUpdated(ticket="
+            << ticket << ", status=" << status
+            << ", error_message=" << error_message << ")";
+
+  Client* client = FindClient(ticket, /*session_id=*/"");
+  if (client == nullptr) {
+    LOG(ERROR) << "OnCertificateUpdated failed to find client for internal "
+                  "DRM ticket="
+               << ticket;
+    return;
+  }
+  client->OnCertificateUpdated(FindClientTicket(ticket), status,
+                               std::move(error_message));
+}
+
+void StarboardDrmWrapper::OnSessionClosed(std::string session_id) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
+    // base::Unretained is safe here because this class is a singleton.
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&StarboardDrmWrapper::OnSessionClosed,
+                       base::Unretained(this), std::move(session_id)));
+    return;
+  }
+
+  LOG(INFO) << "StarboardDrmWrapper::OnSessionClosed(session_id=" << session_id
+            << ")";
+
+  auto it = session_id_to_client_.find(session_id);
+  if (it == session_id_to_client_.end()) {
+    LOG(ERROR) << "OnSessionClosed failed to find client for session_id="
+               << session_id;
+    return;
+  }
+  it->second->OnSessionClosed(std::move(session_id));
+
+  LOG(INFO) << "Removing mapping from session_id=" << it->first
+            << " to client=" << it->second;
+  // Remove the session ID mapping, since the session is closed.
+  session_id_to_client_.erase(it);
+}
+
+StarboardDrmWrapper::Client* StarboardDrmWrapper::FindClient(
+    int internal_ticket,
+    const std::string& session_id) {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  auto ticket_it = ticket_to_client_.find(internal_ticket);
+  if (ticket_it != ticket_to_client_.end()) {
+    Client* client = ticket_it->second;
+    LOG(INFO) << "Found client=" << client
+              << " for internal ticket=" << internal_ticket;
+    ticket_to_client_.erase(ticket_it);
+    return client;
+  }
+
+  auto session_it = session_id_to_client_.find(session_id);
+  if (session_it != session_id_to_client_.end()) {
+    LOG(INFO) << "Found client=" << session_it->second
+              << " for session=" << session_id;
+    return session_it->second;
+  }
+  return nullptr;
+}
+
+int StarboardDrmWrapper::FindClientTicket(int internal_ticket) {
+  auto it = ticket_map_.find(internal_ticket);
+  if (it == ticket_map_.end()) {
+    return kInvalidTicket;
+  }
+  const int client_ticket = it->second;
+  ticket_map_.erase(it);
+
+  LOG(INFO) << "Internal ticket=" << internal_ticket
+            << " maps to client ticket=" << client_ticket;
+  return client_ticket;
+}
+
+void StarboardDrmWrapper::GenerateSessionUpdateRequest(
+    Client* client,
+    int ticket,
+    const std::string& type,
+    const std::vector<uint8_t>& init_data) {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  const int internal_ticket = GetNextTicket();
+  ticket_map_[internal_ticket] = ticket;
+  ticket_to_client_[internal_ticket] = client;
+
+  starboard_->DrmGenerateSessionUpdateRequest(drm_system_, internal_ticket,
+                                              type.c_str(), init_data.data(),
+                                              init_data.size());
+}
+
+void StarboardDrmWrapper::UpdateSession(Client* client,
+                                        int ticket,
+                                        const std::string& session_id,
+                                        const std::vector<uint8_t>& key) {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  const int internal_ticket = GetNextTicket();
+  ticket_map_[internal_ticket] = ticket;
+  ticket_to_client_[internal_ticket] = client;
+
+  // This will eventually call OnSessionUpdated.
+  starboard_->DrmUpdateSession(drm_system_, internal_ticket, key.data(),
+                               key.size(), session_id.c_str(),
+                               session_id.size());
+}
+
+void StarboardDrmWrapper::CloseSession(Client* client,
+                                       const std::string& session_id) {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  auto it_and_inserted = session_id_to_client_.insert({session_id, client});
+  auto it = it_and_inserted.first;
+  const bool inserted = it_and_inserted.second;
+
+  // If a session is closing, it is expected that we were already tracking that
+  // session and its client. This condition checks whether the insertion
+  // occurred, meaning we were NOT tracking the session.
+  if (inserted) {
+    LOG(WARNING) << "Closing session_id=" << session_id
+                 << ", which was not being tracked";
+  }
+
+  if (it->second != client) {
+    LOG(WARNING) << "client=" << client
+                 << " is closing session_id=" << session_id
+                 << ", which was created for client=" << it->second;
+  }
+  starboard_->DrmCloseSession(drm_system_, session_id.c_str(),
+                              session_id.size());
+}
+
+bool StarboardDrmWrapper::IsServerCertificateUpdatable() {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  return starboard_->DrmIsServerCertificateUpdatable(drm_system_);
+}
+
+void StarboardDrmWrapper::UpdateServerCertificate(
+    Client* client,
+    int ticket,
+    const std::vector<uint8_t>& certificate_data) {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  const int internal_ticket = GetNextTicket();
+  ticket_map_[internal_ticket] = ticket;
+  ticket_to_client_[internal_ticket] = client;
+
+  starboard_->DrmUpdateServerCertificate(drm_system_, internal_ticket,
+                                         certificate_data.data(),
+                                         certificate_data.size());
+}
+
+int StarboardDrmWrapper::GetNextTicket() {
+  CHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  const int ticket = ticket_++;
+  if (ticket_ == kInvalidTicket) {
+    ++ticket_;
+  }
+  return ticket;
+}
+
+StarboardDrmWrapper::StarboardDrmWrapper()
+    : task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
+  // This is the version of the constructor that runs in production. As such, we
+  // should properly destroy the SbDrmSystem via an AtExitManager.
+  //
+  // Use of base::Unretained is safe because this object should never be
+  // destructed in production code (it's a private destructor, and the only code
+  // that destroys it is the test-only function SetSingletonForTesting).
+  chromecast::CastStarboardApiAdapter::GetInstance()->Subscribe(this, nullptr);
+  base::AtExitManager::RegisterTask(base::BindOnce(
+      &StarboardDrmWrapper::DestroySbDrmSystem, base::Unretained(this)));
+
+  owned_starboard_ = GetStarboardApiWrapper();
+  starboard_ = owned_starboard_.get();
+  CHECK(starboard_->EnsureInitialized()) << "Failed to initialize starboard";
+
+  drm_system_ = starboard_->CreateDrmSystem(
+      /*key_system=*/"com.widevine.alpha",
+      /*callback_handler=*/&callback_handler_);
+  CHECK(drm_system_) << "Failed to create an SbDrmSystem";
+  LOG(INFO) << "Created DRM system with address " << drm_system_;
+}
+
+StarboardDrmWrapper::StarboardDrmWrapper(StarboardApiWrapper* starboard)
+    : task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
+  CHECK(starboard);
+  starboard_ = starboard;
+  drm_system_ = starboard_->CreateDrmSystem(
+      /*key_system=*/"com.widevine.alpha",
+      /*callback_handler=*/&callback_handler_);
+  CHECK(drm_system_) << "Failed to create an SbDrmSystem";
+  LOG(INFO) << "Created DRM system with address " << drm_system_;
+}
+
+StarboardDrmWrapper::~StarboardDrmWrapper() = default;
+
+void StarboardDrmWrapper::DestroySbDrmSystem() {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
+    // base::Unretained is safe because this class is a singleton.
+    task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&StarboardDrmWrapper::DestroySbDrmSystem,
+                                  base::Unretained(this)));
+    return;
+  }
+
+  LOG(INFO) << "Destroying SbDrmSystem because core_runtime is shutting down.";
+  starboard_->DrmDestroySystem(drm_system_);
+  chromecast::CastStarboardApiAdapter::GetInstance()->Unsubscribe(this);
+
+  // We need to destroy owned_starboard_ here, so that it unsubscribes from
+  // CastStarboardApiAdapter.
+  owned_starboard_ = nullptr;
+  starboard_ = nullptr;
+  // TODO(antoniori): maybe add checks in other places to ensure that we crash
+  // if attempting to use starboard_ after this point.
+}
+
+StarboardDrmWrapper& StarboardDrmWrapper::GetInstance() {
+  if (g_test_drm_wrapper) {
+    return *g_test_drm_wrapper;
+  }
+
+  static base::NoDestructor<StarboardDrmWrapper> instance;
+  return *instance;
+}
+
+void* StarboardDrmWrapper::GetDrmSystem() {
+  return drm_system_;
+}
+
+void StarboardDrmWrapper::SetSingletonForTesting(
+    StarboardApiWrapper* starboard) {
+  LOG(INFO) << "Overriding StarboardDrmWrapper singleton for testing";
+  if (g_test_drm_wrapper) {
+    delete g_test_drm_wrapper;
+  }
+  g_test_drm_wrapper = new StarboardDrmWrapper(starboard);
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/cdm/starboard_drm_wrapper.h b/chromecast/starboard/media/cdm/starboard_drm_wrapper.h
new file mode 100644
index 0000000..186a4dc
--- /dev/null
+++ b/chromecast/starboard/media/cdm/starboard_drm_wrapper.h
@@ -0,0 +1,250 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_STARBOARD_MEDIA_CDM_STARBOARD_DRM_WRAPPER_H_
+#define CHROMECAST_STARBOARD_MEDIA_CDM_STARBOARD_DRM_WRAPPER_H_
+
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/functional/callback.h"
+#include "base/no_destructor.h"
+#include "base/task/sequenced_task_runner.h"
+#include "chromecast/starboard/media/media/starboard_api_wrapper.h"
+
+namespace chromecast {
+namespace media {
+
+// A wrapper around a single SbDrmSystem instance. This class supports
+// multiplexing calls from multiple callers (Clients).
+//
+// This class must only be accessed on a single sequence. It is expected to be
+// used as a singleton, via GetInstance(). Its destructor should not run in
+// production code.
+class StarboardDrmWrapper {
+ public:
+  // This must match the definition of kSbDrmTicketInvalid in starboard/drm.h.
+  static constexpr int kInvalidTicket = std::numeric_limits<int>::min();
+
+  // A client that interacts with a StarboardDrmWrapper to make DRM-related
+  // calls into starboard.
+  class Client {
+   public:
+    virtual ~Client();
+
+    // Called when a new session has been created.
+    virtual void OnSessionUpdateRequest(int ticket,
+                                        StarboardDrmStatus status,
+                                        StarboardDrmSessionRequestType type,
+                                        std::string error_message,
+                                        std::string session_id,
+                                        std::vector<uint8_t> content) = 0;
+
+    // Called once a session has been updated.
+    virtual void OnSessionUpdated(int ticket,
+                                  StarboardDrmStatus status,
+                                  std::string error_message,
+                                  std::string session_id) = 0;
+
+    // Called when the status of keys change.
+    virtual void OnKeyStatusesChanged(
+        std::string session_id,
+        std::vector<StarboardDrmKeyId> key_ids,
+        std::vector<StarboardDrmKeyStatus> key_statuses) = 0;
+
+    // Called when a certificate has been updated.
+    virtual void OnCertificateUpdated(int ticket,
+                                      StarboardDrmStatus status,
+                                      std::string error_message) = 0;
+
+    // Called when a session has closed.
+    virtual void OnSessionClosed(std::string session_id) = 0;
+  };
+
+  // Returns a handle to the SbDrmSystem singleton. All calls to starboard for
+  // DRM should go through this.
+  static StarboardDrmWrapper& GetInstance();
+
+  // Disallow copy and assign.
+  StarboardDrmWrapper(const StarboardDrmWrapper&) = delete;
+  StarboardDrmWrapper& operator=(const StarboardDrmWrapper&) = delete;
+
+  // Returns the handle to the SbDrmSystem. This should only be called for the
+  // purpose of creating the SbPlayer. Any calls to SbDrmSystem should go
+  // through GetInstance().
+  void* GetDrmSystem();
+
+  // Tells starboard to generate a session update request (e.g. a license
+  // request).
+  void GenerateSessionUpdateRequest(Client* client,
+                                    int ticket,
+                                    const std::string& type,
+                                    const std::vector<uint8_t>& init_data);
+
+  // Updates a session in starboard, e.g. making a key from the license server
+  // available for a given session.
+  void UpdateSession(Client* client,
+                     int ticket,
+                     const std::string& session_id,
+                     const std::vector<uint8_t>& key);
+
+  // Closes the specified session.
+  void CloseSession(Client* client, const std::string& session_id);
+
+  // Updates the server certificate. This should only be called if
+  // IsServerCertificateUpdatable() returns true.
+  void UpdateServerCertificate(Client* client,
+                               int ticket,
+                               const std::vector<uint8_t>& certificate_data);
+
+  // Returns whether the server certificate can be updated.
+  bool IsServerCertificateUpdatable();
+
+  static void SetSingletonForTesting(StarboardApiWrapper* starboard);
+
+ private:
+  friend base::NoDestructor<StarboardDrmWrapper>;
+
+  StarboardDrmWrapper();
+
+  // Test-only constructor. Used in SetSingletonForTesting.
+  explicit StarboardDrmWrapper(StarboardApiWrapper* starboard);
+
+  virtual ~StarboardDrmWrapper();
+
+  // Destroys the owned SbDrmSystem and unsubscribes from
+  // CastStarboardApiAdapter. This should only be called when the cast runtime
+  // is stopping.
+  void DestroySbDrmSystem();
+
+  // Returns the next internal ticket. Avoids returning kSbDrmTicketInvalid.
+  // Must be called on task_runner_.
+  int GetNextTicket();
+
+  // Called by a Client upon deletion. This tells StarboardDrmWrapper that it
+  // can clean up any mappings to/from that client in its internal data
+  // structures. Must be called on task_runner_.
+  void RemoveClient(Client* client);
+
+  // Attempts to find a client by `internal_ticket`. If that fails, attempts to
+  // find a client by `session_id`. Returns null if a client was not found.
+  Client* FindClient(int internal_ticket, const std::string& session_id);
+
+  // Finds a client's ticket by looking up the mapping from `internal_ticket` ->
+  // client ticket.
+  int FindClientTicket(int internal_ticket);
+
+  // These functions are called by starboard. In particular, a function F() is
+  // called via starboard calling the static function CallF() (defined below).
+  // These functions can be called on any sequence; they will post a task that
+  // runs on task_runner_ if necessary.
+  //
+  // See the documentation in starboard/drm.h for more information. These
+  // functions replace some C concepts with corresponding C++ ones for
+  // convenience/safety (e.g. replacing ptr + size with a vector).
+  void OnSessionUpdateRequest(int ticket,
+                              StarboardDrmStatus status,
+                              StarboardDrmSessionRequestType type,
+                              std::string error_message,
+                              std::string session_id,
+                              std::vector<uint8_t> content);
+  void OnSessionUpdated(int ticket,
+                        StarboardDrmStatus status,
+                        std::string error_message,
+                        std::string session_id);
+  void OnKeyStatusesChanged(std::string session_id,
+                            std::vector<StarboardDrmKeyId> key_ids,
+                            std::vector<StarboardDrmKeyStatus> key_statuses);
+  void OnServerCertificateUpdated(int ticket,
+                                  StarboardDrmStatus status,
+                                  std::string error_message);
+  void OnSessionClosed(std::string session_id);
+
+  // These functions are called directly as callbacks from starboard. See the
+  // documentation in starboard/drm.h for more info.
+  static void CallOnSessionUpdateRequest(void* drm_system,
+                                         void* context,
+                                         int ticket,
+                                         StarboardDrmStatus status,
+                                         StarboardDrmSessionRequestType type,
+                                         std::string error_message,
+                                         std::string session_id,
+                                         std::vector<uint8_t> content,
+                                         std::string url);
+  static void CallOnSessionUpdated(void* drm_system,
+                                   void* context,
+                                   int ticket,
+                                   StarboardDrmStatus status,
+                                   std::string error_message,
+                                   std::string session_id);
+  static void CallOnKeyStatusesChanged(
+      void* drm_system,
+      void* context,
+      std::string session_id,
+      std::vector<StarboardDrmKeyId> key_ids,
+      std::vector<StarboardDrmKeyStatus> key_statuses);
+  static void CallOnServerCertificateUpdated(void* drm_system,
+                                             void* context,
+                                             int ticket,
+                                             StarboardDrmStatus status,
+                                             std::string error_message);
+  static void CallOnSessionClosed(void* drm_system,
+                                  void* context,
+                                  std::string session_id);
+
+  // This gets passed to starboard, and tells starboard which functions to call
+  // for DRM callbacks.
+  StarboardDrmSystemCallbackHandler callback_handler_{
+      this,
+      &CallOnSessionUpdateRequest,
+      &CallOnSessionUpdated,
+      &CallOnKeyStatusesChanged,
+      &CallOnServerCertificateUpdated,
+      &CallOnSessionClosed};
+
+  // Keeps track of session IDs and the client associated with each.
+  base::flat_map<std::string, Client*> session_id_to_client_;
+
+  // Keeps track of internal tickets (from ticket_) and the Client they
+  // correspond to.
+  base::flat_map<int, Client*> ticket_to_client_;
+
+  // Maps from our internal ticket (ticket_) to the ticket passed in by the
+  // client. This is done in case multiple Clients interact with
+  // StarboardDrmWrapper, and they happen to pass the same ticket. Starboard
+  // requires that tickets be unique, otherwise there can be undefined behavior.
+  //
+  // Guarded by ticket_map_lock_, since this may be accessed on multiple
+  // sequences (Starboard's callbacks do not provide sequencing guarantees).
+  base::flat_map<int, int> ticket_map_;
+
+  // Per the documentation at starboard/drm.h, the ticket must not be INT_MIN.
+  // This is an internal ticket, not to be confused with client tickets. This
+  // allows us to handle multiple clients simultaneously. For example, two
+  // clients may each use the same ticket, but this unique ticket allows us to
+  // identify the correct response from starboard.
+  int ticket_ = 0;
+
+  // Pointer to the SbDrmSystem instance.
+  void* drm_system_ = nullptr;
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  // In production this points to the object owned by owned_starboard_. For
+  // tests, this may point to a mock (set via SetStarboardForTesting).
+  StarboardApiWrapper* starboard_ = nullptr;
+
+  // In production this will be populated with an owned instance of a
+  // StarboardApiWrapper. For tests, a mock may be used instead, and starboard_
+  // will point to that.
+  std::unique_ptr<StarboardApiWrapper> owned_starboard_;
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_STARBOARD_MEDIA_CDM_STARBOARD_DRM_WRAPPER_H_
diff --git a/chromecast/starboard/media/cdm/starboard_drm_wrapper_test.cc b/chromecast/starboard/media/cdm/starboard_drm_wrapper_test.cc
new file mode 100644
index 0000000..4bd6df2
--- /dev/null
+++ b/chromecast/starboard/media/cdm/starboard_drm_wrapper_test.cc
@@ -0,0 +1,702 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/starboard/media/cdm/starboard_drm_wrapper.h"
+
+#include <cstdint>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "base/test/task_environment.h"
+#include "chromecast/starboard/media/media/mock_starboard_api_wrapper.h"
+#include "chromecast/starboard/media/media/starboard_api_wrapper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace media {
+namespace {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::NotNull;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::StrEq;
+
+// Checks that a const void* arg matches a string.
+//
+// str is an std::string, arg is a const void*. Only the first str.length()
+// characters will be checked.
+MATCHER_P(StrEqWhenCast, str, "") {
+  const char* c_str_arg = static_cast<const char*>(arg);
+  if (!c_str_arg) {
+    *result_listener << "the argument is null";
+    return false;
+  }
+
+  if (strlen(c_str_arg) < str.length()) {
+    *result_listener << "the argument is too short";
+    return false;
+  }
+
+  return ExplainMatchResult(StrEq(str), std::string(c_str_arg, str.length()),
+                            result_listener);
+}
+
+// Checks that a StarboardDrmKeyId holds data matching a string.
+MATCHER_P(StarboardDrmKeyIdMatches, str, "") {
+  const StarboardDrmKeyId& key = arg;
+  CHECK_LE(str.size(), std::size(key.identifier))
+      << "The expected key must not be longer than "
+      << std::size(key.identifier) << " characters.";
+
+  if (key.identifier_size != static_cast<int>(str.size())) {
+    *result_listener << " size mismatch";
+    return false;
+  }
+
+  base::span<const uint8_t> key_view = key.identifier;
+  for (size_t i = 0; i < str.size(); ++i) {
+    if (key_view[i] != str[i]) {
+      *result_listener << " character mismatch at index " << i;
+      return false;
+    }
+  }
+  return true;
+}
+
+class MockStarboardDrmWrapperClient : public StarboardDrmWrapper::Client {
+ public:
+  MockStarboardDrmWrapperClient() = default;
+  ~MockStarboardDrmWrapperClient() override = default;
+
+  MOCK_METHOD(void,
+              OnSessionUpdateRequest,
+              (int ticket,
+               StarboardDrmStatus status,
+               StarboardDrmSessionRequestType type,
+               std::string error_message,
+               std::string session_id,
+               std::vector<uint8_t> content),
+              (override));
+
+  MOCK_METHOD(void,
+              OnSessionUpdated,
+              (int ticket,
+               StarboardDrmStatus status,
+               std::string error_message,
+               std::string session_id),
+              (override));
+
+  MOCK_METHOD(void,
+              OnKeyStatusesChanged,
+              (std::string session_id,
+               std::vector<StarboardDrmKeyId> key_ids,
+               std::vector<StarboardDrmKeyStatus> key_statuses),
+              (override));
+
+  MOCK_METHOD(void,
+              OnCertificateUpdated,
+              (int ticket,
+               StarboardDrmStatus status,
+               std::string error_message),
+              (override));
+
+  MOCK_METHOD(void, OnSessionClosed, (std::string session_id), (override));
+};
+
+// A test fixture is used to handle creation of a task environment and set up
+// the mocks to handle calls that are irrelevant to tests.
+//
+// We do not call StarboardDrmWrapper::SetSingletonForTesting in the constructor
+// since a mock should not be passed to production code until all expectations
+// have been set on it.
+class StarboardDrmWrapperTest : public ::testing::Test {
+ protected:
+  StarboardDrmWrapperTest() {
+    ON_CALL(starboard_, EnsureInitialized).WillByDefault(Return(true));
+  }
+
+  // This should be destructed last.
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  // This will be passed to the StarboardDecryptorCast, and all calls to
+  // Starboard will go through it. Thus, we can mock out those calls.
+  MockStarboardApiWrapper starboard_;
+  MockStarboardDrmWrapperClient client_;
+  // Since SbDrmSystem is just an opaque blob to the StarboardDecryptorCast, we
+  // will simply use an int to represent it.
+  int fake_drm_system_ = 1;
+};
+
+TEST_F(StarboardDrmWrapperTest, GeneratesSessionUpdateRequestForSuccessCase) {
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string content_str = "content";
+  base::span<const uint8_t> content = base::as_byte_span(content_str);
+  const std::string error_message = "";
+  const std::string session_id = "session_id";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusSuccess;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  const int ticket = 7;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_ticket = StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_ticket));
+  EXPECT_CALL(client_, OnSessionUpdateRequest(ticket, status, request_type,
+                                              error_message, session_id,
+                                              ElementsAreArray(content)))
+      .Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_, ticket, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+
+  // Simulate Starboard responding.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  EXPECT_NE(actual_wrapper_ticket, StarboardDrmWrapper::kInvalidTicket);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_ticket, status, request_type, error_message, session_id,
+      std::vector<uint8_t>(content.begin(), content.end()), url);
+}
+
+TEST_F(StarboardDrmWrapperTest, GeneratesSessionUpdateRequestForErrorCase) {
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string error_message = "expected error";
+  const std::string session_id = "";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusTypeError;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  const int ticket = 7;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_ticket = StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_ticket));
+  EXPECT_CALL(client_, OnSessionUpdateRequest(ticket, status, _, error_message,
+                                              session_id, IsEmpty()))
+      .Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_, ticket, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+
+  // Simulate Starboard responding with an error.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  EXPECT_NE(actual_wrapper_ticket, StarboardDrmWrapper::kInvalidTicket);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_ticket, status, request_type, error_message, session_id,
+      {}, url);
+}
+
+TEST_F(StarboardDrmWrapperTest, UpdatesSessionForSuccessCase) {
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string content_str = "content";
+  base::span<const uint8_t> content = base::as_byte_span(content_str);
+  constexpr std::string_view key = "key";
+  const std::string error_message = "";
+  const std::string session_id = "session_id";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusSuccess;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  const int generate_session_ticket = 7;
+  const int update_session_ticket = 200;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_generate_session_ticket =
+      StarboardDrmWrapper::kInvalidTicket;
+  int actual_wrapper_update_session_ticket =
+      StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_generate_session_ticket));
+  EXPECT_CALL(
+      starboard_,
+      DrmUpdateSession(&fake_drm_system_, _, StrEqWhenCast(key), key.size(),
+                       StrEqWhenCast(session_id), session_id.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_update_session_ticket));
+  EXPECT_CALL(client_,
+              OnSessionUpdateRequest(generate_session_ticket, status,
+                                     request_type, error_message, session_id,
+                                     ElementsAreArray(content)))
+      .Times(1);
+  EXPECT_CALL(client_, OnSessionUpdated(update_session_ticket, status,
+                                        error_message, session_id))
+      .Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_, generate_session_ticket, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+  base::span<const uint8_t> key_span = base::as_byte_span(key);
+  StarboardDrmWrapper::GetInstance().UpdateSession(
+      &client_, update_session_ticket, session_id,
+      std::vector<uint8_t>(key_span.begin(), key_span.end()));
+
+  // Simulate Starboard responding.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->session_updated_fn, NotNull());
+  EXPECT_NE(actual_wrapper_generate_session_ticket,
+            StarboardDrmWrapper::kInvalidTicket);
+  EXPECT_NE(actual_wrapper_update_session_ticket,
+            StarboardDrmWrapper::kInvalidTicket);
+
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_generate_session_ticket, status, request_type,
+      error_message, session_id,
+      std::vector<uint8_t>(content.begin(), content.end()), url);
+  decryptor_provided_callbacks->session_updated_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_update_session_ticket, status, error_message, session_id);
+}
+
+TEST_F(StarboardDrmWrapperTest, ForwardsKeyStatusUpdates) {
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string content_str = "content";
+  base::span<const uint8_t> content = base::as_byte_span(content_str);
+  constexpr std::string_view key = "key";
+  const std::string error_message = "";
+  const std::string session_id = "session_id";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusSuccess;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  const int generate_session_ticket = 7;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_generate_session_ticket =
+      StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_generate_session_ticket));
+  EXPECT_CALL(client_,
+              OnSessionUpdateRequest(generate_session_ticket, status,
+                                     request_type, error_message, session_id,
+                                     ElementsAreArray(content)))
+      .Times(1);
+  EXPECT_CALL(
+      client_,
+      OnKeyStatusesChanged(
+          session_id, ElementsAre(StarboardDrmKeyIdMatches(key)),
+          ElementsAre(StarboardDrmKeyStatus::kStarboardDrmKeyStatusUsable)))
+      .Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_, generate_session_ticket, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+
+  // Simulate Starboard responding, including a response that keys have been
+  // updated for the session.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->key_statuses_changed_fn, NotNull());
+  EXPECT_NE(actual_wrapper_generate_session_ticket,
+            StarboardDrmWrapper::kInvalidTicket);
+
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_generate_session_ticket, status, request_type,
+      error_message, session_id,
+      std::vector<uint8_t>(content.begin(), content.end()), url);
+  StarboardDrmKeyId key_id = {};
+  // Double-check that a memcpy is safe.
+  base::span<uint8_t>(key_id.identifier)
+      .take_first<key.size()>()
+      .copy_from(base::as_byte_span(key));
+  key_id.identifier_size = key.size();
+  const StarboardDrmKeyStatus key_status =
+      StarboardDrmKeyStatus::kStarboardDrmKeyStatusUsable;
+  decryptor_provided_callbacks->key_statuses_changed_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(), session_id,
+      {key_id}, {key_status});
+}
+
+TEST_F(StarboardDrmWrapperTest, UpdatesServerCertificates) {
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string content_str = "content";
+  base::span<const uint8_t> content = base::as_byte_span(content_str);
+  const std::string cert_str = "server_cert";
+  base::span<const uint8_t> cert = base::as_byte_span(cert_str);
+  const std::string error_message = "";
+  const std::string session_id = "session_id";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusSuccess;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  const int generate_session_ticket = 7;
+  const int update_cert_ticket = 9;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_generate_session_ticket =
+      StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_generate_session_ticket));
+  int actual_wrapper_update_cert_ticket = StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_, DrmUpdateServerCertificate(&fake_drm_system_, _,
+                                                     StrEqWhenCast(cert_str),
+                                                     cert_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_update_cert_ticket));
+  EXPECT_CALL(client_,
+              OnSessionUpdateRequest(generate_session_ticket, status,
+                                     request_type, error_message, session_id,
+                                     ElementsAreArray(content)))
+      .Times(1);
+  EXPECT_CALL(client_, OnCertificateUpdated(
+                           update_cert_ticket,
+                           StarboardDrmStatus::kStarboardDrmStatusSuccess, ""))
+      .Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_, generate_session_ticket, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+  StarboardDrmWrapper::GetInstance().UpdateServerCertificate(
+      &client_, update_cert_ticket,
+      std::vector<uint8_t>(cert.begin(), cert.end()));
+
+  // Simulate Starboard responding, including a response that the server cert
+  // has been updated.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->server_certificate_updated_fn,
+              NotNull());
+  EXPECT_NE(actual_wrapper_generate_session_ticket,
+            StarboardDrmWrapper::kInvalidTicket);
+  EXPECT_NE(actual_wrapper_update_cert_ticket,
+            StarboardDrmWrapper::kInvalidTicket);
+
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_generate_session_ticket, status, request_type,
+      error_message, session_id,
+      std::vector<uint8_t>(content.begin(), content.end()), url);
+  decryptor_provided_callbacks->server_certificate_updated_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_update_cert_ticket,
+      StarboardDrmStatus::kStarboardDrmStatusSuccess, error_message.c_str());
+}
+
+TEST_F(StarboardDrmWrapperTest, ClosesSession) {
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string content_str = "content";
+  base::span<const uint8_t> content = base::as_byte_span(content_str);
+  const std::string error_message = "";
+  const std::string session_id = "session_id";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusSuccess;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  const int generate_session_ticket = 7;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_generate_session_ticket =
+      StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_generate_session_ticket));
+  EXPECT_CALL(starboard_,
+              DrmCloseSession(&fake_drm_system_, StrEqWhenCast(session_id),
+                              session_id.size()));
+  EXPECT_CALL(client_,
+              OnSessionUpdateRequest(generate_session_ticket, status,
+                                     request_type, error_message, session_id,
+                                     ElementsAreArray(content)))
+      .Times(1);
+  EXPECT_CALL(client_, OnSessionClosed(session_id)).Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_, generate_session_ticket, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+  StarboardDrmWrapper::GetInstance().CloseSession(&client_, session_id);
+
+  // Simulate Starboard responding.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->session_closed_fn, NotNull());
+  EXPECT_NE(actual_wrapper_generate_session_ticket,
+            StarboardDrmWrapper::kInvalidTicket);
+
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_generate_session_ticket, status, request_type,
+      error_message, session_id,
+      std::vector<uint8_t>(content.begin(), content.end()), url);
+  decryptor_provided_callbacks->session_closed_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(), session_id);
+}
+
+TEST_F(StarboardDrmWrapperTest,
+       ReturnsWhetherServerCertIsUpdatableFromStarboard) {
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(Return(&fake_drm_system_));
+  EXPECT_CALL(starboard_, DrmIsServerCertificateUpdatable)
+      .WillOnce(Return(true))
+      .WillOnce(Return(false));
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  EXPECT_TRUE(
+      StarboardDrmWrapper::GetInstance().IsServerCertificateUpdatable());
+  EXPECT_FALSE(
+      StarboardDrmWrapper::GetInstance().IsServerCertificateUpdatable());
+}
+
+TEST_F(StarboardDrmWrapperTest, RespondsToCorrectClientByTicket) {
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string content_str_1 = "content_1";
+  base::span<const uint8_t> content_1 = base::as_byte_span(content_str_1);
+  const std::string content_str_2 = "content_2";
+  base::span<const uint8_t> content_2 = base::as_byte_span(content_str_2);
+  const std::string error_message = "";
+  const std::string session_id_1 = "session_id_1";
+  const std::string session_id_2 = "session_id_2";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusSuccess;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  // Clients may use the same ticket; test that this is supported.
+  const int ticket_1 = 7;
+  const int ticket_2 = 7;
+
+  MockStarboardDrmWrapperClient client_1;
+  MockStarboardDrmWrapperClient client_2;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_ticket_1 = StarboardDrmWrapper::kInvalidTicket;
+  int actual_wrapper_ticket_2 = StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_ticket_1))
+      .WillOnce(SaveArg<1>(&actual_wrapper_ticket_2));
+  EXPECT_CALL(client_1, OnSessionUpdateRequest(ticket_1, status, request_type,
+                                               error_message, session_id_1,
+                                               ElementsAreArray(content_1)))
+      .Times(1);
+  EXPECT_CALL(client_2, OnSessionUpdateRequest(ticket_2, status, request_type,
+                                               error_message, session_id_2,
+                                               ElementsAreArray(content_2)))
+      .Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_1, ticket_1, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_2, ticket_2, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+
+  // Simulate Starboard responding. To ensure that the logic in
+  // StarboardDrmWrapper is not dependent on ordering, we respond to the second
+  // session update request first.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  EXPECT_NE(actual_wrapper_ticket_1, StarboardDrmWrapper::kInvalidTicket);
+  EXPECT_NE(actual_wrapper_ticket_2, StarboardDrmWrapper::kInvalidTicket);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_ticket_2, status, request_type, error_message,
+      session_id_2, std::vector<uint8_t>(content_2.begin(), content_2.end()),
+      url);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_ticket_1, status, request_type, error_message,
+      session_id_1, std::vector<uint8_t>(content_1.begin(), content_1.end()),
+      url);
+}
+
+TEST_F(StarboardDrmWrapperTest, RespondsToCorrectClientBySessionId) {
+  // For this test we simulate the provisoining flow. Starboard will send an
+  // individualization request with an invalid ticket. StarboardDrmWrapper needs
+  // to find the correct client by looking at the session ID.
+  const std::string payload_type = "cenc";
+  const std::string init_data_str = "init_data";
+  base::span<const uint8_t> init_data = base::as_byte_span(init_data_str);
+  const std::string content_str_1 = "content_1";
+  base::span<const uint8_t> content_1 = base::as_byte_span(content_str_1);
+  const std::string content_str_2 = "content_2";
+  base::span<const uint8_t> content_2 = base::as_byte_span(content_str_2);
+  const std::string provisioning_data_str = "provisioning_data";
+  base::span<const uint8_t> provisioning_data =
+      base::as_byte_span(provisioning_data_str);
+  const std::string error_message = "";
+  const std::string session_id_1 = "session_id_1";
+  const std::string session_id_2 = "session_id_2";
+  const std::string url = "";
+  const StarboardDrmStatus status =
+      StarboardDrmStatus::kStarboardDrmStatusSuccess;
+  const StarboardDrmSessionRequestType request_type =
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeLicenseRequest;
+  // Clients may use the same ticket; test that this is supported.
+  const int ticket_1 = 7;
+  const int ticket_2 = 7;
+
+  MockStarboardDrmWrapperClient client_1;
+  MockStarboardDrmWrapperClient client_2;
+
+  // This will get populated by StarboardDrmWrapper.
+  const StarboardDrmSystemCallbackHandler* decryptor_provided_callbacks =
+      nullptr;
+  EXPECT_CALL(starboard_, CreateDrmSystem("com.widevine.alpha", _))
+      .WillOnce(DoAll(SaveArg<1>(&decryptor_provided_callbacks),
+                      Return(&fake_drm_system_)));
+  int actual_wrapper_ticket_1 = StarboardDrmWrapper::kInvalidTicket;
+  int actual_wrapper_ticket_2 = StarboardDrmWrapper::kInvalidTicket;
+  EXPECT_CALL(starboard_,
+              DrmGenerateSessionUpdateRequest(
+                  &fake_drm_system_, _, StrEq(payload_type),
+                  StrEqWhenCast(init_data_str), init_data_str.size()))
+      .WillOnce(SaveArg<1>(&actual_wrapper_ticket_1))
+      .WillOnce(SaveArg<1>(&actual_wrapper_ticket_2));
+  EXPECT_CALL(client_1, OnSessionUpdateRequest(ticket_1, status, request_type,
+                                               error_message, session_id_1,
+                                               ElementsAreArray(content_1)))
+      .Times(1);
+  EXPECT_CALL(
+      client_1,
+      OnSessionUpdateRequest(
+          StarboardDrmWrapper::kInvalidTicket, status,
+          StarboardDrmSessionRequestType::
+              kStarboardDrmSessionRequestTypeIndividualizationRequest,
+          error_message, session_id_1, ElementsAreArray(provisioning_data)));
+  EXPECT_CALL(client_2, OnSessionUpdateRequest(ticket_2, status, request_type,
+                                               error_message, session_id_2,
+                                               ElementsAreArray(content_2)))
+      .Times(1);
+
+  StarboardDrmWrapper::SetSingletonForTesting(&starboard_);
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_1, ticket_1, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+  StarboardDrmWrapper::GetInstance().GenerateSessionUpdateRequest(
+      &client_2, ticket_2, payload_type,
+      std::vector<uint8_t>(init_data.begin(), init_data.end()));
+
+  // Simulate Starboard responding.
+  ASSERT_THAT(decryptor_provided_callbacks, NotNull());
+  ASSERT_THAT(decryptor_provided_callbacks->update_request_fn, NotNull());
+  EXPECT_NE(actual_wrapper_ticket_1, StarboardDrmWrapper::kInvalidTicket);
+  EXPECT_NE(actual_wrapper_ticket_2, StarboardDrmWrapper::kInvalidTicket);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_ticket_1, status, request_type, error_message,
+      session_id_1, std::vector<uint8_t>(content_1.begin(), content_1.end()),
+      url);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      actual_wrapper_ticket_2, status, request_type, error_message,
+      session_id_2, std::vector<uint8_t>(content_2.begin(), content_2.end()),
+      url);
+  decryptor_provided_callbacks->update_request_fn(
+      &fake_drm_system_, &StarboardDrmWrapper::GetInstance(),
+      StarboardDrmWrapper::kInvalidTicket, status,
+      StarboardDrmSessionRequestType::
+          kStarboardDrmSessionRequestTypeIndividualizationRequest,
+      error_message, session_id_1,
+      std::vector<uint8_t>(provisioning_data.begin(), provisioning_data.end()),
+      url);
+}
+
+}  // namespace
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/media/BUILD.gn b/chromecast/starboard/media/media/BUILD.gn
index 8d56bd4..3e3eee9 100644
--- a/chromecast/starboard/media/media/BUILD.gn
+++ b/chromecast/starboard/media/media/BUILD.gn
@@ -40,6 +40,7 @@
     "//chromecast/starboard/chromecast/starboard_adapter",
     "//chromecast/starboard/chromecast/starboard_cast_api:cast_starboard_api_types",
     "//chromecast/starboard/media/cdm:starboard_drm_key_tracker",
+    "//chromecast/starboard/media/cdm:starboard_drm_wrapper",
     "//ui/display",
     "//ui/gfx/geometry",
   ]
diff --git a/chromecast/starboard/media/media/drm_util.cc b/chromecast/starboard/media/media/drm_util.cc
index b95bc26..532b435 100644
--- a/chromecast/starboard/media/media/drm_util.cc
+++ b/chromecast/starboard/media/media/drm_util.cc
@@ -72,7 +72,8 @@
   // Populate drm_info->initialization_vector.
   base::span<uint8_t>(drm_info->initialization_vector)
       .first(iv_size)
-      .copy_from(base::as_byte_span(decrypt_config->iv()).first(iv_size));
+      .copy_from_nonoverlapping(
+          base::as_byte_span(decrypt_config->iv()).first(iv_size));
   drm_info->initialization_vector_size = iv_size;
 
   size_t id_size = decrypt_config->key_id().size();
@@ -86,7 +87,8 @@
   // Populate drm_info->identifier.
   base::span<uint8_t>(drm_info->identifier)
       .first(id_size)
-      .copy_from(base::as_byte_span(decrypt_config->key_id()).first(id_size));
+      .copy_from_nonoverlapping(
+          base::as_byte_span(decrypt_config->key_id()).first(id_size));
   drm_info->identifier_size = id_size;
 
   // Populate subsample_mappings.
diff --git a/chromecast/starboard/media/media/media_pipeline_backend_starboard.cc b/chromecast/starboard/media/media/media_pipeline_backend_starboard.cc
index a08e3581..5bfee13 100644
--- a/chromecast/starboard/media/media/media_pipeline_backend_starboard.cc
+++ b/chromecast/starboard/media/media/media_pipeline_backend_starboard.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/task/bind_post_task.h"
 #include "chromecast/public/graphics_types.h"
+#include "chromecast/starboard/media/cdm/starboard_drm_wrapper.h"
 #include "chromecast/starboard/media/media/starboard_api_wrapper.h"
 
 namespace chromecast {
@@ -220,12 +221,20 @@
 void MediaPipelineBackendStarboard::CreatePlayer() {
   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
 
+  bool has_drm = false;
   StarboardPlayerCreationParam params = {};
   if (audio_decoder_) {
     const std::optional<StarboardAudioSampleInfo>& audio_info =
         audio_decoder_->GetAudioSampleInfo();
     CHECK(audio_info);
     params.audio_sample_info = *audio_info;
+
+    std::optional<EncryptionScheme> encryption_scheme =
+        audio_decoder_->GetEncryptionScheme();
+    if (encryption_scheme.has_value() &&
+        *encryption_scheme != EncryptionScheme::kUnencrypted) {
+      has_drm = true;
+    }
   }
   if (video_decoder_) {
     const std::optional<StarboardVideoSampleInfo>& video_info =
@@ -238,7 +247,21 @@
       // prioritize minimizing latency (render the frames as soon as possible).
       params.video_sample_info.max_video_capabilities = "streaming=1";
     }
+
+    std::optional<EncryptionScheme> encryption_scheme =
+        video_decoder_->GetEncryptionScheme();
+    if (encryption_scheme.has_value() &&
+        *encryption_scheme != EncryptionScheme::kUnencrypted) {
+      has_drm = true;
+    }
   }
+
+  if (has_drm) {
+    params.drm_system = StarboardDrmWrapper::GetInstance().GetDrmSystem();
+  } else {
+    params.drm_system = nullptr;
+  }
+
   params.output_mode = kStarboardPlayerOutputModePunchOut;
   player_ =
       starboard_->CreatePlayer(&params,
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper.h b/chromecast/starboard/media/media/starboard_api_wrapper.h
index 77c365b1..a69c3ade 100644
--- a/chromecast/starboard/media/media/starboard_api_wrapper.h
+++ b/chromecast/starboard/media/media/starboard_api_wrapper.h
@@ -264,9 +264,11 @@
 
 // Copy of SbPlayerCreationParam from starboard.
 struct StarboardPlayerCreationParam {
-  // Note: a DRM system is not included in this struct. Due to the architecture
-  // of cast, the MediaPipelineBackend does not have direct access to the CDM.
-  // So instead we pass a global to Starboard (in starboard_media_api.cc).
+  // Provides an appropriate DRM system if the media stream has encrypted
+  // portions. It will be null if the stream does not have encrypted portions.
+  //
+  // If not null, drm_system should point to an object of type SbDrmSystem.
+  void* drm_system;
 
   // Contains a populated SbMediaAudioSampleInfo if |audio_sample_info.codec|
   // isn't |kSbMediaAudioCodecNone|.  When |audio_sample_info.codec| is
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_14.cc b/chromecast/starboard/media/media/starboard_api_wrapper_14.cc
index 61dbc28..94802b0e 100644
--- a/chromecast/starboard/media/media/starboard_api_wrapper_14.cc
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_14.cc
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/check.h"
+#include "base/containers/span.h"
 #include "base/logging.h"
 #include "chromecast/starboard/media/media/starboard_api_wrapper_base.h"
 
@@ -20,6 +21,12 @@
 
 namespace {
 
+static_assert(sizeof(SbMediaColorMetadata::custom_primary_matrix) ==
+              sizeof(StarboardColorMetadata::custom_primary_matrix));
+
+constexpr size_t kCustomPrimaryMatrixSize =
+    std::size(StarboardColorMetadata{}.custom_primary_matrix);
+
 // A concrete implementation of StarboardApiWrapper for Starboard version 14.
 class StarboardApiWrapper14 : public StarboardApiWrapperBase {
  public:
@@ -57,8 +64,7 @@
  private:
   // StarboardApiWrapperBase impl:
   SbPlayerCreationParam ToSbPlayerCreationParam(
-      const StarboardPlayerCreationParam& in_param,
-      void* drm_system) override {
+      const StarboardPlayerCreationParam& in_param) override {
     SbPlayerCreationParam out_param = {};
 
     out_param.audio_sample_info =
@@ -68,13 +74,12 @@
     out_param.output_mode =
         static_cast<SbPlayerOutputMode>(in_param.output_mode);
 
-    if (drm_system) {
+    if (in_param.drm_system) {
       LOG(INFO) << "Using an SbDrmSystem for decryption.";
-      out_param.drm_system = static_cast<SbDrmSystem>(drm_system);
+      out_param.drm_system = static_cast<SbDrmSystem>(in_param.drm_system);
     } else {
-      LOG(INFO)
-          << "No SbDrmSystem was created before SbPlayer; no decryption is "
-             "possible in starboard.";
+      LOG(INFO) << "No SbDrmSystem was specified; no decryption is possible in "
+                   "starboard.";
       out_param.drm_system = kSbDrmSystemInvalid;
     }
 
@@ -122,12 +127,9 @@
     out_color_metadata.range =
         static_cast<SbMediaRangeId>(in_color_metadata.range);
 
-    static_assert(sizeof(out_color_metadata.custom_primary_matrix) ==
-                      sizeof(in_color_metadata.custom_primary_matrix),
-                  "Struct field size mismatch (custom_primary_matrix)");
-    memcpy(out_color_metadata.custom_primary_matrix,
-           in_color_metadata.custom_primary_matrix,
-           sizeof(out_color_metadata.custom_primary_matrix));
+    base::span<float, kCustomPrimaryMatrixSize>(
+        out_color_metadata.custom_primary_matrix)
+        .copy_from_nonoverlapping(in_color_metadata.custom_primary_matrix);
 
     return out_video_info;
   }
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_15.cc b/chromecast/starboard/media/media/starboard_api_wrapper_15.cc
index 86766901..52c9c64 100644
--- a/chromecast/starboard/media/media/starboard_api_wrapper_15.cc
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_15.cc
@@ -9,6 +9,7 @@
 #include <starboard/player.h>
 
 #include "base/check.h"
+#include "base/containers/span.h"
 #include "base/logging.h"
 #include "chromecast/starboard/media/media/starboard_api_wrapper_base.h"
 
@@ -17,6 +18,12 @@
 
 namespace {
 
+static_assert(sizeof(SbMediaColorMetadata::custom_primary_matrix) ==
+              sizeof(StarboardColorMetadata::custom_primary_matrix));
+
+constexpr size_t kCustomPrimaryMatrixSize =
+    std::size(StarboardColorMetadata{}.custom_primary_matrix);
+
 // Populates a VideoStreamInfo struct from a StarboardVideoSampleInfo.
 SbMediaVideoStreamInfo ToSbMediaVideoStreamInfo(
     const StarboardVideoSampleInfo& in_video_info) {
@@ -57,12 +64,9 @@
   out_color_metadata.range =
       static_cast<SbMediaRangeId>(in_color_metadata.range);
 
-  static_assert(sizeof(out_color_metadata.custom_primary_matrix) ==
-                    sizeof(in_color_metadata.custom_primary_matrix),
-                "Struct field size mismatch (custom_primary_matrix)");
-  memcpy(out_color_metadata.custom_primary_matrix,
-         in_color_metadata.custom_primary_matrix,
-         sizeof(out_color_metadata.custom_primary_matrix));
+  base::span<float, kCustomPrimaryMatrixSize>(
+      out_color_metadata.custom_primary_matrix)
+      .copy_from_nonoverlapping(in_color_metadata.custom_primary_matrix);
 
   return out_video_info;
 }
@@ -121,8 +125,7 @@
  private:
   // StarboardApiWrapperBase impl:
   SbPlayerCreationParam ToSbPlayerCreationParam(
-      const StarboardPlayerCreationParam& in_param,
-      void* drm_system) override {
+      const StarboardPlayerCreationParam& in_param) override {
     SbPlayerCreationParam out_param = {};
 
     out_param.audio_stream_info =
@@ -132,13 +135,12 @@
     out_param.output_mode =
         static_cast<SbPlayerOutputMode>(in_param.output_mode);
 
-    if (drm_system) {
+    if (in_param.drm_system) {
       LOG(INFO) << "Using an SbDrmSystem for decryption.";
-      out_param.drm_system = static_cast<SbDrmSystem>(drm_system);
+      out_param.drm_system = static_cast<SbDrmSystem>(in_param.drm_system);
     } else {
-      LOG(INFO)
-          << "No SbDrmSystem was created before SbPlayer; no decryption is "
-             "possible in starboard.";
+      LOG(INFO) << "No SbDrmSystem was specified; no decryption is possible in "
+                   "starboard.";
       out_param.drm_system = kSbDrmSystemInvalid;
     }
 
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_base.cc b/chromecast/starboard/media/media/starboard_api_wrapper_base.cc
index fe8c79b..b80d146 100644
--- a/chromecast/starboard/media/media/starboard_api_wrapper_base.cc
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_base.cc
@@ -24,9 +24,21 @@
 
 namespace {
 
-// Set via StarboardCreateDrmSystem, and passed to the SbPlayer when the player
-// is created.
-SbDrmSystem g_drm_system = nullptr;
+// Ensure that our internal starboard structs use arrays of the same size as the
+// real starboard structs. Later in this code we'll just copy the entire array
+// over (via span's copy_from_nonoverlapping()).
+static_assert(sizeof(SbDrmKeyId::identifier) ==
+              sizeof(StarboardDrmKeyId::identifier));
+static_assert(sizeof(SbDrmSampleInfo::initialization_vector) ==
+              sizeof(StarboardDrmSampleInfo::initialization_vector));
+static_assert(sizeof(SbDrmSampleInfo::identifier) ==
+              sizeof(StarboardDrmSampleInfo::identifier));
+
+constexpr size_t kDrmKeyIdentifierSize = std::size(SbDrmKeyId{}.identifier);
+constexpr size_t kDrmSampleInfoIvSize =
+    std::size(SbDrmSampleInfo{}.initialization_vector);
+constexpr size_t kDrmSampleInfoIdentifierSize =
+    std::size(SbDrmSampleInfo{}.identifier);
 
 // Helper function to convert a session ID to a string. Returns an empty string
 // if session_id is null or the size is invalid (<=0).
@@ -92,8 +104,8 @@
                 "StarboardDrmKeyId.identifier and SbDrmKeyId.identifier must "
                 "be arrays of the same size");
 
-  memcpy(out_key_id.identifier, in_key_id.identifier,
-         sizeof(out_key_id.identifier));
+  base::span<uint8_t, kDrmKeyIdentifierSize>(out_key_id.identifier)
+      .copy_from_nonoverlapping(in_key_id.identifier);
   out_key_id.identifier_size = in_key_id.identifier_size;
 
   return out_key_id;
@@ -244,7 +256,7 @@
       chromecast::CastStarboardApiAdapter::GetInstance()->GetWindow(nullptr);
 
   SbPlayerCreationParam sb_creation_param =
-      ToSbPlayerCreationParam(*creation_param, g_drm_system);
+      ToSbPlayerCreationParam(*creation_param);
 
   return SbPlayerCreate(
       window, &sb_creation_param, &DeallocateSample, &OnDecoderStatus,
@@ -287,19 +299,14 @@
 void* StarboardApiWrapperBase::CreateDrmSystem(
     const char* key_system,
     const StarboardDrmSystemCallbackHandler* callback_handler) {
-  if (g_drm_system) {
-    LOG(INFO) << "An SbDrmSystem already exists; creating a new one.";
-  }
-
   LOG(INFO) << "Creating SbDrmSystem";
-  g_drm_system = SbDrmCreateSystem(
+  return SbDrmCreateSystem(
       key_system,
       /*context=*/
       static_cast<void*>(
           const_cast<StarboardDrmSystemCallbackHandler*>(callback_handler)),
       &OnUpdateRequest, &OnSessionUpdated, &OnKeyStatusesChanged,
       &OnServerCertificateUpdated, &OnSessionClosed);
-  return g_drm_system;
 }
 
 void StarboardApiWrapperBase::DrmGenerateSessionUpdateRequest(
@@ -347,9 +354,6 @@
 
 void StarboardApiWrapperBase::DrmDestroySystem(void* drm_system) {
   LOG(INFO) << "Destroying SbDrmSystem";
-  if (reinterpret_cast<void*>(g_drm_system) == drm_system) {
-    g_drm_system = nullptr;
-  }
   SbDrmDestroySystem(static_cast<SbDrmSystem>(drm_system));
 }
 
@@ -400,13 +404,13 @@
     drm_info.encryption_pattern.skip_byte_block =
         in_drm_info.encryption_pattern.skip_byte_block;
 
-    memcpy(drm_info.initialization_vector, in_drm_info.initialization_vector,
-           in_drm_info.initialization_vector_size);
+    base::span<uint8_t, kDrmSampleInfoIvSize>(drm_info.initialization_vector)
+        .copy_from_nonoverlapping(in_drm_info.initialization_vector);
     drm_info.initialization_vector_size =
         in_drm_info.initialization_vector_size;
 
-    memcpy(drm_info.identifier, in_drm_info.identifier,
-           in_drm_info.identifier_size);
+    base::span<uint8_t, kDrmSampleInfoIdentifierSize>(drm_info.identifier)
+        .copy_from_nonoverlapping(in_drm_info.identifier);
     drm_info.identifier_size = in_drm_info.identifier_size;
 
     subsample_mappings.reserve(in_drm_info.subsample_mapping.size());
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_base.h b/chromecast/starboard/media/media/starboard_api_wrapper_base.h
index 6cf8556..2a7404d65 100644
--- a/chromecast/starboard/media/media/starboard_api_wrapper_base.h
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_base.h
@@ -87,8 +87,7 @@
   // Converts the version-agnostic StarboardPlayerCreationParam to starboard's
   // SbPlayerCreationParam.
   virtual SbPlayerCreationParam ToSbPlayerCreationParam(
-      const StarboardPlayerCreationParam& in_param,
-      void* drm_system) = 0;
+      const StarboardPlayerCreationParam& in_param) = 0;
 
   // Converts from cast's version-agnostic struct to starboard's version.
   virtual SbMediaVideoSampleInfo ToSbMediaVideoSampleInfo(
diff --git a/chromecast/starboard/media/media/starboard_audio_decoder.cc b/chromecast/starboard/media/media/starboard_audio_decoder.cc
index 92a8109..6f6a7539 100644
--- a/chromecast/starboard/media/media/starboard_audio_decoder.cc
+++ b/chromecast/starboard/media/media/starboard_audio_decoder.cc
@@ -112,6 +112,14 @@
   return audio_sample_info_;
 }
 
+std::optional<EncryptionScheme> StarboardAudioDecoder::GetEncryptionScheme() {
+  if (audio_sample_info_.has_value()) {
+    // The config is populated when audio_sample_info_ is populated.
+    return config_.encryption_scheme;
+  }
+  return std::nullopt;
+}
+
 bool StarboardAudioDecoder::SetConfig(const AudioConfig& config) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/chromecast/starboard/media/media/starboard_audio_decoder.h b/chromecast/starboard/media/media/starboard_audio_decoder.h
index fe90ead..75ec455 100644
--- a/chromecast/starboard/media/media/starboard_audio_decoder.h
+++ b/chromecast/starboard/media/media/starboard_audio_decoder.h
@@ -40,8 +40,11 @@
   AudioTrackTimestamp GetAudioTrackTimestamp() override;
   int GetStartThresholdInFrames() override;
 
+  // StarboardDecoder implementation:
+  std::optional<EncryptionScheme> GetEncryptionScheme() override;
+
  private:
-  // StarboardDecoder impl:
+  // StarboardDecoder implementation:
   void InitializeInternal() override;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromecast/starboard/media/media/starboard_decoder.h b/chromecast/starboard/media/media/starboard_decoder.h
index 3b84123..cae4216 100644
--- a/chromecast/starboard/media/media/starboard_decoder.h
+++ b/chromecast/starboard/media/media/starboard_decoder.h
@@ -24,8 +24,8 @@
 // logic common to all decoders. It manages interactions with Starboard and the
 // lifetime of buffers.
 //
-// This is an abstract class; child classes can implement InitializeInternal to
-// perform any necessary initialization logic.
+// This is an abstract class; child classes must implement InitializeInternal
+// and GetEncryptionScheme (see the function declarations for more information).
 //
 // All functions, including the constructor and destructor, must be called on
 // the same sequence (the media thread).
@@ -52,6 +52,12 @@
   // the decoder is no longer initialized.
   bool IsInitialized();
 
+  // Returns the encryption scheme for this decoder, or nullopt if the
+  // encryption scheme is not yet known.
+  //
+  // kUnencrypted will be returned if the content is known to not be encrypted.
+  virtual std::optional<EncryptionScheme> GetEncryptionScheme() = 0;
+
   // Called when a buffer has been processed by Starboard.
   void OnBufferWritten();
 
diff --git a/chromecast/starboard/media/media/starboard_video_decoder.cc b/chromecast/starboard/media/media/starboard_video_decoder.cc
index 6d99df2..ba39800 100644
--- a/chromecast/starboard/media/media/starboard_video_decoder.cc
+++ b/chromecast/starboard/media/media/starboard_video_decoder.cc
@@ -147,6 +147,14 @@
   return video_sample_info_;
 }
 
+std::optional<EncryptionScheme> StarboardVideoDecoder::GetEncryptionScheme() {
+  if (video_sample_info_.has_value()) {
+    // The config is populated when video_sample_info_ is populated.
+    return config_.encryption_scheme;
+  }
+  return std::nullopt;
+}
+
 bool StarboardVideoDecoder::SetConfig(const VideoConfig& config) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/chromecast/starboard/media/media/starboard_video_decoder.h b/chromecast/starboard/media/media/starboard_video_decoder.h
index 5423048..a21e7ef 100644
--- a/chromecast/starboard/media/media/starboard_video_decoder.h
+++ b/chromecast/starboard/media/media/starboard_video_decoder.h
@@ -37,6 +37,9 @@
       CastDecoderBuffer* buffer) override;
   void SetDelegate(Delegate* delegate) override;
 
+  // StarboardDecoder implementation:
+  std::optional<EncryptionScheme> GetEncryptionScheme() override;
+
  private:
   // StarboardDecoder implementation:
   void InitializeInternal() override;
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 2a05851..9b100b3 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16272.0.0-1068599
\ No newline at end of file
+16275.0.0-1068679
\ No newline at end of file
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_streaming_client.cc b/chromeos/ash/components/boca/babelorca/tachyon_streaming_client.cc
index aa65e582..684137e 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_streaming_client.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_streaming_client.cc
@@ -111,6 +111,7 @@
   if (success) {
     base::UmaHistogramEnumeration(kStreamEndReasonUma,
                                   StreamEndReason::kConnectionClosedSuccess);
+    url_loader_.reset();
     std::move(request_data_->response_cb)
         .Run(TachyonResponse(TachyonResponse::Status::kOk));
     return;
diff --git a/chromeos/ash/components/boca/babelorca/tachyon_streaming_client_unittest.cc b/chromeos/ash/components/boca/babelorca/tachyon_streaming_client_unittest.cc
index 398fffca..5a0f3f21 100644
--- a/chromeos/ash/components/boca/babelorca/tachyon_streaming_client_unittest.cc
+++ b/chromeos/ash/components/boca/babelorca/tachyon_streaming_client_unittest.cc
@@ -8,6 +8,8 @@
 #include <string>
 #include <utility>
 
+#include "base/functional/bind.h"
+#include "base/functional/callback_forward.h"
 #include "base/functional/callback_helpers.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
@@ -92,12 +94,18 @@
   int parse_calls_ = 0;
 };
 
-class TachyonStreamingClientTest : public testing::Test {
+class TachyonStreamingClientTest : public testing::TestWithParam<bool> {
  protected:
-  RequestDataPtr request_data() {
+  RequestDataPtr request_data(bool destroy_client_on_repsonse = false) {
     auto request_data = std::make_unique<RequestDataWrapper>(
         TRAFFIC_ANNOTATION_FOR_TESTS, kUrl, /*max_retries_param=*/1,
-        result_future_.GetCallback());
+        base::BindLambdaForTesting(
+            [this, destroy_client_on_repsonse](TachyonResponse response) {
+              if (destroy_client_on_repsonse) {
+                client_.reset();
+              }
+              std::move(result_future_.GetCallback()).Run(std::move(response));
+            }));
     request_data->content_data = "request-body";
     request_data->uma_name = kUmaName;
     return request_data;
@@ -142,12 +150,12 @@
   base::HistogramTester uma_recorder_;
 };
 
-TEST_F(TachyonStreamingClientTest, SuccessfulRequestNoDataStreamed) {
+TEST_P(TachyonStreamingClientTest, SuccessfulRequestNoDataStreamed) {
   url_loader_factory_.AddResponse(kUrl, "");
 
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(/*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   TachyonResponse result = result_future_.Take();
   // Advance time to verify timeout reset.
   task_environment_.FastForwardBy(base::Minutes(1));
@@ -165,13 +173,14 @@
       1);
 }
 
-TEST_F(TachyonStreamingClientTest, HttpErrorNoDataStreamed) {
+TEST_P(TachyonStreamingClientTest, HttpErrorNoDataStreamed) {
   url_loader_factory_.AddResponse(
       kUrl, "error", net::HttpStatusCode::HTTP_PRECONDITION_FAILED);
 
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(
+                            /*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   TachyonResponse result = result_future_.Take();
   // Advance time to verify timeout reset.
   task_environment_.FastForwardBy(base::Minutes(1));
@@ -189,13 +198,13 @@
       1);
 }
 
-TEST_F(TachyonStreamingClientTest, AuthErrorNoDataStreamed) {
+TEST_P(TachyonStreamingClientTest, AuthErrorNoDataStreamed) {
   url_loader_factory_.AddResponse(kUrl, "error",
                                   net::HttpStatusCode::HTTP_UNAUTHORIZED);
 
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(/*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   RequestDataPtr auth_request_data = auth_failure_future_.Take();
   // Advance time to verify timeout reset.
   task_environment_.FastForwardBy(base::Minutes(1));
@@ -212,10 +221,10 @@
       1);
 }
 
-TEST_F(TachyonStreamingClientTest, TimeoutAfterStartRequest) {
+TEST_P(TachyonStreamingClientTest, TimeoutAfterStartRequest) {
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(/*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   task_environment_.FastForwardBy(base::Minutes(1));
 
   TachyonResponse result = result_future_.Take();
@@ -303,10 +312,10 @@
   EXPECT_FALSE(auth_failure_future_.IsReady());
 }
 
-TEST_F(TachyonStreamingClientTest, DataStreamedSuccessClosed) {
+TEST_P(TachyonStreamingClientTest, DataStreamedSuccessClosed) {
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(/*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   client_->OnDataReceived("123", resume_future_.GetCallback());
   std::vector<mojom::BabelOrcaMessagePtr> messages;
   messages.emplace_back(babel_orca_message_mojom());
@@ -332,10 +341,10 @@
       1);
 }
 
-TEST_F(TachyonStreamingClientTest, DataStreamedParsingError) {
+TEST_P(TachyonStreamingClientTest, DataStreamedParsingError) {
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(/*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   client_->OnDataReceived("123", resume_future_.GetCallback());
   std::vector<mojom::BabelOrcaMessagePtr> messages;
   messages.emplace_back(babel_orca_message_mojom());
@@ -361,10 +370,10 @@
             1);
 }
 
-TEST_F(TachyonStreamingClientTest, DataStreamedAuthErrorClosed) {
+TEST_P(TachyonStreamingClientTest, DataStreamedAuthErrorClosed) {
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(/*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   client_->OnDataReceived("123", resume_future_.GetCallback());
   mojom::StreamStatusPtr stream_status =
       mojom::StreamStatus::New(/*code=*/16, /*message=*/"auth error");
@@ -382,10 +391,10 @@
       1);
 }
 
-TEST_F(TachyonStreamingClientTest, ParsingServiceDisconnected) {
+TEST_P(TachyonStreamingClientTest, ParsingServiceDisconnected) {
   CreateStreamingClient();
-  client_->StartRequest(request_data(), kOAuthToken,
-                        auth_failure_future_.GetCallback());
+  client_->StartRequest(request_data(/*destroy_client_on_repsonse=*/GetParam()),
+                        kOAuthToken, auth_failure_future_.GetCallback());
   client_->OnDataReceived("123", resume_future_.GetCallback());
   parsing_service_->RunParseCallback(mojom::ParsingState::kOk, {}, nullptr);
   EXPECT_TRUE(resume_future_.Wait());
@@ -441,5 +450,9 @@
   EXPECT_EQ(parsing_service_->parse_calls(), 1);
 }
 
+INSTANTIATE_TEST_SUITE_P(TachyonStreamingClientTestSuite,
+                         TachyonStreamingClientTest,
+                         testing::Bool());
+
 }  // namespace
 }  // namespace ash::babelorca
diff --git a/chromeos/ash/components/dbus/fwupd/fwupd_client.cc b/chromeos/ash/components/dbus/fwupd/fwupd_client.cc
index 93423af2..863aa040 100644
--- a/chromeos/ash/components/dbus/fwupd/fwupd_client.cc
+++ b/chromeos/ash/components/dbus/fwupd/fwupd_client.cc
@@ -386,8 +386,9 @@
       can_parse = false;
     }
 
-    const bool needs_trusted_report = !features::IsFlexFirmwareUpdateEnabled();
-    FIRMWARE_LOG(DEBUG) << "Trusted reports required: " << needs_trusted_report;
+    const bool needs_trusted_report =
+        !features::IsFlexFirmwareUpdateEnabled() &&
+        !features::IsFwupdDeveloperModeEnabled();
 
     FwupdUpdateList updates;
     while (can_parse && array_reader.HasMoreData()) {
@@ -407,7 +408,9 @@
       std::optional<bool> trusted_report = dict.FindBool(kHasTrustedReportKey);
       const bool has_trusted_report =
           trusted_report.has_value() && trusted_report.value();
-      FIRMWARE_LOG(DEBUG) << "Trusted Reports: " << has_trusted_report;
+      FIRMWARE_LOG(DEBUG) << "Trusted Reports required: "
+                          << needs_trusted_report
+                          << "; Trusted Reports found: " << has_trusted_report;
       const bool missing_trusted_report =
           needs_trusted_report && !has_trusted_report;
 
@@ -679,8 +682,17 @@
     return base::FilePath();
   }
 
-  // Convert to a FilePath and verify the extension.
+  // Convert to a FilePath
   base::FilePath path(url.spec());
+
+  // Force return; don't authenticate URL further.
+  if (features::IsFwupdDeveloperModeEnabled()) {
+    FIRMWARE_LOG(DEBUG)
+        << "Developer mode detected; URI authentication skipped";
+    return path;
+  }
+
+  // Verify the extension.
   if (path.Extension() != kCabFileExtension) {
     FIRMWARE_LOG(ERROR) << "Invalid location extension: " << path;
     return base::FilePath();
diff --git a/chromeos/ash/components/dbus/fwupd/fwupd_client_unittest.cc b/chromeos/ash/components/dbus/fwupd/fwupd_client_unittest.cc
index 08e9ce9..1725f72 100644
--- a/chromeos/ash/components/dbus/fwupd/fwupd_client_unittest.cc
+++ b/chromeos/ash/components/dbus/fwupd/fwupd_client_unittest.cc
@@ -307,7 +307,7 @@
     // This value is returned by DBus as a uint32_t and is added to a dictionary
     // that doesn't support unsigned numbers. So it needs to be casted to int.
     EXPECT_EQ(expected_priority_, (*updates)[0].priority);
-    EXPECT_EQ(kFakeUpdateUriForTesting, (*updates)[0].filepath.value());
+    EXPECT_EQ(expected_location_, (*updates)[0].filepath.value());
     EXPECT_EQ(expected_checksum_, (*updates)[0].checksum);
   }
 
@@ -329,6 +329,10 @@
 
   void SetExpectNoUpdates(bool no_updates) { expect_no_updates_ = no_updates; }
 
+  void SetExpectedLocation(const std::string& location) {
+    expected_location_ = location;
+  }
+
   void CheckPropertyChanged(FwupdProperties* properties) {
     if (properties->IsPercentageValid()) {
       EXPECT_EQ(expected_properties_->GetPercentage(),
@@ -406,6 +410,7 @@
   std::string expected_checksum_;
   std::string expected_description_;
   int expected_priority_ = kFakeUpdatePriorityForTesting;
+  std::string expected_location_ = kFakeUpdateUriForTesting;
 
   base::test::ScopedFeatureList scoped_feature_list_;
 
@@ -723,6 +728,63 @@
   run_loop_.Run();
 }
 
+// Test that accepts firmware with invalid URI when fwupd dev mode is enabled.
+TEST_F(FwupdClientTest, AcceptAnyUriInDevMode) {
+  // The observer will check that the update description is parsed and passed
+  // correctly.
+  MockObserver observer;
+  EXPECT_CALL(observer, OnUpdateListResponse(_, _))
+      .Times(1)
+      .WillRepeatedly(Invoke(this, &FwupdClientTest::CheckUpdates));
+  fwupd_client_->AddObserver(&observer);
+
+  EXPECT_CALL(*proxy_, DoCallMethodWithErrorResponse(_, _, _))
+      .WillRepeatedly(Invoke(this, &FwupdClientTest::OnMethodCalled));
+
+  std::string fake_location = "http://fakelocation.com/firmware.cab/auth";
+  RequestUpdatesResponse response;
+  response.locations = {fake_location};
+
+  AddDbusMethodCallResultSimulation(response.Create(), nullptr);
+  EnableFeatureFlag(features::kFwupdDeveloperMode);
+
+  SetExpectedLocation(fake_location);
+  SetExpectedDescription(kFakeUpdateDescriptionForTesting);
+  SetExpectedChecksum(kFakeSha256ForTesting);
+
+  fwupd_client_->RequestUpdates(kFakeDeviceIdForTesting);
+
+  run_loop_.Run();
+}
+
+// Test that accepts firmware with no trusted reports when fwupd dev mode is
+// enabled.
+TEST_F(FwupdClientTest, AcceptNoTrustedReportsInDevMode) {
+  // The observer will check that the update description is parsed and passed
+  // correctly.
+  MockObserver observer;
+  EXPECT_CALL(observer, OnUpdateListResponse(_, _))
+      .Times(1)
+      .WillRepeatedly(Invoke(this, &FwupdClientTest::CheckUpdates));
+  fwupd_client_->AddObserver(&observer);
+
+  EXPECT_CALL(*proxy_, DoCallMethodWithErrorResponse(_, _, _))
+      .WillRepeatedly(Invoke(this, &FwupdClientTest::OnMethodCalled));
+
+  RequestUpdatesResponse response;
+  response.trusted = false;
+
+  AddDbusMethodCallResultSimulation(response.Create(), nullptr);
+  EnableFeatureFlag(features::kFwupdDeveloperMode);
+
+  SetExpectedDescription(kFakeUpdateDescriptionForTesting);
+  SetExpectedChecksum(kFakeSha256ForTesting);
+
+  fwupd_client_->RequestUpdates(kFakeDeviceIdForTesting);
+
+  run_loop_.Run();
+}
+
 TEST_F(FwupdClientTest, Install) {
   EXPECT_CALL(*proxy_, DoCallMethodWithErrorResponse(_, _, _))
       .WillRepeatedly(Invoke(this, &FwupdClientTest::OnMethodCalled));
diff --git a/clank b/clank
index 6115866..a85f502 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 611586675d71250b8b9ffca165e159f05acbb3d5
+Subproject commit a85f502de34463769977268999f0dbce0321efa6
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 0056926..596e9b07 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -577,6 +577,7 @@
       "//components/signin/public/identity_manager/objc:unit_tests",
       "//components/translate/ios/browser:unit_tests",
       "//components/ukm/ios:unit_tests",
+      "//components/webauthn/ios:js_tests",
     ]
     if (use_blink) {
       deps += [ ":components_tests_distiller_bundle_data" ]
diff --git a/components/account_id/account_id.cc b/components/account_id/account_id.cc
index 7463032..c55ff04 100644
--- a/components/account_id/account_id.cc
+++ b/components/account_id/account_id.cc
@@ -83,10 +83,6 @@
   }
 }
 
-bool AccountId::operator!=(const AccountId& other) const {
-  return !operator==(other);
-}
-
 bool AccountId::operator<(const AccountId& right) const {
   // TODO(alemate): update this once all AccountId members are filled.
   return user_email_ < right.user_email_;
diff --git a/components/account_id/account_id.h b/components/account_id/account_id.h
index f188ed3..b94d2fe 100644
--- a/components/account_id/account_id.h
+++ b/components/account_id/account_id.h
@@ -47,7 +47,6 @@
   // If both are not UNKNOWN and not equal then it returns false.
   // If AccountType == GOOGLE then it checks if either ids or emails are equal.
   bool operator==(const AccountId& other) const;
-  bool operator!=(const AccountId& other) const;
   bool operator<(const AccountId& right) const;
 
   bool empty() const;
diff --git a/components/account_manager_core/account.cc b/components/account_manager_core/account.cc
index dce0562..8cca02a 100644
--- a/components/account_manager_core/account.cc
+++ b/components/account_manager_core/account.cc
@@ -20,32 +20,6 @@
   DCHECK(!id_.empty());
 }
 
-bool AccountKey::operator<(const AccountKey& other) const {
-  return std::tie(id_, account_type_) <
-         std::tie(other.id_, other.account_type_);
-}
-
-bool AccountKey::operator==(const AccountKey& other) const {
-  return std::tie(id_, account_type_) ==
-         std::tie(other.id_, other.account_type_);
-}
-
-bool AccountKey::operator!=(const AccountKey& other) const {
-  return !(*this == other);
-}
-
-bool Account::operator<(const Account& other) const {
-  return std::tie(key, raw_email) < std::tie(other.key, other.raw_email);
-}
-
-bool Account::operator==(const Account& other) const {
-  return std::tie(key, raw_email) == std::tie(other.key, other.raw_email);
-}
-
-bool Account::operator!=(const Account& other) const {
-  return !(*this == other);
-}
-
 COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
 std::ostream& operator<<(std::ostream& os, const AccountType& account_type) {
   // Currently, we only support `kGaia` account type. Should a new type be added
diff --git a/components/account_manager_core/account.h b/components/account_manager_core/account.h
index 13fbe2b0..7640f4cf 100644
--- a/components/account_manager_core/account.h
+++ b/components/account_manager_core/account.h
@@ -37,9 +37,8 @@
   const std::string& id() const { return id_; }
   AccountType account_type() const { return account_type_; }
 
-  bool operator<(const AccountKey& other) const;
-  bool operator==(const AccountKey& other) const;
-  bool operator!=(const AccountKey& other) const;
+  friend bool operator==(const AccountKey&, const AccountKey&) = default;
+  friend auto operator<=>(const AccountKey&, const AccountKey&) = default;
 
  private:
   // Fields are not const to allow assignment operator.
@@ -55,9 +54,8 @@
   // The raw, un-canonicalized email id for this account.
   std::string raw_email;
 
-  bool operator<(const Account& other) const;
-  bool operator==(const Account& other) const;
-  bool operator!=(const Account& other) const;
+  friend bool operator==(const Account&, const Account&) = default;
+  friend auto operator<=>(const Account&, const Account&) = default;
 };
 
 // For logging.
diff --git a/components/autofill/content/browser/content_identity_credential_delegate_unittest.cc b/components/autofill/content/browser/content_identity_credential_delegate_unittest.cc
index d90c8c0..4f03864 100644
--- a/components/autofill/content/browser/content_identity_credential_delegate_unittest.cc
+++ b/components/autofill/content/browser/content_identity_credential_delegate_unittest.cc
@@ -258,6 +258,15 @@
   EXPECT_EQ(suggestion.main_text.value, u"john@email.com");
   EXPECT_EQ(suggestion.labels.size(), 1ul);
   EXPECT_EQ(suggestion.minor_texts.size(), 0ul);
+
+  // Expect the payload to be populated properly.
+  Suggestion::IdentityCredentialPayload payload =
+      suggestion.GetPayload<Suggestion::IdentityCredentialPayload>();
+  EXPECT_EQ(payload.account_id, "id");
+  EXPECT_EQ(payload.config_url, GURL("https://idp.example"));
+
+  // Expect no field to be available in the payload for PASSWORD.
+  EXPECT_TRUE(payload.fields.empty());
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/data_model/addresses/contact_info.h b/components/autofill/core/browser/data_model/addresses/contact_info.h
index 020ff909..9b131db 100644
--- a/components/autofill/core/browser/data_model/addresses/contact_info.h
+++ b/components/autofill/core/browser/data_model/addresses/contact_info.h
@@ -118,7 +118,6 @@
   ~EmailInfo() override;
 
   bool operator==(const EmailInfo& other) const;
-  bool operator!=(const EmailInfo& other) const { return !operator==(other); }
 
   // FormGroup:
   std::u16string GetInfo(const AutofillType& type,
@@ -150,7 +149,6 @@
   ~CompanyInfo() override;
 
   bool operator==(const CompanyInfo& other) const;
-  bool operator!=(const CompanyInfo& other) const { return !operator==(other); }
 
   // FormGroup:
   std::u16string GetInfo(const AutofillType& type,
diff --git a/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc b/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc
index 73f44d6e..bdb3b7c0 100644
--- a/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc
+++ b/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc
@@ -31,10 +31,6 @@
          test_api(a).index() == test_api(b).index();
 }
 
-bool operator!=(MatchPatternRef a, MatchPatternRef b) {
-  return !(a == b);
-}
-
 void PrintTo(MatchPatternRef p, std::ostream* os) {
   *os << "MatchPatternRef(" << test_api(p).is_supplementary() << ","
       << test_api(p).index() << ")";
diff --git a/components/autofill/core/common/dense_set.h b/components/autofill/core/common/dense_set.h
index e2bc201..1d7adb83 100644
--- a/components/autofill/core/common/dense_set.h
+++ b/components/autofill/core/common/dense_set.h
@@ -302,10 +302,6 @@
       return a.index_ == b.index_;
     }
 
-    friend constexpr bool operator!=(const Iterator& a, const Iterator& b) {
-      return !(a == b);
-    }
-
     constexpr T operator*() const {
       DCHECK(dereferenceable());
       return index_to_value(index_);
diff --git a/components/autofill/ios/browser/BUILD.gn b/components/autofill/ios/browser/BUILD.gn
index 15f1c7f..b768bb9c 100644
--- a/components/autofill/ios/browser/BUILD.gn
+++ b/components/autofill/ios/browser/BUILD.gn
@@ -102,7 +102,6 @@
   deps = [
     "//components/autofill/ios/form_util:fill_js_dependencies",
     "//components/autofill/ios/form_util:fill_js_namespace",
-    "//ios/web/public/js_messaging:frame_id",
     "//ios/web/public/js_messaging:gcrweb",
     "//ios/web/public/js_messaging:util_scripts",
   ]
diff --git a/components/autofill/ios/browser/autofill_across_iframes_unittest.mm b/components/autofill/ios/browser/autofill_across_iframes_unittest.mm
index a637339..994744f 100644
--- a/components/autofill/ios/browser/autofill_across_iframes_unittest.mm
+++ b/components/autofill/ios/browser/autofill_across_iframes_unittest.mm
@@ -1844,7 +1844,7 @@
 
     // Change the frame ID provided by getFrameId() to simulate a different
     // frame receiving the forms extraction request.
-    std::u16string script = u"__gCrWeb.message.getFrameId = () => "
+    std::u16string script = u"__gCrWeb.getFrameId = () => "
                             "'1effd8f52a067c8d3a01762d3c41dfd8'; true";
     ASSERT_TRUE(ExecuteJavaScriptInFrame(main_frame, script));
   }
diff --git a/components/autofill/ios/browser/resources/autofill_controller.js b/components/autofill/ios/browser/resources/autofill_controller.js
index 33d718cf..7e34798 100644
--- a/components/autofill/ios/browser/resources/autofill_controller.js
+++ b/components/autofill/ios/browser/resources/autofill_controller.js
@@ -4,8 +4,7 @@
 
 import * as fill_constants from '//components/autofill/ios/form_util/resources/fill_constants.js';
 import {isTextAreaElement} from '//components/autofill/ios/form_util/resources/fill_element_inference_util.js';
-import {getFrameId} from '//ios/web/public/js_messaging/resources/frame_id.js';
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {isTextField, sendWebKitMessage, trim} from '//ios/web/public/js_messaging/resources/utils.js';
 
 
@@ -325,7 +324,7 @@
         sendWebKitMessage(NATIVE_MESSAGE_HANDLER, {
           'command': FORM_FILLED_COMMAND,
           'form_data': formData,
-          'frame': getFrameId(),
+          'frame': gCrWeb.getFrameId(),
         });
       }
     }, _delay);
diff --git a/components/autofill/ios/common/features.mm b/components/autofill/ios/common/features.mm
index a07232d..7e582d0 100644
--- a/components/autofill/ios/common/features.mm
+++ b/components/autofill/ios/common/features.mm
@@ -36,7 +36,7 @@
 
 BASE_FEATURE(kAutofillDynamicallyLoadsFieldsForAddressInput,
              "AutofillDynamicallyLoadsFieldsForAddressInput",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // LINT.IfChange(autofill_fix_post_filling_payment_sheet)
 BASE_FEATURE(kAutofillFixPaymentSheetSpam,
diff --git a/components/autofill/ios/form_util/BUILD.gn b/components/autofill/ios/form_util/BUILD.gn
index e931130..5948976 100644
--- a/components/autofill/ios/form_util/BUILD.gn
+++ b/components/autofill/ios/form_util/BUILD.gn
@@ -110,7 +110,6 @@
   deps = [
     ":autofill_form_features_ts",
     ":fill_js_namespace",
-    "//ios/web/public/js_messaging:frame_id",
     "//ios/web/public/js_messaging:gcrweb",
     "//ios/web/public/js_messaging:util_scripts",
   ]
@@ -151,7 +150,6 @@
   deps = [
     ":fill_js_dependencies",
     ":fill_js_namespace",
-    "//ios/web/public/js_messaging:frame_id",
     "//ios/web/public/js_messaging:gcrweb",
   ]
 }
diff --git a/components/autofill/ios/form_util/form_activity_params.h b/components/autofill/ios/form_util/form_activity_params.h
index 66d998e..0d00a24 100644
--- a/components/autofill/ios/form_util/form_activity_params.h
+++ b/components/autofill/ios/form_util/form_activity_params.h
@@ -64,8 +64,6 @@
 // value: "LouisLane" (assuming that was the password typed)
 // has_user_gesture:  true
 // input_missing:  false
-// frame_id: will be the unique ID generated in for the frame containing the
-// form (see __gCrWeb.message.getFrameId for details).
 struct FormActivityParams : public BaseFormActivityParams {
   FormActivityParams();
   FormActivityParams(const FormActivityParams& other);
diff --git a/components/autofill/ios/form_util/resources/child_frame_registration_lib.ts b/components/autofill/ios/form_util/resources/child_frame_registration_lib.ts
index 3cbfe91..fc83856 100644
--- a/components/autofill/ios/form_util/resources/child_frame_registration_lib.ts
+++ b/components/autofill/ios/form_util/resources/child_frame_registration_lib.ts
@@ -8,8 +8,7 @@
  */
 
 import {CHILD_FRAME_REMOTE_TOKEN_ATTRIBUTE} from '//components/autofill/ios/form_util/resources/fill_constants.js';
-import {getFrameId} from '//ios/web/public/js_messaging/resources/frame_id.js';
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {generateRandomId, sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 /**
@@ -89,7 +88,7 @@
  */
 function registerSelfWithRemoteToken(remoteId: string): void {
   sendWebKitMessage(NATIVE_MESSAGE_HANDLER, {
-    'local_frame_id': getFrameId(),
+    'local_frame_id': gCrWeb.getFrameId(),
     'remote_frame_id': remoteId,
   });
 }
diff --git a/components/autofill/ios/form_util/resources/fill.ts b/components/autofill/ios/form_util/resources/fill.ts
index a69f586e..0614ef3 100644
--- a/components/autofill/ios/form_util/resources/fill.ts
+++ b/components/autofill/ios/form_util/resources/fill.ts
@@ -8,7 +8,7 @@
 import {inferLabelFromNext} from '//components/autofill/ios/form_util/resources/fill_element_inference.js';
 import * as inferenceUtil from '//components/autofill/ios/form_util/resources/fill_element_inference_util.js';
 import type * as fillUtil from '//components/autofill/ios/form_util/resources/fill_util.js';
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {isTextField, removeQueryAndReferenceFromURL} from '//ios/web/public/js_messaging/resources/utils.js';
 
 // This file provides methods used to fill forms in JavaScript.
@@ -353,7 +353,7 @@
   // Protect against custom implementation of Array.toJSON in host pages.
   (form.fields as any).toJSON = null;
 
-  form.host_frame = gCrWebLegacy.message.getFrameId();
+  form.host_frame = gCrWeb.getFrameId();
 
   if (childFrames.length > 0) {
     form.child_frames = childFrames;
@@ -427,7 +427,7 @@
 
   form.renderer_id = gCrWebLegacy.fill.getUniqueID(formElement);
 
-  form.host_frame = frame.__gCrWeb.message.getFrameId();
+  form.host_frame = frame.__gCrWeb.getFrameId();
 
   // Note different from form_autofill_util.cc version of this method, which
   // computes |form.action| using document.completeURL(form_element.action())
diff --git a/components/autofill/ios/form_util/resources/form.ts b/components/autofill/ios/form_util/resources/form.ts
index 27f54ef..a678639 100644
--- a/components/autofill/ios/form_util/resources/form.ts
+++ b/components/autofill/ios/form_util/resources/form.ts
@@ -8,7 +8,7 @@
 
 import {RENDERER_ID_NOT_SET} from '//components/autofill/ios/form_util/resources/fill_constants.js';
 import {getRemoteFrameToken} from '//components/autofill/ios/form_util/resources/fill_util.js';
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage, trim} from '//ios/web/public/js_messaging/resources/utils.js';
 
 /**
@@ -346,7 +346,7 @@
 
   const message = {
     command: 'form.submit',
-    frameID: gCrWebLegacy.message.getFrameId(),
+    frameID: gCrWeb.getFrameId(),
     formName: gCrWebLegacy.form.getFormIdentifier(form),
     href: getFullyQualifiedUrl(action),
     formData: gCrWebLegacy.fill.autofillSubmissionData(form),
diff --git a/components/autofill/ios/form_util/resources/form_handlers.ts b/components/autofill/ios/form_util/resources/form_handlers.ts
index 47e8400..7265f58 100644
--- a/components/autofill/ios/form_util/resources/form_handlers.ts
+++ b/components/autofill/ios/form_util/resources/form_handlers.ts
@@ -11,7 +11,7 @@
 // Requires functions from fill.ts, form.ts, autofill_form_features.ts and
 // child_frame_registration_lib.ts.
 
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 /**
@@ -143,7 +143,7 @@
 
   const msg = {
     'command': 'form.activity',
-    'frameID': gCrWebLegacy.message.getFrameId(),
+    'frameID': gCrWeb.getFrameId(),
     'formName': gCrWebLegacy.form.getFormIdentifier(form),
     'formRendererID': formRendererID,
     'fieldIdentifier': gCrWebLegacy.form.getFieldIdentifier(field),
@@ -362,7 +362,7 @@
       if (!addedFormMessage && formWasAdded) {
         addedFormMessage = {
           'command': 'form.activity',
-          'frameID': gCrWebLegacy.message.getFrameId(),
+          'frameID': gCrWeb.getFrameId(),
           'formName': '',
           'formRendererID': '',
           'fieldIdentifier': '',
@@ -404,7 +404,7 @@
               forms.map(form => gCrWebLegacy.fill.getUniqueID(form));
           removedFormMessage = {
             'command': 'form.removal',
-            'frameID': gCrWebLegacy.message.getFrameId(),
+            'frameID': gCrWeb.getFrameId(),
             'removedFormIDs': gCrWebLegacy.stringify(filteredFormIDs),
             'removedFieldIDs': gCrWebLegacy.stringify(removedFormlessFieldsIds),
           };
@@ -416,7 +416,7 @@
         // Handle the removed formless field case.
         removedFormMessage = {
           'command': 'form.removal',
-          'frameID': gCrWebLegacy.message.getFrameId(),
+          'frameID': gCrWeb.getFrameId(),
           'removedFieldIDs': gCrWebLegacy.stringify(removedFormlessFieldsIds),
         };
         continue;
@@ -430,7 +430,7 @@
         // mutation that is treated the same way as adding a new form.
         addedFormMessage = {
           'command': 'form.activity',
-          'frameID': gCrWebLegacy.message.getFrameId(),
+          'frameID': gCrWeb.getFrameId(),
           'formName': '',
           'formRendererID': '',
           'fieldIdentifier': '',
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp
index cfc400c4..435e64e 100644
--- a/components/autofill_payments_strings.grdp
+++ b/components/autofill_payments_strings.grdp
@@ -450,6 +450,11 @@
   <message name="IDS_AUTOFILL_CARD_UNMASK_CONFIRMATION_MESSAGE" desc="Message displayed after tapping a card, and the response from the bank indicates that no further verification is required.">
     Verified
   </message>
+  <if expr="is_ios">
+    <message name="IDS_IOS_AUTOFILL_PROGRESS_DIALOG_CONFIRMATION_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement to indicate autofill progress dialog shows confirmation state. This is spoken by VoiceOver.">
+      Verified
+    </message>
+  </if>
   <message name="IDS_AUTOFILL_3DS_FETCH_VCN_PROGRESS_DIALOG_LOADING_MESSAGE" desc="Message to be displayed after a VCN 3DS authentication has completed, and Chrome is attempting to retrieve the virtual card from the Payments server. If the authentication was successful, a confirmation message will display in the progress dialog and then the virtual card will be filled. If the authentication was not successful, an error message will be displayed.">
     Verifying...
   </message>
diff --git a/components/autofill_payments_strings_grdp/IDS_IOS_AUTOFILL_PROGRESS_DIALOG_CONFIRMATION_ACCESSIBILITY_ANNOUNCEMENT.png.sha1 b/components/autofill_payments_strings_grdp/IDS_IOS_AUTOFILL_PROGRESS_DIALOG_CONFIRMATION_ACCESSIBILITY_ANNOUNCEMENT.png.sha1
new file mode 100644
index 0000000..8be1c98
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_IOS_AUTOFILL_PROGRESS_DIALOG_CONFIRMATION_ACCESSIBILITY_ANNOUNCEMENT.png.sha1
@@ -0,0 +1 @@
+fcde686abe55285d63edfa69b9f01b6fe9e9f0ae
\ No newline at end of file
diff --git a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
index 4d5e927..1195c5f 100644
--- a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
+++ b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
@@ -208,7 +208,7 @@
      * feature/content that is showing. It can be a dynamic string. 'Swipe down to close.' will be
      * automatically appended after the content description.
      */
-    String getSheetContentDescription(Context context);
+    @Nullable String getSheetContentDescription(Context context);
 
     /**
      * @return The resource id of the string announced when the sheet is opened at half height. This
diff --git a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
index 3c9147a..de92866 100644
--- a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
+++ b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
@@ -106,7 +106,9 @@
      * @param hideReason The reason that the content is being hidden.
      */
     void hideContent(
-            BottomSheetContent content, boolean animate, @StateChangeReason int hideReason);
+            @Nullable BottomSheetContent content,
+            boolean animate,
+            @StateChangeReason int hideReason);
 
     void hideContent(@Nullable BottomSheetContent content, boolean animate);
 
diff --git a/components/browser_ui/modaldialog/android/java/res/layout/modal_dialog_title.xml b/components/browser_ui/modaldialog/android/java/res/layout/modal_dialog_title.xml
index a7e57378..f300f81 100644
--- a/components/browser_ui/modaldialog/android/java/res/layout/modal_dialog_title.xml
+++ b/components/browser_ui/modaldialog/android/java/res/layout/modal_dialog_title.xml
@@ -16,7 +16,8 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:layout_marginEnd="8dp"
-        android:importantForAccessibility="no" />
+        android:importantForAccessibility="no"
+        android:focusable="false"/>
 
     <androidx.appcompat.widget.DialogTitle
         android:id="@+id/title"
diff --git a/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/ModalDialogView.java b/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/ModalDialogView.java
index c69e071..bf14780 100644
--- a/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/ModalDialogView.java
+++ b/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/ModalDialogView.java
@@ -245,13 +245,12 @@
         mTitleView.setMaxLines(maxLines);
     }
 
-    /** @param drawable The icon drawable on the title. */
+    /**
+     * @param drawable The icon drawable on the title.
+     */
     public void setTitleIcon(Drawable drawable) {
         mTitleIcon.setImageDrawable(drawable);
         updateContentVisibility();
-        if (drawable != null) {
-            setupClickableView(mTitleIcon, ButtonType.TITLE_ICON);
-        }
     }
 
     /** @param titleScrollable Whether the title is scrollable with the message. */
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java
index 6a987039..b666873 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java
@@ -109,7 +109,8 @@
      *
      * @see CompoundButton#setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener).
      */
-    public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener listener) {
+    public void setOnCheckedChangeListener(
+            CompoundButton.@Nullable OnCheckedChangeListener listener) {
         mSwitch.setOnCheckedChangeListener(listener);
     }
 }
diff --git a/components/browsing_data/content/browsing_data_model.cc b/components/browsing_data/content/browsing_data_model.cc
index 3f7534b4..20225f5 100644
--- a/components/browsing_data/content/browsing_data_model.cc
+++ b/components/browsing_data/content/browsing_data_model.cc
@@ -752,10 +752,6 @@
          inner_iterator_ == other.inner_iterator_;
 }
 
-bool BrowsingDataModel::Iterator::operator!=(const Iterator& other) const {
-  return !operator==(other);
-}
-
 BrowsingDataModel::BrowsingDataEntryView
 BrowsingDataModel::Iterator::operator*() const {
   DCHECK(outer_iterator_ != outer_end_iterator_);
diff --git a/components/browsing_data/content/browsing_data_model.h b/components/browsing_data/content/browsing_data_model.h
index 55c4bc7f..5b86e91 100644
--- a/components/browsing_data/content/browsing_data_model.h
+++ b/components/browsing_data/content/browsing_data_model.h
@@ -204,7 +204,6 @@
     ~Iterator();
     Iterator(const Iterator& iterator);
     bool operator==(const Iterator& other) const;
-    bool operator!=(const Iterator& other) const;
 
     // Input iterator functionality. These declarations allow STL functions to
     // make use of the iterator interface.
diff --git a/components/browsing_data/core/browsing_data_utils.h b/components/browsing_data/core/browsing_data_utils.h
index cf7573a..61e3057 100644
--- a/components/browsing_data/core/browsing_data_utils.h
+++ b/components/browsing_data/core/browsing_data_utils.h
@@ -20,42 +20,49 @@
 // in all platforms.
 extern const char kDeleteBrowsingDataDialogHistogram[];
 
-// Browsing data types as seen in the Android and Desktop UI.
+// Browsing data types as seen in the Android and Desktop UI. Keep in sync with
+// the respective enum in
+// c/b/r/s/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
 //
 // A Java counterpart will be generated for this enum.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
+// LINT.IfChange(BrowsingDataType)
 enum class BrowsingDataType {
-  HISTORY,
-  CACHE,
-  SITE_DATA,
-  PASSWORDS,
-  FORM_DATA,
-  SITE_SETTINGS,
+  HISTORY = 0,
+  CACHE = 1,
+  SITE_DATA = 2,
+  PASSWORDS = 3,
+  FORM_DATA = 4,
+  SITE_SETTINGS = 5,
   // Only for Desktop:
-  DOWNLOADS,
-  HOSTED_APPS_DATA,
-  TABS,
+  DOWNLOADS = 6,
+  HOSTED_APPS_DATA = 7,
+  // Only for Android:
+  TABS = 8,
   MAX_VALUE = TABS,
 };
+// LINT.ThenChange(/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts:BrowsingDataType)
 
 // Time period ranges available when doing browsing data removals.
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused. Keep in sync with respective enums in
 // tools/metrics/histograms/metadata/settings/enums.xml and
-// c/b/r/s/clear_browsing_data_dialog/clear_browsing_data_dialog.ts
+// c/b/r/s/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
 //
 // A Java counterpart will be generated for this enum.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
+// LINT.IfChange(TimePeriod)
 enum class TimePeriod {
   LAST_HOUR = 0,
-  LAST_DAY,
-  LAST_WEEK,
-  FOUR_WEEKS,
-  ALL_TIME,
-  OLDER_THAN_30_DAYS,
-  LAST_15_MINUTES,
+  LAST_DAY = 1,
+  LAST_WEEK = 2,
+  FOUR_WEEKS = 3,
+  ALL_TIME = 4,
+  OLDER_THAN_30_DAYS = 5,
+  LAST_15_MINUTES = 6,
   TIME_PERIOD_LAST = LAST_15_MINUTES
 };
+// LINT.ThenChange(/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts:TimePeriod)
 
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 394f82d..4abb8e0 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "53.34",
-  "log_list_timestamp": "2025-05-05T12:54:12Z",
+  "version": "53.35",
+  "log_list_timestamp": "2025-05-06T12:54:31Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/collaboration_strings.grdp b/components/collaboration_strings.grdp
index 04868144..0d7229ac 100644
--- a/components/collaboration_strings.grdp
+++ b/components/collaboration_strings.grdp
@@ -158,8 +158,8 @@
   <message name="IDS_DATA_SHARING_RECENT_ACTIVITY_UNKNOWN_USER" desc="The user name to show on the recent activity bottom sheet row if the user info cannot be found, e.g. deleted their account.">
     Deleted account
   </message>
-  <message name ="IDS_DATA_SHARING_RECENT_ACTIVITY_SHOW_ALL" desc="The text on the button to show the full recent activity logs." formatter_data="android_java">
-    See full activity
+  <message name ="IDS_DATA_SHARING_SHARED_TAB_GROUP_ACTIVITY" desc="The text on the button to show the full recent activity logs and manage screen menu options." formatter_data="android_java">
+    Shared tab group activity
   </message>
   <!-- Recent Activity -->
 
diff --git a/components/collaboration_strings_grdp/IDS_DATA_SHARING_RECENT_ACTIVITY_SHOW_ALL.png.sha1 b/components/collaboration_strings_grdp/IDS_DATA_SHARING_RECENT_ACTIVITY_SHOW_ALL.png.sha1
deleted file mode 100644
index 613c0a61..0000000
--- a/components/collaboration_strings_grdp/IDS_DATA_SHARING_RECENT_ACTIVITY_SHOW_ALL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b4c0bcff0719f2aa94b7da82e46178c3cd906222
\ No newline at end of file
diff --git a/components/collaboration_strings_grdp/IDS_DATA_SHARING_SHARED_TAB_GROUP_ACTIVITY.png.sha1 b/components/collaboration_strings_grdp/IDS_DATA_SHARING_SHARED_TAB_GROUP_ACTIVITY.png.sha1
new file mode 100644
index 0000000..d61607d0
--- /dev/null
+++ b/components/collaboration_strings_grdp/IDS_DATA_SHARING_SHARED_TAB_GROUP_ACTIVITY.png.sha1
@@ -0,0 +1 @@
+cf9b27802baddb7c506b71dc00ba116852a36e3f
\ No newline at end of file
diff --git a/components/content_capture/browser/content_capture_frame.h b/components/content_capture/browser/content_capture_frame.h
index da905bc9..35ce135 100644
--- a/components/content_capture/browser/content_capture_frame.h
+++ b/components/content_capture/browser/content_capture_frame.h
@@ -65,10 +65,6 @@
   std::string favicon;
 
   bool operator==(const ContentCaptureFrame& other) const;
-
-  bool operator!=(const ContentCaptureFrame& other) const {
-    return !(*this == other);
-  }
 };
 
 // This defines a session, is a list of frames from current frame to root.
diff --git a/components/content_capture/common/content_capture_data.cc b/components/content_capture/common/content_capture_data.cc
index 75ce0b6..86d7950 100644
--- a/components/content_capture/common/content_capture_data.cc
+++ b/components/content_capture/common/content_capture_data.cc
@@ -13,9 +13,4 @@
 
 ContentCaptureData::~ContentCaptureData() = default;
 
-bool ContentCaptureData::operator==(const ContentCaptureData& other) const {
-  return id == other.id && value == other.value && bounds == other.bounds &&
-         children == other.children;
-}
-
 }  // namespace content_capture
diff --git a/components/content_capture/common/content_capture_data.h b/components/content_capture/common/content_capture_data.h
index 340ea95..0c45b5b 100644
--- a/components/content_capture/common/content_capture_data.h
+++ b/components/content_capture/common/content_capture_data.h
@@ -29,6 +29,9 @@
   ContentCaptureData(const ContentCaptureData& data);
   ~ContentCaptureData();
 
+  friend bool operator==(const ContentCaptureData&,
+                         const ContentCaptureData&) = default;
+
   // The id of the frame or the content,
   // For frame, this will be 0 until ContentCaptureReceiver assigns a unique ID.
   int64_t id = 0;
@@ -41,12 +44,6 @@
   gfx::Rect bounds;
   // The children content, only available for frame or scrollable area.
   std::vector<ContentCaptureData> children;
-
-  bool operator==(const ContentCaptureData& other) const;
-
-  bool operator!=(const ContentCaptureData& other) const {
-    return !(*this == other);
-  }
 };
 
 }  // namespace content_capture
diff --git a/components/content_settings/core/browser/cookie_settings.h b/components/content_settings/core/browser/cookie_settings.h
index 19f346f..319f7f5 100644
--- a/components/content_settings/core/browser/cookie_settings.h
+++ b/components/content_settings/core/browser/cookie_settings.h
@@ -44,6 +44,7 @@
 // This enum needs to be kept in sync with the enum of the same name in
 // browser/resources/settings/site_settings/constants.js.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.content_settings
+// LINT.IfChange(CookieControlsMode)
 enum class CookieControlsMode {
   kOff = 0,
   kBlockThirdParty = 1,
@@ -51,6 +52,7 @@
   kLimited = 3,
   kMaxValue = kLimited,
 };
+// LINT.ThenChange(/tools/metrics/histograms/enums.xml:CookieControlsMode, /chrome/browser/resources/settings/site_settings/constants.ts:CookieControlsMode)
 
 // Default value for |extension_scheme|.
 const char kDummyExtensionScheme[] = ":no-extension-scheme:";
diff --git a/components/cronet/gn2bp/templates/Android.extras.bp.template b/components/cronet/gn2bp/templates/Android.extras.bp.template
index 17e54c5..0cb202b 100644
--- a/components/cronet/gn2bp/templates/Android.extras.bp.template
+++ b/components/cronet/gn2bp/templates/Android.extras.bp.template
@@ -203,13 +203,3 @@
         "//external/cronet:__subpackages__",
     ],
 }
-
-filegroup {
-    name: "${GN2BP_MODULE_PREFIX}license_data",
-    srcs: [
-        "**/README.chromium",
-        "**/MODULE_LICENSE_*",
-        "**/LICENSE",
-        "**/METADATA",
-    ],
-}
diff --git a/components/data_sharing/OWNERS b/components/data_sharing/OWNERS
index f98d9b6..b259a13 100644
--- a/components/data_sharing/OWNERS
+++ b/components/data_sharing/OWNERS
@@ -2,6 +2,7 @@
 mmoskvitin@google.com
 nyquist@chromium.org
 qinmin@chromium.org
+ritikagup@google.com
 rushans@google.com
 shaktisahu@chromium.org
 ssid@chromium.org
diff --git a/components/dbus/properties/types.cc b/components/dbus/properties/types.cc
index 71cda5f..f479bf3c 100644
--- a/components/dbus/properties/types.cc
+++ b/components/dbus/properties/types.cc
@@ -99,10 +99,6 @@
   return IsEqual(other);
 }
 
-bool DbusType::operator!=(const DbusType& other) const {
-  return !(*this == other);
-}
-
 bool DbusType::Move(DbusType&& object) {
   if (GetSignatureDynamic() != object.GetSignatureDynamic()) {
     return false;
diff --git a/components/dbus/properties/types.h b/components/dbus/properties/types.h
index 25488e61..3931a10a 100644
--- a/components/dbus/properties/types.h
+++ b/components/dbus/properties/types.h
@@ -30,7 +30,6 @@
   virtual ~DbusType();
 
   bool operator==(const DbusType& other) const;
-  bool operator!=(const DbusType& other) const;
 
   // Serializes this object to `writer`.
   virtual void Write(dbus::MessageWriter* writer) const = 0;
diff --git a/components/download/database/download_db_entry.cc b/components/download/database/download_db_entry.cc
index cb758f2..e94e6f7 100644
--- a/components/download/database/download_db_entry.cc
+++ b/components/download/database/download_db_entry.cc
@@ -12,18 +12,10 @@
 
 DownloadDBEntry::~DownloadDBEntry() = default;
 
-bool DownloadDBEntry::operator==(const DownloadDBEntry& other) const {
-  return download_info == other.download_info;
-}
-
 std::string DownloadDBEntry::GetGuid() const {
   if (!download_info)
     return std::string();
   return download_info->guid;
 }
 
-bool DownloadDBEntry::operator!=(const DownloadDBEntry& other) const {
-  return !(*this == other);
-}
-
 }  // namespace download
diff --git a/components/download/database/download_db_entry.h b/components/download/database/download_db_entry.h
index 5876e41..9a05162 100644
--- a/components/download/database/download_db_entry.h
+++ b/components/download/database/download_db_entry.h
@@ -20,8 +20,8 @@
   DownloadDBEntry(const DownloadDBEntry& other);
   ~DownloadDBEntry();
 
-  bool operator==(const DownloadDBEntry& other) const;
-  bool operator!=(const DownloadDBEntry& other) const;
+  friend bool operator==(const DownloadDBEntry&,
+                         const DownloadDBEntry&) = default;
 
   // Gets a unique ID for this entry.
   std::string GetGuid() const;
diff --git a/components/download/database/in_progress/download_entry.cc b/components/download/database/in_progress/download_entry.cc
index ddf08f2..c235dae 100644
--- a/components/download/database/in_progress/download_entry.cc
+++ b/components/download/database/in_progress/download_entry.cc
@@ -26,17 +26,4 @@
 
 DownloadEntry::~DownloadEntry() = default;
 
-bool DownloadEntry::operator==(const DownloadEntry& other) const {
-  return guid == other.guid && request_origin == other.request_origin &&
-         download_source == other.download_source &&
-         ukm_download_id == other.ukm_download_id &&
-         bytes_wasted == other.bytes_wasted &&
-         fetch_error_body == other.fetch_error_body &&
-         request_headers == other.request_headers;
-}
-
-bool DownloadEntry::operator!=(const DownloadEntry& other) const {
-  return !(*this == other);
-}
-
 }  // namespace download
diff --git a/components/download/database/in_progress/download_entry.h b/components/download/database/in_progress/download_entry.h
index 5872229..93dc01bce 100644
--- a/components/download/database/in_progress/download_entry.h
+++ b/components/download/database/in_progress/download_entry.h
@@ -27,9 +27,7 @@
       int64_t ukm_id);
   ~DownloadEntry();
 
-  bool operator==(const DownloadEntry& other) const;
-
-  bool operator!=(const DownloadEntry& other) const;
+  friend bool operator==(const DownloadEntry&, const DownloadEntry&) = default;
 
   // A unique GUID that represents this download.
   std::string guid;
diff --git a/components/download/internal/background_service/scheduler/device_status.cc b/components/download/internal/background_service/scheduler/device_status.cc
index 0c5f534..897bf18 100644
--- a/components/download/internal/background_service/scheduler/device_status.cc
+++ b/components/download/internal/background_service/scheduler/device_status.cc
@@ -30,16 +30,6 @@
       battery_percentage(battery_percentage),
       network_status(network) {}
 
-bool DeviceStatus::operator==(const DeviceStatus& rhs) const {
-  return network_status == rhs.network_status &&
-         battery_status == rhs.battery_status &&
-         battery_percentage == rhs.battery_percentage;
-}
-
-bool DeviceStatus::operator!=(const DeviceStatus& rhs) const {
-  return !(*this == rhs);
-}
-
 DeviceStatus::Result DeviceStatus::MeetsCondition(
     const SchedulingParams& params,
     int download_battery_percentage) const {
diff --git a/components/download/internal/background_service/scheduler/device_status.h b/components/download/internal/background_service/scheduler/device_status.h
index 2512fc1..90306a1 100644
--- a/components/download/internal/background_service/scheduler/device_status.h
+++ b/components/download/internal/background_service/scheduler/device_status.h
@@ -50,8 +50,7 @@
 
   NetworkStatus network_status;
 
-  bool operator==(const DeviceStatus& rhs) const;
-  bool operator!=(const DeviceStatus& rhs) const;
+  friend bool operator==(const DeviceStatus&, const DeviceStatus&) = default;
 
   // Returns if the current device status meets all the conditions defined in
   // the scheduling parameters.
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
index e0264aff..3726055 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -186,6 +186,7 @@
 }
 
 bool WebContentsDelegateAndroid::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h
index 67a01b4..996b3d45 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.h
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h
@@ -79,6 +79,7 @@
                           const GURL& target_url,
                           content::WebContents* new_contents) override;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/components/enterprise/connectors/core/enterprise_interstitial_util.cc b/components/enterprise/connectors/core/enterprise_interstitial_util.cc
index 297a4d3..8c3d0b669 100644
--- a/components/enterprise/connectors/core/enterprise_interstitial_util.cc
+++ b/components/enterprise/connectors/core/enterprise_interstitial_util.cc
@@ -37,14 +37,14 @@
 
 std::u16string GetUrlFilteringCustomMessage(
     const std::vector<security_interstitials::UnsafeResource>&
-        unsafe_resources_) {
+        unsafe_resources) {
   std::u16string custom_message = u"";
   int highest_severity_verdict = 0;
 
-  if (!unsafe_resources_.empty() &&
-      !unsafe_resources_[0].rt_lookup_response.threat_info().empty()) {
+  if (!unsafe_resources.empty() &&
+      !unsafe_resources[0].rt_lookup_response.threat_info().empty()) {
     const auto& threat_infos =
-        unsafe_resources_[0].rt_lookup_response.threat_info();
+        unsafe_resources[0].rt_lookup_response.threat_info();
 
     // If it exists, We pick a non-empty custom message from all matched rules
     // at the same highest severity level.
diff --git a/components/enterprise/connectors/core/enterprise_interstitial_util.h b/components/enterprise/connectors/core/enterprise_interstitial_util.h
index 86fab59..467b3161 100644
--- a/components/enterprise/connectors/core/enterprise_interstitial_util.h
+++ b/components/enterprise/connectors/core/enterprise_interstitial_util.h
@@ -6,8 +6,8 @@
 #define COMPONENTS_ENTERPRISE_CONNECTORS_CORE_ENTERPRISE_INTERSTITIAL_UTIL_H_
 
 #include <string>
+#include <vector>
 
-#include "components/safe_browsing/core/common/proto/realtimeapi.pb.h"
 #include "components/security_interstitials/core/unsafe_resource.h"
 
 // This namespace contains shared functions for enterprise interstitials
@@ -17,7 +17,7 @@
 // Returns the custom message specified by admin in RTLookup response.
 std::u16string GetUrlFilteringCustomMessage(
     const std::vector<security_interstitials::UnsafeResource>&
-        unsafe_resources_);
+        unsafe_resources);
 
 }  // namespace enterprise_connectors
 
diff --git a/components/enterprise/connectors/core/reporting_event_router.h b/components/enterprise/connectors/core/reporting_event_router.h
index 120240b23..2f313c61 100644
--- a/components/enterprise/connectors/core/reporting_event_router.h
+++ b/components/enterprise/connectors/core/reporting_event_router.h
@@ -55,7 +55,9 @@
   // `user_name`
   void OnPasswordChanged(const std::string& user_name);
 
-  void OnUrlFilteringInterstitial(
+  // Notifies listeners about events related to Url Filtering Interstitials.
+  // Virtual for tests.
+  virtual void OnUrlFilteringInterstitial(
       const GURL& url,
       const std::string& threat_type,
       const safe_browsing::RTLookupResponse& response,
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationParams.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationParams.java
index 5d7ac0ce..8b8dcc2 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationParams.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationParams.java
@@ -99,6 +99,7 @@
     private boolean mIsRendererInitiated;
     private @Nullable Origin mInitiatorOrigin;
     private final long mNavigationId;
+    private final boolean mIsCustomTab;
 
     // Populated when an async action is taken, ensuring the callback gets called.
     private @Nullable RequiredCallback<AsyncActionTakenParams> mRequiredAsyncActionTakenCallback;
@@ -122,7 +123,8 @@
             boolean isInitialNavigationInFrame,
             boolean isHiddenCrossFrameNavigation,
             boolean isSandboxedMainFrame,
-            long navigationId) {
+            long navigationId,
+            boolean isCustomTab) {
         mUrl = url;
         mIsIncognito = isIncognito;
         mPageTransition = pageTransition;
@@ -142,6 +144,7 @@
         mIsHiddenCrossFrameNavigation = isHiddenCrossFrameNavigation;
         mIsSandboxedMainFrame = isSandboxedMainFrame;
         mNavigationId = navigationId;
+        mIsCustomTab = isCustomTab;
     }
 
     public void onAsyncActionStarted() {
@@ -261,6 +264,13 @@
         return mNavigationId;
     }
 
+    /**
+     * @return whether this WebContents is a Custom Tab, false otherwise.
+     */
+    public boolean isCustomTab() {
+        return mIsCustomTab;
+    }
+
     /** The builder for {@link ExternalNavigationParams} objects. */
     public static class Builder {
         private GURL mUrl;
@@ -282,6 +292,7 @@
         private boolean mIsHiddenCrossFrameNavigation;
         private boolean mIsSandboxedMainFrame;
         private long mNavigationId;
+        private boolean mIsCustomTab;
 
         public Builder(GURL url, boolean isIncognito) {
             mUrl = url;
@@ -384,6 +395,12 @@
             return this;
         }
 
+        /** Sets whether this navigation was started in a custom tab (e.g. PWA) */
+        public Builder setIsCustomTab(boolean isCustomTab) {
+            mIsCustomTab = isCustomTab;
+            return this;
+        }
+
         /**
          * @return A fully constructed {@link ExternalNavigationParams} object.
          */
@@ -407,7 +424,8 @@
                     mIsInitialNavigationInFrame,
                     mIsHiddenCrossFrameNavigation,
                     mIsSandboxedMainFrame,
-                    mNavigationId);
+                    mNavigationId,
+                    mIsCustomTab);
         }
     }
 }
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java
index 9d661d3..f861fae 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java
@@ -50,4 +50,7 @@
      * @param loadUrlParams parameters of the URL to be loaded
      */
     void loadUrlIfPossible(LoadUrlParams loadUrlParams);
+
+    /* Returns whether the tab associated with this client is a custom tab or not */
+    boolean isCustomTab();
 }
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
index 6220569d..8241ab0 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
@@ -449,6 +449,7 @@
                         .setIsHiddenCrossFrameNavigation(hiddenCrossFrame)
                         .setIsSandboxedMainFrame(isSandboxedMainFrame)
                         .setNavigationId(navigationId)
+                        .setIsCustomTab(mClient.isCustomTab())
                         .build();
         if (!shouldRunAsync) return doShouldOverrideUrlLoading(params, isExternalProtocol);
         Runnable shouldIgnoreCheck =
diff --git a/components/feature_engagement/public/configuration.cc b/components/feature_engagement/public/configuration.cc
index 1ddd6c3..db2190e 100644
--- a/components/feature_engagement/public/configuration.cc
+++ b/components/feature_engagement/public/configuration.cc
@@ -190,53 +190,12 @@
   return os << "] }";
 }
 
-bool operator==(const SessionRateImpact& lhs, const SessionRateImpact& rhs) {
-  return std::tie(lhs.type, lhs.affected_features) ==
-         std::tie(rhs.type, rhs.affected_features);
-}
-
-bool operator==(const BlockedBy& lhs, const BlockedBy& rhs) {
-  return std::tie(lhs.type, lhs.affected_features) ==
-         std::tie(rhs.type, rhs.affected_features);
-}
-
-bool operator==(const Blocking& lhs, const Blocking& rhs) {
-  return lhs.type == rhs.type;
-}
-
-bool operator==(const SnoozeParams& lhs, const SnoozeParams& rhs) {
-  return std::tie(lhs.max_limit, lhs.snooze_interval) ==
-         std::tie(rhs.max_limit, rhs.snooze_interval);
-}
-
 FeatureConfig::FeatureConfig() = default;
 
 FeatureConfig::FeatureConfig(const FeatureConfig& other) = default;
 
 FeatureConfig::~FeatureConfig() = default;
 
-bool operator==(const Comparator& lhs, const Comparator& rhs) {
-  return std::tie(lhs.type, lhs.value) == std::tie(rhs.type, rhs.value);
-}
-
-bool operator<(const Comparator& lhs, const Comparator& rhs) {
-  return std::tie(lhs.type, lhs.value) < std::tie(rhs.type, rhs.value);
-}
-
-bool operator==(const EventConfig& lhs, const EventConfig& rhs) {
-  return std::tie(lhs.name, lhs.comparator, lhs.window, lhs.storage) ==
-         std::tie(rhs.name, rhs.comparator, rhs.window, rhs.storage);
-}
-
-bool operator!=(const EventConfig& lhs, const EventConfig& rhs) {
-  return !(lhs == rhs);
-}
-
-bool operator<(const EventConfig& lhs, const EventConfig& rhs) {
-  return std::tie(lhs.name, lhs.comparator, lhs.window, lhs.storage) <
-         std::tie(rhs.name, rhs.comparator, rhs.window, rhs.storage);
-}
-
 bool operator==(const FeatureConfig& lhs, const FeatureConfig& rhs) {
   return std::tie(lhs.valid, lhs.used, lhs.trigger, lhs.event_configs,
                   lhs.session_rate, lhs.availability) ==
@@ -267,12 +226,6 @@
 
 GroupConfig::~GroupConfig() = default;
 
-bool operator==(const GroupConfig& lhs, const GroupConfig& rhs) {
-  return std::tie(lhs.valid, lhs.trigger, lhs.event_configs,
-                  lhs.session_rate) ==
-         std::tie(rhs.valid, rhs.trigger, rhs.event_configs, rhs.session_rate);
-}
-
 std::ostream& operator<<(std::ostream& os, const GroupConfig& group_config) {
   os << "{ valid: " << group_config.valid
      << ", trigger: " << group_config.trigger << ", event_configs: [";
diff --git a/components/feature_engagement/public/configuration.h b/components/feature_engagement/public/configuration.h
index 8fb5f435..2096b81 100644
--- a/components/feature_engagement/public/configuration.h
+++ b/components/feature_engagement/public/configuration.h
@@ -44,6 +44,9 @@
   Comparator(ComparatorType type, uint32_t value);
   ~Comparator();
 
+  friend bool operator==(const Comparator&, const Comparator&) = default;
+  friend auto operator<=>(const Comparator&, const Comparator&) = default;
+
   // Returns true if the |v| meets the this criteria based on the current
   // |type| and |value|.
   bool MeetsCriteria(uint32_t v) const;
@@ -52,8 +55,6 @@
   uint32_t value;
 };
 
-bool operator==(const Comparator& lhs, const Comparator& rhs);
-bool operator<(const Comparator& lhs, const Comparator& rhs);
 std::ostream& operator<<(std::ostream& os, const Comparator& comparator);
 
 // A EventConfig contains all the information about how many times
@@ -68,6 +69,9 @@
               uint32_t storage);
   ~EventConfig();
 
+  friend bool operator==(const EventConfig&, const EventConfig&) = default;
+  friend auto operator<=>(const EventConfig&, const EventConfig&) = default;
+
   // The identifier of the event.
   std::string name;
 
@@ -82,9 +86,6 @@
   uint32_t storage;
 };
 
-bool operator==(const EventConfig& lhs, const EventConfig& rhs);
-bool operator!=(const EventConfig& lhs, const EventConfig& rhs);
-bool operator<(const EventConfig& lhs, const EventConfig& rhs);
 std::ostream& operator<<(std::ostream& os, const EventConfig& event_config);
 
 // A SessionRateImpact describes which features the |session_rate| of a given
@@ -103,6 +104,9 @@
   SessionRateImpact(const SessionRateImpact& other);
   ~SessionRateImpact();
 
+  friend bool operator==(const SessionRateImpact&,
+                         const SessionRateImpact&) = default;
+
   // Describes which features are impacted.
   Type type;
 
@@ -111,7 +115,6 @@
   std::optional<std::vector<std::string>> affected_features;
 };
 
-bool operator==(const SessionRateImpact& lhs, const SessionRateImpact& rhs);
 std::ostream& operator<<(std::ostream& os, const SessionRateImpact& impact);
 
 // BlockedBy describes which features the |blocked_by| of a given
@@ -130,6 +133,8 @@
   BlockedBy(const BlockedBy& other);
   ~BlockedBy();
 
+  friend bool operator==(const BlockedBy&, const BlockedBy&) = default;
+
   // Describes which features are impacted.
   Type type{Type::ALL};
 
@@ -138,7 +143,6 @@
   std::optional<std::vector<std::string>> affected_features;
 };
 
-bool operator==(const BlockedBy& lhs, const BlockedBy& rhs);
 std::ostream& operator<<(std::ostream& os, const BlockedBy& impact);
 
 // Blocking describes which features the |blocking| of a given FeatureConfig
@@ -154,11 +158,12 @@
   Blocking(const Blocking& other);
   ~Blocking();
 
+  friend bool operator==(const Blocking&, const Blocking&) = default;
+
   // Describes which features are impacted.
   Type type{Type::ALL};
 };
 
-bool operator==(const Blocking& lhs, const Blocking& rhs);
 std::ostream& operator<<(std::ostream& os, const Blocking& impact);
 
 // A SnoozeParams describes the parameters for snoozable options of in-product
@@ -173,9 +178,10 @@
   SnoozeParams();
   SnoozeParams(const SnoozeParams& other);
   ~SnoozeParams();
+
+  friend bool operator==(const SnoozeParams&, const SnoozeParams&) = default;
 };
 
-bool operator==(const SnoozeParams& lhs, const SnoozeParams& rhs);
 std::ostream& operator<<(std::ostream& os, const SnoozeParams& impact);
 
 // A FeatureConfig contains all the configuration for a given feature.
@@ -241,6 +247,8 @@
   GroupConfig(const GroupConfig& other);
   ~GroupConfig();
 
+  friend bool operator==(const GroupConfig&, const GroupConfig&) = default;
+
   // Whether the group configuration has been successfully parsed.
   bool valid{false};
 
@@ -258,7 +266,6 @@
   std::set<EventConfig> event_configs;
 };
 
-bool operator==(const GroupConfig& lhs, const GroupConfig& rhs);
 std::ostream& operator<<(std::ostream& os, const GroupConfig& feature_config);
 
 // A Configuration contains the current set of runtime configurations.
diff --git a/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc b/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
index 4d71fd43..6eb9cae 100644
--- a/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
@@ -269,7 +269,6 @@
       "LogResponseReceived id=1 receive_timestamp=123456000 send_timestamp=0\n"
       "LogRequestFinished result=200 id=1\n"
 
-      "LogLoadingIndicatorShown\n"
       "LogLaunchFinishedAfterStreamUpdate "
       "result=NO_CARDS_RESPONSE_ERROR_ZERO_CARDS\n"
 
diff --git a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
index 5ba16c6..c19f1f4 100644
--- a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -1756,7 +1756,7 @@
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
 
-  ASSERT_EQ("loading -> loading -> no-cards", surface.DescribeUpdates());
+  ASSERT_EQ("loading -> no-cards", surface.DescribeUpdates());
 
   // This network response has no content.
   EXPECT_FALSE(stream_->HasUnreadContent(StreamType(StreamKind::kForYou)));
@@ -2761,6 +2761,38 @@
   EXPECT_EQ("new-frame-data", stored_data->content[0].frame());
 }
 
+// Test that we do not overwrite stored stream data if no content is received.
+TEST_F(FeedApiTest, DoNotOverwriteExistingStreamOnEmptyContent) {
+  // Trigger stream load with valid content saved to the storage.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  surface.Detach();
+  UnloadModel(surface.GetStreamType());
+
+  // Trigger a background refresh with no card.
+  response_translator_.InjectResponse(MakeEmptyModelState());
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+  WaitForIdleTaskQueue();
+
+  // Verify the refresh happened.
+  ASSERT_TRUE(refresh_scheduler_.completed_tasks.count(
+      RefreshTaskId::kRefreshForYouFeed));
+  EXPECT_TRUE(network_.query_request_sent);
+  EXPECT_EQ(feedwire::FeedQuery::SCHEDULED_REFRESH,
+            network_.query_request_sent->feed_request().feed_query().reason());
+  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
+
+  // The refresh request should fail with no card error.
+  EXPECT_EQ(LoadStreamStatus::kNoCardReceived,
+            metrics_reporter_->background_refresh_status);
+
+  // The stored cards should not be updated.
+  TestForYouSurface surface2(stream_.get());
+  WaitForIdleTaskQueue();
+  EXPECT_EQ("loading -> [user@foo] 2 slices", surface2.DescribeUpdates());
+}
+
 TEST_F(FeedApiTest, HasUnreadContentIsFalseAfterFeedViewed) {
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
   TestForYouSurface surface(stream_.get());
diff --git a/components/feed/core/v2/enums.cc b/components/feed/core/v2/enums.cc
index e1c42b6b..949892b 100644
--- a/components/feed/core/v2/enums.cc
+++ b/components/feed/core/v2/enums.cc
@@ -114,6 +114,8 @@
       return out << "kLoadNotAllowedDisabled";
     case LoadStreamStatus::kLoadNotAllowedDisabledByDse:
       return out << "kLoadNotAllowedDisabledByDse";
+    case LoadStreamStatus::kNoCardReceived:
+      return out << "kNoCardReceived";
   }
 #else
   return out << (static_cast<int>(value));
@@ -157,6 +159,7 @@
     case LoadStreamStatus::kNetworkFetchTimedOut:
     case LoadStreamStatus::kLoadNotAllowedDisabled:
     case LoadStreamStatus::kLoadNotAllowedDisabledByDse:
+    case LoadStreamStatus::kNoCardReceived:
       return false;
   }
 }
diff --git a/components/feed/core/v2/enums.h b/components/feed/core/v2/enums.h
index 40c4e5e..a6e5eca 100644
--- a/components/feed/core/v2/enums.h
+++ b/components/feed/core/v2/enums.h
@@ -93,7 +93,8 @@
   kNetworkFetchTimedOut = 29,
   kLoadNotAllowedDisabled = 30,
   kLoadNotAllowedDisabledByDse = 31,
-  kMaxValue = kLoadNotAllowedDisabledByDse,
+  kNoCardReceived = 32,
+  kMaxValue = kNoCardReceived,
 };
 
 // Were we able to load fresh Feed data. This should be 'true' unless some kind
diff --git a/components/feed/core/v2/proto_util.cc b/components/feed/core/v2/proto_util.cc
index e0b5e78..f5258add 100644
--- a/components/feed/core/v2/proto_util.cc
+++ b/components/feed/core/v2/proto_util.cc
@@ -174,9 +174,7 @@
     feed_request.add_client_capability(Capability::SYNTHETIC_CAPABILITIES);
   }
 
-  if (base::FeatureList::IsEnabled(kFeedDynamicColors)) {
-    feed_request.add_client_capability(Capability::DYNAMIC_COLORS);
-  }
+  feed_request.add_client_capability(Capability::DYNAMIC_COLORS);
 
   if (base::FeatureList::IsEnabled(kFeedStreaming)) {
     feed_request.add_client_capability(Capability::STREAMING_FULL);
diff --git a/components/feed/core/v2/proto_util_unittest.cc b/components/feed/core/v2/proto_util_unittest.cc
index 7822c95..1c50c97 100644
--- a/components/feed/core/v2/proto_util_unittest.cc
+++ b/components/feed/core/v2/proto_util_unittest.cc
@@ -83,7 +83,8 @@
            feedwire::Capability::PREFETCH_METADATA, feedwire::Capability::SHARE,
            feedwire::Capability::CONTENT_LIFETIME,
            feedwire::Capability::INFO_CARD_ACKNOWLEDGEMENT_TRACKING,
-           feedwire::Capability::SPORTS_IN_GAME_UPDATE}));
+           feedwire::Capability::SPORTS_IN_GAME_UPDATE,
+           feedwire::Capability::DYNAMIC_COLORS}));
 }
 
 // SYNC_STRING_REMOVAL is mobile-only.
@@ -205,21 +206,6 @@
               Contains(feedwire::Capability::AMP_GROUP_DATASTORE));
 }
 
-TEST(ProtoUtilTest, DynamicColorEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({kFeedDynamicColors}, {});
-  feedwire::FeedRequest request =
-      CreateFeedQueryRefreshRequest(
-          StreamType(StreamKind::kForYou), feedwire::FeedQuery::MANUAL_REFRESH,
-          /*request_metadata=*/{},
-          /*consistency_token=*/std::string(), SingleWebFeedEntryPoint::kOther,
-          /*doc_view_counts=*/{})
-          .feed_request();
-
-  ASSERT_THAT(request.client_capability(),
-              Contains(feedwire::Capability::DYNAMIC_COLORS));
-}
-
 // ReadLater is enabled by default everywhere with the exception of iOS which
 // has a build-flag to enable it.
 #if !BUILDFLAG(IS_IOS)
diff --git a/components/feed/core/v2/surface_updater.cc b/components/feed/core/v2/surface_updater.cc
index 4e3dd91e..327876e 100644
--- a/components/feed/core/v2/surface_updater.cc
+++ b/components/feed/core/v2/surface_updater.cc
@@ -213,6 +213,7 @@
     case LoadStreamStatus::kAlreadyHaveUnreadContent:
     case LoadStreamStatus::kLoadNotAllowedDisabled:
     case LoadStreamStatus::kLoadNotAllowedDisabledByDse:
+    case LoadStreamStatus::kNoCardReceived:
       break;
   }
   return feedui::ZeroStateSlice::NO_CARDS_AVAILABLE;
diff --git a/components/feed/core/v2/tasks/load_stream_task.cc b/components/feed/core/v2/tasks/load_stream_task.cc
index 01d8a2db..f63a693 100644
--- a/components/feed/core/v2/tasks/load_stream_task.cc
+++ b/components/feed/core/v2/tasks/load_stream_task.cc
@@ -423,10 +423,18 @@
          feedwire::DiscoverLaunchResult::NO_CARDS_REQUEST_ERROR_OTHER});
   }
 
-  loaded_new_content_from_network_ = true;
   content_ids_ =
       feedstore::GetContentIds(response_data.model_update_request->stream_data);
 
+  // Bail out if no card is received.
+  if (content_ids_.IsEmpty()) {
+    return RequestFinished(
+        {LoadStreamStatus::kNoCardReceived,
+         feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_ZERO_CARDS});
+  }
+
+  loaded_new_content_from_network_ = true;
+
   stream_->GetStore().OverwriteStream(
       options_.stream_type,
       std::make_unique<StreamModelUpdateRequest>(
diff --git a/components/feed/core/v2/test/stream_builder.cc b/components/feed/core/v2/test/stream_builder.cc
index 19972a9..6d9c7c5 100644
--- a/components/feed/core/v2/test/stream_builder.cc
+++ b/components/feed/core/v2/test/stream_builder.cc
@@ -231,36 +231,40 @@
 std::unique_ptr<StreamModelUpdateRequest>
 StreamModelUpdateRequestGenerator::MakeFirstPageWithSpecificContents(
     const std::vector<int>& id_numbers) const {
-  int first_cluster_id = id_numbers.front();
-  bool include_notice_card =
-      (privacy_notice_fulfilled && first_cluster_id == 0);
-
   auto initial_update = std::make_unique<StreamModelUpdateRequest>();
   initial_update->source =
       StreamModelUpdateRequest::Source::kInitialLoadFromStore;
   initial_update->stream_structures = {MakeClearAll(), MakeStream()};
 
-  for (const auto i : id_numbers) {
-    if (include_notice_card && i == first_cluster_id) {
-      initial_update->content.push_back(MakeNoticeCardContent(i));
-      initial_update->stream_structures.push_back(
-          MakeNoticeCardCluster(i, MakeRootId()));
-      initial_update->stream_structures.push_back(
-          MakeNoticeCardContentNode(i, MakeClusterId(i)));
-    } else {
-      initial_update->content.push_back(MakeContent(i));
-      initial_update->stream_structures.push_back(MakeCluster(i, MakeRootId()));
-      initial_update->stream_structures.push_back(
-          MakeContentNode(i, MakeClusterId(i)));
+  if (!id_numbers.empty()) {
+    int first_cluster_id = id_numbers.front();
+    bool include_notice_card =
+        (privacy_notice_fulfilled && first_cluster_id == 0);
+
+    for (const auto i : id_numbers) {
+      if (include_notice_card && i == first_cluster_id) {
+        initial_update->content.push_back(MakeNoticeCardContent(i));
+        initial_update->stream_structures.push_back(
+            MakeNoticeCardCluster(i, MakeRootId()));
+        initial_update->stream_structures.push_back(
+            MakeNoticeCardContentNode(i, MakeClusterId(i)));
+      } else {
+        initial_update->content.push_back(MakeContent(i));
+        initial_update->stream_structures.push_back(
+            MakeCluster(i, MakeRootId()));
+        initial_update->stream_structures.push_back(
+            MakeContentNode(i, MakeClusterId(i)));
+      }
     }
+
+    initial_update->shared_states.push_back(MakeSharedState(first_cluster_id));
+    *initial_update->stream_data.add_shared_state_ids() =
+        MakeSharedStateId(first_cluster_id);
   }
 
-  initial_update->shared_states.push_back(MakeSharedState(first_cluster_id));
   *initial_update->stream_data.mutable_content_id() = MakeRootId();
   initial_update->stream_data.set_root_event_id(
       MakeRootEventId(event_id_number));
-  *initial_update->stream_data.add_shared_state_ids() =
-      MakeSharedStateId(first_cluster_id);
   initial_update->stream_data.set_next_page_token("page-2");
   initial_update->stream_data.set_signed_in(signed_in);
   if (signed_in) {
@@ -322,6 +326,17 @@
   return initial_update;
 }
 
+std::unique_ptr<StreamModelUpdateRequest> MakeEmptyModelState() {
+  StreamModelUpdateRequestGenerator generator;
+  generator.last_added_time = kTestTimeEpoch;
+  generator.signed_in = true;
+  generator.logging_enabled = true;
+  generator.privacy_notice_fulfilled = false;
+  generator.stream_key = feedstore::StreamKey(StreamType(StreamKind::kForYou));
+
+  return generator.MakeFirstPage(/*first_cluster_id=*/0, /*num_cards=*/0);
+}
+
 std::unique_ptr<StreamModelUpdateRequest> MakeTypicalInitialModelState(
     int first_cluster_id,
     base::Time last_added_time,
diff --git a/components/feed/core/v2/test/stream_builder.h b/components/feed/core/v2/test/stream_builder.h
index 93f0c8f..908d9db 100644
--- a/components/feed/core/v2/test/stream_builder.h
+++ b/components/feed/core/v2/test/stream_builder.h
@@ -85,6 +85,8 @@
           StreamModelUpdateRequest::Source::kInitialLoadFromStore) const;
 };
 
+std::unique_ptr<StreamModelUpdateRequest> MakeEmptyModelState();
+
 // Returns data operations to create a typical stream:
 // Root
 // |-Cluster 0
diff --git a/components/feed/feed_feature_list.cc b/components/feed/feed_feature_list.cc
index 5353c65..45fa660 100644
--- a/components/feed/feed_feature_list.cc
+++ b/components/feed/feed_feature_list.cc
@@ -85,10 +85,6 @@
              "FeedSignedOutViewDemotion",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kFeedDynamicColors,
-             "FeedDynamicColors",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kFeedFollowUiUpdate,
              "FeedFollowUiUpdate",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h
index 6b7fd102..b2b79e0 100644
--- a/components/feed/feed_feature_list.h
+++ b/components/feed/feed_feature_list.h
@@ -101,10 +101,6 @@
 COMPONENT_EXPORT(COMPONENTS_FEED_FEATURE_LIST)
 BASE_DECLARE_FEATURE(kFeedSignedOutViewDemotion);
 
-// Feature that enables dynamic colors in the feed.
-COMPONENT_EXPORT(COMPONENTS_FEED_FEATURE_LIST)
-BASE_DECLARE_FEATURE(kFeedDynamicColors);
-
 // Feature that enables UI update for Follow.
 COMPONENT_EXPORT(COMPONENTS_FEED_FEATURE_LIST)
 BASE_DECLARE_FEATURE(kFeedFollowUiUpdate);
diff --git a/components/feedback/redaction_tool/ip_address.cc b/components/feedback/redaction_tool/ip_address.cc
index 52f292c9..b163ac9 100644
--- a/components/feedback/redaction_tool/ip_address.cc
+++ b/components/feedback/redaction_tool/ip_address.cc
@@ -115,10 +115,6 @@
   return std::ranges::equal(*this, other);
 }
 
-bool IPAddressBytes::operator!=(const IPAddressBytes& other) const {
-  return !(*this == other);
-}
-
 // static
 
 IPAddress::IPAddress() = default;
@@ -217,14 +213,6 @@
   return AllZeros(kIPv6AddressSize);
 }
 
-bool IPAddress::operator==(const IPAddress& that) const {
-  return ip_address_ == that.ip_address_;
-}
-
-bool IPAddress::operator!=(const IPAddress& that) const {
-  return ip_address_ != that.ip_address_;
-}
-
 bool IPAddress::operator<(const IPAddress& that) const {
   // Sort IPv4 before IPv6.
   if (ip_address_.size() != that.ip_address_.size()) {
diff --git a/components/feedback/redaction_tool/ip_address.h b/components/feedback/redaction_tool/ip_address.h
index e6d9f20..5272025 100644
--- a/components/feedback/redaction_tool/ip_address.h
+++ b/components/feedback/redaction_tool/ip_address.h
@@ -94,7 +94,6 @@
   }
 
   bool operator<(const IPAddressBytes& other) const;
-  bool operator!=(const IPAddressBytes& other) const;
   bool operator==(const IPAddressBytes& other) const;
 
   size_t EstimateMemoryUsage() const;
@@ -219,8 +218,7 @@
   // Returns an IPAddress instance representing the :: address.
   static IPAddress IPv6AllZeros();
 
-  bool operator==(const IPAddress& that) const;
-  bool operator!=(const IPAddress& that) const;
+  friend bool operator==(const IPAddress&, const IPAddress&) = default;
   bool operator<(const IPAddress& that) const;
 
   // Must be a valid address (per IsValid()).
diff --git a/components/history/core/browser/history_types.cc b/components/history/core/browser/history_types.cc
index 2b6df0af..5e56ded6 100644
--- a/components/history/core/browser/history_types.cc
+++ b/components/history/core/browser/history_types.cc
@@ -49,26 +49,6 @@
 
 VisitRow::VisitRow(const VisitRow&) = default;
 
-// VisitedLinkRow --------------------------------------------------------------
-
-bool operator==(const VisitedLinkRow& lhs, const VisitedLinkRow& rhs) {
-  return std::tie(lhs.id, lhs.link_url_id, lhs.top_level_url, lhs.frame_url,
-                  lhs.visit_count) == std::tie(rhs.id, rhs.link_url_id,
-                                               rhs.top_level_url, rhs.frame_url,
-                                               rhs.visit_count);
-}
-
-bool operator!=(const VisitedLinkRow& lhs, const VisitedLinkRow& rhs) {
-  return !(lhs == rhs);
-}
-
-bool operator<(const VisitedLinkRow& lhs, const VisitedLinkRow& rhs) {
-  return std::tie(lhs.id, lhs.link_url_id, lhs.top_level_url, lhs.frame_url,
-                  lhs.visit_count) < std::tie(rhs.id, rhs.link_url_id,
-                                              rhs.top_level_url, rhs.frame_url,
-                                              rhs.visit_count);
-}
-
 // QueryResults ----------------------------------------------------------------
 
 QueryResults::QueryResults() = default;
@@ -503,39 +483,6 @@
 
 VisitContextAnnotations::~VisitContextAnnotations() = default;
 
-bool VisitContextAnnotations::operator==(
-    const VisitContextAnnotations& other) const {
-  return on_visit == other.on_visit &&
-         omnibox_url_copied == other.omnibox_url_copied &&
-         is_existing_part_of_tab_group == other.is_existing_part_of_tab_group &&
-         is_placed_in_tab_group == other.is_placed_in_tab_group &&
-         is_existing_bookmark == other.is_existing_bookmark &&
-         is_new_bookmark == other.is_new_bookmark &&
-         is_ntp_custom_link == other.is_ntp_custom_link &&
-         duration_since_last_visit == other.duration_since_last_visit &&
-         page_end_reason == other.page_end_reason &&
-         total_foreground_duration == other.total_foreground_duration;
-}
-
-bool VisitContextAnnotations::operator!=(
-    const VisitContextAnnotations& other) const {
-  return !(*this == other);
-}
-
-bool VisitContextAnnotations::OnVisitFields::operator==(
-    const VisitContextAnnotations::OnVisitFields& other) const {
-  return browser_type == other.browser_type && window_id == other.window_id &&
-         tab_id == other.tab_id && task_id == other.task_id &&
-         root_task_id == other.root_task_id &&
-         parent_task_id == other.parent_task_id &&
-         response_code == other.response_code;
-}
-
-bool VisitContextAnnotations::OnVisitFields::operator!=(
-    const VisitContextAnnotations::OnVisitFields& other) const {
-  return !(*this == other);
-}
-
 AnnotatedVisit::AnnotatedVisit() = default;
 AnnotatedVisit::AnnotatedVisit(URLRow url_row,
                                VisitRow visit_row,
diff --git a/components/history/core/browser/history_types.h b/components/history/core/browser/history_types.h
index 8672270..c18f798a 100644
--- a/components/history/core/browser/history_types.h
+++ b/components/history/core/browser/history_types.h
@@ -247,10 +247,10 @@
   // partition key).
   int visit_count = 0;
 
- private:
-  friend bool operator==(const VisitedLinkRow& lhs, const VisitedLinkRow& rhs);
-  friend bool operator!=(const VisitedLinkRow& lhs, const VisitedLinkRow& rhs);
-  friend bool operator<(const VisitedLinkRow& lhs, const VisitedLinkRow& rhs);
+  friend bool operator==(const VisitedLinkRow&,
+                         const VisitedLinkRow&) = default;
+  friend auto operator<=>(const VisitedLinkRow&,
+                          const VisitedLinkRow&) = default;
 };
 using VisitedLinkRows = std::vector<VisitedLinkRow>;
 
@@ -883,8 +883,8 @@
   VisitContextAnnotations(const VisitContextAnnotations& other);
   ~VisitContextAnnotations();
 
-  bool operator==(const VisitContextAnnotations& other) const;
-  bool operator!=(const VisitContextAnnotations& other) const;
+  friend bool operator==(const VisitContextAnnotations&,
+                         const VisitContextAnnotations&) = default;
 
   // Values are persisted; do not reorder or reuse, and only add new values at
   // the end.
@@ -914,8 +914,8 @@
     // The HTTP response code of the navigation.
     int response_code = 0;
 
-    bool operator==(const OnVisitFields& other) const;
-    bool operator!=(const OnVisitFields& other) const;
+    friend bool operator==(const OnVisitFields&,
+                           const OnVisitFields&) = default;
   };
 
   OnVisitFields on_visit;
diff --git a/components/history/core/browser/url_row.cc b/components/history/core/browser/url_row.cc
index b10e93d..e5a469e 100644
--- a/components/history/core/browser/url_row.cc
+++ b/components/history/core/browser/url_row.cc
@@ -67,16 +67,6 @@
   return base::StrCat({id, ":", base::NumberToString(weight)});
 }
 
-bool VisitContentModelAnnotations::Category::operator==(
-    const VisitContentModelAnnotations::Category& other) const {
-  return id == other.id && weight == other.weight;
-}
-
-bool VisitContentModelAnnotations::Category::operator!=(
-    const VisitContentModelAnnotations::Category& other) const {
-  return !(*this == other);
-}
-
 VisitContentModelAnnotations::VisitContentModelAnnotations(
     float visibility_score,
     const std::vector<Category>& categories,
diff --git a/components/history/core/browser/url_row.h b/components/history/core/browser/url_row.h
index a718b82..384f099 100644
--- a/components/history/core/browser/url_row.h
+++ b/components/history/core/browser/url_row.h
@@ -190,8 +190,7 @@
     static std::optional<Category> FromStringVector(
         const std::vector<std::string>& vector);
     std::string ToString() const;
-    bool operator==(const Category& other) const;
-    bool operator!=(const Category& other) const;
+    friend bool operator==(const Category&, const Category&) = default;
 
     std::string id;
     int weight = 0;
diff --git a/components/infobars/core/infobar_container.cc b/components/infobars/core/infobar_container.cc
index fe20d04..aa26556 100644
--- a/components/infobars/core/infobar_container.cc
+++ b/components/infobars/core/infobar_container.cc
@@ -89,6 +89,10 @@
   infobars_.erase(i);
 }
 
+bool InfoBarContainer::ShouldHideInFullscreen() const {
+  return infobar_manager_->ShouldHideInFullscreen();
+}
+
 void InfoBarContainer::RemoveAllInfoBarsForDestruction() {
   // Before we remove any children, we reset |delegate_|, so that no removals
   // will result in us trying to call
diff --git a/components/infobars/core/infobar_container.h b/components/infobars/core/infobar_container.h
index 0d44712..6d1a846 100644
--- a/components/infobars/core/infobar_container.h
+++ b/components/infobars/core/infobar_container.h
@@ -61,6 +61,8 @@
 
   const Delegate* delegate() const { return delegate_; }
 
+  bool ShouldHideInFullscreen() const;
+
  protected:
   // Subclasses must call this during destruction, so that we can remove
   // infobars (which will call the pure virtual functions below) while the
diff --git a/components/infobars/core/infobar_delegate.cc b/components/infobars/core/infobar_delegate.cc
index dc39b91..2cb887a 100644
--- a/components/infobars/core/infobar_delegate.cc
+++ b/components/infobars/core/infobar_delegate.cc
@@ -84,6 +84,10 @@
   return true;
 }
 
+bool InfoBarDelegate::ShouldHideInFullscreen() const {
+  return false;
+}
+
 ConfirmInfoBarDelegate* InfoBarDelegate::AsConfirmInfoBarDelegate() {
   return nullptr;
 }
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index c15c2da..8018ed6 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -285,6 +285,10 @@
   // default.
   virtual bool ShouldAnimate() const;
 
+  // Returns true if the InfoBar should hide when the browser is in fullscreen
+  // mode. True by default.
+  virtual bool ShouldHideInFullscreen() const;
+
   // Type-checking downcast routines:
   virtual ConfirmInfoBarDelegate* AsConfirmInfoBarDelegate();
   virtual blocked_content::PopupBlockedInfoBarDelegate*
diff --git a/components/infobars/core/infobar_manager.cc b/components/infobars/core/infobar_manager.cc
index 6c7e9083..f4c8b437 100644
--- a/components/infobars/core/infobar_manager.cc
+++ b/components/infobars/core/infobar_manager.cc
@@ -170,6 +170,13 @@
   infobar->CloseSoon();
 }
 
+bool InfoBarManager::ShouldHideInFullscreen() const {
+  return std::all_of(infobars_.begin(), infobars_.end(), [](InfoBar* infobar) {
+    return infobar->delegate()->ShouldHideInFullscreen();
+  });
+  ;
+}
+
 bool InfoBarManager::ShouldShowInfoBar(const InfoBar* infobar) const {
   DCHECK(infobar);
 
diff --git a/components/infobars/core/infobar_manager.h b/components/infobars/core/infobar_manager.h
index 6b98977..b911dab9 100644
--- a/components/infobars/core/infobar_manager.h
+++ b/components/infobars/core/infobar_manager.h
@@ -102,6 +102,8 @@
   // Opens a URL according to the specified |disposition|.
   virtual void OpenURL(const GURL& url, WindowOpenDisposition disposition) = 0;
 
+  bool ShouldHideInFullscreen() const;
+
  protected:
   void set_animations_enabled(bool animations_enabled) {
     animations_enabled_ = animations_enabled;
diff --git a/components/language/ios/browser/resources/language_detection.ts b/components/language/ios/browser/resources/language_detection.ts
index efbc4a3..ea92c656 100644
--- a/components/language/ios/browser/resources/language_detection.ts
+++ b/components/language/ios/browser/resources/language_detection.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 // Mark: Private properties
@@ -128,7 +128,7 @@
     'hasNoTranslate': false,
     'htmlLang': document.documentElement.lang,
     'httpContentLanguage': httpContentLanguage,
-    'frameId': gCrWebLegacy.message.getFrameId(),
+    'frameId': gCrWeb.getFrameId(),
   };
 
   if (hasNoTranslate()) {
diff --git a/components/media_router/common/discovery/media_sink_internal.cc b/components/media_router/common/discovery/media_sink_internal.cc
index 490b60b..d912283 100644
--- a/components/media_router/common/discovery/media_sink_internal.cc
+++ b/components/media_router/common/discovery/media_sink_internal.cc
@@ -72,10 +72,6 @@
   NOTREACHED();
 }
 
-bool MediaSinkInternal::operator!=(const MediaSinkInternal& other) const {
-  return !operator==(other);
-}
-
 bool MediaSinkInternal::operator<(const MediaSinkInternal& other) const {
   return sink_.id() < other.sink().id();
 }
diff --git a/components/media_router/common/discovery/media_sink_internal.h b/components/media_router/common/discovery/media_sink_internal.h
index f48e5dd..9c7bd61 100644
--- a/components/media_router/common/discovery/media_sink_internal.h
+++ b/components/media_router/common/discovery/media_sink_internal.h
@@ -92,7 +92,6 @@
   MediaSinkInternal& operator=(const MediaSinkInternal& other);
   MediaSinkInternal& operator=(MediaSinkInternal&& other) noexcept;
   bool operator==(const MediaSinkInternal& other) const;
-  bool operator!=(const MediaSinkInternal& other) const;
   // Sorted by sink id.
   bool operator<(const MediaSinkInternal& other) const;
 
diff --git a/components/media_router/common/media_sink.cc b/components/media_router/common/media_sink.cc
index ba85a77..f30ae2ad 100644
--- a/components/media_router/common/media_sink.cc
+++ b/components/media_router/common/media_sink.cc
@@ -27,15 +27,6 @@
 MediaSink& MediaSink::operator=(const MediaSink& other) = default;
 MediaSink& MediaSink::operator=(MediaSink&& other) noexcept = default;
 
-bool MediaSink::operator==(const MediaSink& other) const {
-  return sink_id_ == other.sink_id_ && name_ == other.name_ &&
-         icon_type_ == other.icon_type_ && provider_id_ == other.provider_id_;
-}
-
-bool MediaSink::operator!=(const MediaSink& other) const {
-  return !operator==(other);
-}
-
 bool MediaSink::CompareUsingCollator(const MediaSink& other,
                                      const icu::Collator* collator) const {
   if (icon_type_ != other.icon_type_) {
diff --git a/components/media_router/common/media_sink.h b/components/media_router/common/media_sink.h
index 324896b..836e8ce7 100644
--- a/components/media_router/common/media_sink.h
+++ b/components/media_router/common/media_sink.h
@@ -66,8 +66,7 @@
   }
   mojom::MediaRouteProviderId provider_id() const { return provider_id_; }
 
-  bool operator==(const MediaSink& other) const;
-  bool operator!=(const MediaSink& other) const;
+  friend bool operator==(const MediaSink&, const MediaSink&) = default;
 
   // Compares |this| to |other| first by their icon types, then their names
   // using |collator|, and finally their IDs.
diff --git a/components/metrics_services_manager/metrics_services_manager.h b/components/metrics_services_manager/metrics_services_manager.h
index 5d63624..b5eeb68 100644
--- a/components/metrics_services_manager/metrics_services_manager.h
+++ b/components/metrics_services_manager/metrics_services_manager.h
@@ -99,7 +99,10 @@
   OnRendererUnresponsiveCb GetOnRendererUnresponsiveCb();
 
   // Updates the managed services when permissions for uploading metrics change.
-  void UpdateUploadPermissions(bool may_upload);
+  // Note: Normally, uploads will happen when collection is enabled, but the
+  // `may_upload` params allows disabling uploads separately from collection
+  // (e.g. if network is unavailable).
+  void UpdateUploadPermissions(bool may_upload = true);
 
   // Gets the current state of metric reporting.
   bool IsMetricsReportingEnabled() const;
diff --git a/components/ntp_tiles/ntp_tile.cc b/components/ntp_tiles/ntp_tile.cc
index 10506e9..b19d7bc6 100644
--- a/components/ntp_tiles/ntp_tile.cc
+++ b/components/ntp_tiles/ntp_tile.cc
@@ -20,8 +20,4 @@
          (a.from_most_visited == b.from_most_visited);
 }
 
-bool operator!=(const NTPTile& a, const NTPTile& b) {
-  return !(a == b);
-}
-
 }  // namespace ntp_tiles
diff --git a/components/ntp_tiles/ntp_tile.h b/components/ntp_tiles/ntp_tile.h
index d0a76684..e193d287 100644
--- a/components/ntp_tiles/ntp_tile.h
+++ b/components/ntp_tiles/ntp_tile.h
@@ -48,7 +48,6 @@
 };
 
 bool operator==(const NTPTile& a, const NTPTile& b);
-bool operator!=(const NTPTile& a, const NTPTile& b);
 
 using NTPTilesVector = std::vector<NTPTile>;
 
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.cc b/components/offline_pages/content/background_loader/background_loader_contents.cc
index e0e9a5a8..9dcf196 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents.cc
+++ b/components/offline_pages/content/background_loader/background_loader_contents.cc
@@ -86,6 +86,7 @@
 }
 
 bool BackgroundLoaderContents::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.h b/components/offline_pages/content/background_loader/background_loader_contents.h
index c6838c8..b3fef77c 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents.h
+++ b/components/offline_pages/content/background_loader/background_loader_contents.h
@@ -63,6 +63,7 @@
                    base::OnceCallback<void(bool)> callback) override;
 
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc b/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
index fa4d1e4f..00e0635f 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
+++ b/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
@@ -142,7 +142,7 @@
 
 TEST_F(BackgroundLoaderContentsTest, ShouldNotCreateWebContents) {
   ASSERT_TRUE(contents()->IsWebContentsCreationOverridden(
-      nullptr /* source_site_instance */,
+      nullptr /* opener */, nullptr /* source_site_instance */,
       content::mojom::WindowContainerType::NORMAL /* window_container_type */,
       GURL() /* opener_url */, "foo" /* frame_name */,
       GURL() /* target_url */));
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index 425f25c..d9be8fd 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit 425f25c52e48f3cf6a80dd192a880bdb3106e99c
+Subproject commit d9be8fda5a8b047287677a35f2b3a6111f5883be
diff --git a/components/origin_trials/common/persisted_trial_token.cc b/components/origin_trials/common/persisted_trial_token.cc
index 7f052c5..0d71f03 100644
--- a/components/origin_trials/common/persisted_trial_token.cc
+++ b/components/origin_trials/common/persisted_trial_token.cc
@@ -81,14 +81,6 @@
   return to_tuple(a) < to_tuple(b);
 }
 
-bool operator==(const PersistedTrialToken& a, const PersistedTrialToken& b) {
-  return to_tuple(a) == to_tuple(b) && a.partition_sites == b.partition_sites;
-}
-
-bool operator!=(const PersistedTrialToken& a, const PersistedTrialToken& b) {
-  return !(a == b);
-}
-
 std::ostream& operator<<(std::ostream& out, const PersistedTrialToken& token) {
   out << "{";
   out << "match_subdomains: " << base::ToString(token.match_subdomains) << ", ";
diff --git a/components/origin_trials/common/persisted_trial_token.h b/components/origin_trials/common/persisted_trial_token.h
index 7fc64ab..7f86f699 100644
--- a/components/origin_trials/common/persisted_trial_token.h
+++ b/components/origin_trials/common/persisted_trial_token.h
@@ -56,18 +56,16 @@
   // specifically the origin, match subdomains, trial name, expiry time, and
   // signature attributes.
   bool Matches(const blink::TrialToken& trial_token) const;
+
+  // Equality operator for testing.
+  friend bool operator==(const PersistedTrialToken&,
+                         const PersistedTrialToken&) = default;
 };
 
 // Comparison operator to let us store PersistedTokens in a flat_set.
 // Does not take partitioning metadata into account.
 bool operator<(const PersistedTrialToken& a, const PersistedTrialToken& b);
 
-// Equality operator for testing.
-bool operator==(const PersistedTrialToken& a, const PersistedTrialToken& b);
-
-// In-equality operator for testing
-bool operator!=(const PersistedTrialToken& a, const PersistedTrialToken& b);
-
 // Stream operator, mainly for GTEST output
 std::ostream& operator<<(std::ostream& out, const PersistedTrialToken& token);
 
diff --git a/components/page_info/core/about_this_site_service_unittest.cc b/components/page_info/core/about_this_site_service_unittest.cc
index ab3cc8d9..256ffe3 100644
--- a/components/page_info/core/about_this_site_service_unittest.cc
+++ b/components/page_info/core/about_this_site_service_unittest.cc
@@ -258,9 +258,9 @@
           std::string_view(), std::string_view(), std::string_view(),
           std::string_view(), std::string_view(), std::string_view(),
           std::string_view(), std::string_view(), std::string_view(),
-          std::vector<std::string>(), std::string_view(), std::string_view(),
-          std::u16string_view(), base::Value::List(), false, false, 0,
-          base::span<TemplateURLData::RegulatoryExtension>())));
+          std::string_view(), std::vector<std::string>(), std::string_view(),
+          std::string_view(), std::u16string_view(), base::Value::List(), false,
+          false, 0, base::span<TemplateURLData::RegulatoryExtension>())));
   templateService()->SetUserSelectedDefaultSearchProvider(template_url);
 
   auto info = service()->GetAboutThisSiteInfo(
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.cc b/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.cc
index bc7ef83..abb4bf1 100644
--- a/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.cc
+++ b/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.cc
@@ -443,22 +443,6 @@
   return result;
 }
 
-bool PageAdDensityTracker::RectId::operator<(const RectId& rhs) const {
-  if (rect_type == rhs.rect_type) {
-    return id < rhs.id;
-  }
-
-  return rect_type < rhs.rect_type;
-}
-
-bool PageAdDensityTracker::RectId::operator==(const RectId& rhs) const {
-  return rect_type == rhs.rect_type && id == rhs.id;
-}
-
-bool PageAdDensityTracker::RectId::operator!=(const RectId& rhs) const {
-  return !(*this == rhs);
-}
-
 bool PageAdDensityTracker::RectEvent::operator<(const RectEvent& rhs) const {
   int lhs_y = is_bottom ? rect.bottom() : rect.y();
   int rhs_y = rhs.is_bottom ? rhs.rect.bottom() : rhs.rect.y();
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.h b/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.h
index 5e5c01a..399ddb87 100644
--- a/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.h
+++ b/components/page_load_metrics/browser/observers/ad_metrics/page_ad_density_tracker.h
@@ -36,16 +36,15 @@
     RectId(RectType rect_type, int id);
     RectId(const RectId& other);
 
+    friend bool operator==(const RectId&, const RectId&) = default;
+    friend auto operator<=>(const RectId&, const RectId&) = default;
+
     RectType rect_type;
 
     // For iframe, the id comes from the frame tree node id. For other elements
     // (e.g. main frame ad rectangles), the id comes from the node id from the
     // renderer.
     int id;
-
-    bool operator<(const RectId& rhs) const;
-    bool operator==(const RectId& rhs) const;
-    bool operator!=(const RectId& rhs) const;
   };
 
   struct AdDensityCalculationResult {
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.cc b/components/password_manager/core/browser/password_form_metrics_recorder.cc
index 585c881..592825d 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -51,6 +51,7 @@
     // Declined by user.
     case metrics_util::CLICKED_CANCEL:
     case metrics_util::CLICKED_NEVER:
+    case metrics_util::CLICKED_NOT_NOW:
       return BubbleDismissalReason::kDeclined;
 
     // Ignored by user.
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index 239d93f9..468a32e 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -67,6 +67,8 @@
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 // Metrics: "PasswordManager.UIDismissalReason"
+//
+// LINT.IfChange(UIDismissalReason)
 enum UIDismissalReason {
   // We use this to mean both "Bubble lost focus" and "No interaction with the
   // infobar".
@@ -86,8 +88,10 @@
   CLICKED_MANAGE_PASSWORD = 13,
   CLICKED_GOT_IT = 14,
   CLICKED_ABOUT_PASSWORD_CHANGE = 15,
+  CLICKED_NOT_NOW = 16,
   NUM_UI_RESPONSES,
 };
+// LINT.ThenChange(/tools/metrics/histograms/metadata/password/enums.xml:PasswordManagerUIDismissalReason)
 
 // Enum representing the different leak detection dialogs shown to the user.
 // Corresponds to LeakDetectionDialogType suffix in histogram_suffixes_list.xml
diff --git a/components/payments/core/payment_details.cc b/components/payments/core/payment_details.cc
index 5248e60..f6cf7589 100644
--- a/components/payments/core/payment_details.cc
+++ b/components/payments/core/payment_details.cc
@@ -57,10 +57,6 @@
          modifiers == other.modifiers && error == other.error;
 }
 
-bool PaymentDetails::operator!=(const PaymentDetails& other) const {
-  return !(*this == other);
-}
-
 bool PaymentDetails::FromValueDict(const base::Value::Dict& dict,
                                    bool requires_total) {
   display_items.clear();
diff --git a/components/payments/core/payment_details.h b/components/payments/core/payment_details.h
index 09af93aa5..414cdba5 100644
--- a/components/payments/core/payment_details.h
+++ b/components/payments/core/payment_details.h
@@ -29,7 +29,6 @@
 
   PaymentDetails& operator=(const PaymentDetails& other);
   bool operator==(const PaymentDetails& other) const;
-  bool operator!=(const PaymentDetails& other) const;
 
   // Populates the properties of this PaymentDetails from |dict|. Returns true
   // if the required values are present. If |requires_total| is true, the total
diff --git a/components/payments/core/payment_details_modifier.cc b/components/payments/core/payment_details_modifier.cc
index 90907aa..d9b6121 100644
--- a/components/payments/core/payment_details_modifier.cc
+++ b/components/payments/core/payment_details_modifier.cc
@@ -49,11 +49,6 @@
          additional_display_items == other.additional_display_items;
 }
 
-bool PaymentDetailsModifier::operator!=(
-    const PaymentDetailsModifier& other) const {
-  return !(*this == other);
-}
-
 base::Value::Dict PaymentDetailsModifier::ToValueDict() const {
   base::Value::Dict result;
   result.Set(kPaymentDetailsModifierSupportedMethods,
diff --git a/components/payments/core/payment_details_modifier.h b/components/payments/core/payment_details_modifier.h
index 5ecd0012..495ed66 100644
--- a/components/payments/core/payment_details_modifier.h
+++ b/components/payments/core/payment_details_modifier.h
@@ -28,7 +28,6 @@
 
   PaymentDetailsModifier& operator=(const PaymentDetailsModifier& other);
   bool operator==(const PaymentDetailsModifier& other) const;
-  bool operator!=(const PaymentDetailsModifier& other) const;
 
   // Creates a dictionary base::Value with the properties of this
   // PaymentDetailsModifier.
diff --git a/components/payments/core/payment_item.cc b/components/payments/core/payment_item.cc
index 423b45bf..c7ebdf3a 100644
--- a/components/payments/core/payment_item.cc
+++ b/components/payments/core/payment_item.cc
@@ -32,10 +32,6 @@
          pending == other.pending;
 }
 
-bool PaymentItem::operator!=(const PaymentItem& other) const {
-  return !(*this == other);
-}
-
 PaymentItem& PaymentItem::operator=(const PaymentItem& other) {
   label = other.label;
   if (other.amount) {
diff --git a/components/payments/core/payment_item.h b/components/payments/core/payment_item.h
index ea45251..b762a2b 100644
--- a/components/payments/core/payment_item.h
+++ b/components/payments/core/payment_item.h
@@ -30,7 +30,6 @@
   PaymentItem(const PaymentItem& other);
 
   bool operator==(const PaymentItem& other) const;
-  bool operator!=(const PaymentItem& other) const;
   PaymentItem& operator=(const PaymentItem& other);
 
   // Populates the properties of this PaymentItem from |dict|. Returns true if
diff --git a/components/payments/core/payment_method_data.cc b/components/payments/core/payment_method_data.cc
index 6376c46..ccfea0c 100644
--- a/components/payments/core/payment_method_data.cc
+++ b/components/payments/core/payment_method_data.cc
@@ -23,15 +23,6 @@
 PaymentMethodData::PaymentMethodData(const PaymentMethodData& other) = default;
 PaymentMethodData::~PaymentMethodData() = default;
 
-bool PaymentMethodData::operator==(const PaymentMethodData& other) const {
-  return supported_method == other.supported_method && data == other.data &&
-         supported_networks == other.supported_networks;
-}
-
-bool PaymentMethodData::operator!=(const PaymentMethodData& other) const {
-  return !(*this == other);
-}
-
 bool PaymentMethodData::FromValueDict(const base::Value::Dict& dict) {
   supported_networks.clear();
 
diff --git a/components/payments/core/payment_method_data.h b/components/payments/core/payment_method_data.h
index 740b627..585886a 100644
--- a/components/payments/core/payment_method_data.h
+++ b/components/payments/core/payment_method_data.h
@@ -27,8 +27,8 @@
   PaymentMethodData(const PaymentMethodData& other);
   ~PaymentMethodData();
 
-  bool operator==(const PaymentMethodData& other) const;
-  bool operator!=(const PaymentMethodData& other) const;
+  friend bool operator==(const PaymentMethodData&,
+                         const PaymentMethodData&) = default;
 
   // Populates the properties of this PaymentMethodData from |dict|. Returns
   // true if the required values are present.
diff --git a/components/payments/core/payment_options.cc b/components/payments/core/payment_options.cc
index d3ab72f..2f6b838e 100644
--- a/components/payments/core/payment_options.cc
+++ b/components/payments/core/payment_options.cc
@@ -16,16 +16,4 @@
       shipping_type(payments::PaymentShippingType::SHIPPING) {}
 PaymentOptions::~PaymentOptions() = default;
 
-bool PaymentOptions::operator==(const PaymentOptions& other) const {
-  return request_payer_name == other.request_payer_name &&
-         request_payer_email == other.request_payer_email &&
-         request_payer_phone == other.request_payer_phone &&
-         request_shipping == other.request_shipping &&
-         shipping_type == other.shipping_type;
-}
-
-bool PaymentOptions::operator!=(const PaymentOptions& other) const {
-  return !(*this == other);
-}
-
 }  // namespace payments
diff --git a/components/payments/core/payment_options.h b/components/payments/core/payment_options.h
index 3449ce3..b181c0a1 100644
--- a/components/payments/core/payment_options.h
+++ b/components/payments/core/payment_options.h
@@ -18,8 +18,8 @@
   PaymentOptions();
   ~PaymentOptions();
 
-  bool operator==(const PaymentOptions& other) const;
-  bool operator!=(const PaymentOptions& other) const;
+  friend bool operator==(const PaymentOptions&,
+                         const PaymentOptions&) = default;
 
   // Indicates whether the user agent should collect and return the payer's name
   // as part of the payment request. For example, this would be set to true to
diff --git a/components/payments/core/payment_response.cc b/components/payments/core/payment_response.cc
index 7f5c325..ebb314c 100644
--- a/components/payments/core/payment_response.cc
+++ b/components/payments/core/payment_response.cc
@@ -20,8 +20,4 @@
          payer_phone == other.payer_phone;
 }
 
-bool PaymentResponse::operator!=(const PaymentResponse& other) const {
-  return !(*this == other);
-}
-
 }  // namespace payments
diff --git a/components/payments/core/payment_response.h b/components/payments/core/payment_response.h
index c53892f..f6a0b5d 100644
--- a/components/payments/core/payment_response.h
+++ b/components/payments/core/payment_response.h
@@ -24,7 +24,6 @@
   ~PaymentResponse();
 
   bool operator==(const PaymentResponse& other) const;
-  bool operator!=(const PaymentResponse& other) const;
 
   // The same ID present in the original PaymentRequest.
   std::string payment_request_id;
diff --git a/components/payments/core/payment_shipping_option.cc b/components/payments/core/payment_shipping_option.cc
index 89aee184..9f3b08e 100644
--- a/components/payments/core/payment_shipping_option.cc
+++ b/components/payments/core/payment_shipping_option.cc
@@ -36,11 +36,6 @@
          amount.Equals(other.amount) && selected == other.selected;
 }
 
-bool PaymentShippingOption::operator!=(
-    const PaymentShippingOption& other) const {
-  return !(*this == other);
-}
-
 PaymentShippingOption& PaymentShippingOption::operator=(
     const PaymentShippingOption& other) {
   id = other.id;
diff --git a/components/payments/core/payment_shipping_option.h b/components/payments/core/payment_shipping_option.h
index 7009480..131cd83 100644
--- a/components/payments/core/payment_shipping_option.h
+++ b/components/payments/core/payment_shipping_option.h
@@ -27,7 +27,6 @@
   ~PaymentShippingOption();
 
   bool operator==(const PaymentShippingOption& other) const;
-  bool operator!=(const PaymentShippingOption& other) const;
   PaymentShippingOption& operator=(const PaymentShippingOption& other);
 
   // Populates the properties of this PaymentShippingOption from |dict|.
diff --git a/components/performance_manager/execution_context_priority/boosting_vote_aggregator.h b/components/performance_manager/execution_context_priority/boosting_vote_aggregator.h
index 078e40a..1fd5a66 100644
--- a/components/performance_manager/execution_context_priority/boosting_vote_aggregator.h
+++ b/components/performance_manager/execution_context_priority/boosting_vote_aggregator.h
@@ -254,11 +254,7 @@
     Edge& operator=(const Edge&) = default;
     Edge& operator=(Edge&&) = delete;
 
-    bool operator==(const Edge& rhs) const {
-      return std::tie(src_, dst_) == std::tie(rhs.src_, rhs.dst_);
-    }
-
-    bool operator!=(const Edge& rhs) const { return !(*this == rhs); }
+    friend bool operator==(const Edge&, const Edge&) = default;
 
     // Forward edges sort by (src, dst), while reverse edges sort by (dst, src).
     bool operator<(const Edge& rhs) const {
diff --git a/components/performance_manager/execution_context_priority/execution_context_priority.cc b/components/performance_manager/execution_context_priority/execution_context_priority.cc
index f35774b..ce94d28 100644
--- a/components/performance_manager/execution_context_priority/execution_context_priority.cc
+++ b/components/performance_manager/execution_context_priority/execution_context_priority.cc
@@ -27,36 +27,9 @@
 /////////////////////////////////////////////////////////////////////
 // PriorityAndReason
 
-int PriorityAndReason::Compare(const PriorityAndReason& other) const {
-  if (priority_ > other.priority_)
-    return 1;
-  if (priority_ < other.priority_)
-    return -1;
-  return ReasonCompare(reason_, other.reason_);
-}
-
-bool PriorityAndReason::operator==(const PriorityAndReason& other) const {
-  return Compare(other) == 0;
-}
-
-bool PriorityAndReason::operator!=(const PriorityAndReason& other) const {
-  return Compare(other) != 0;
-}
-
-bool PriorityAndReason::operator<=(const PriorityAndReason& other) const {
-  return Compare(other) <= 0;
-}
-
-bool PriorityAndReason::operator>=(const PriorityAndReason& other) const {
-  return Compare(other) >= 0;
-}
-
-bool PriorityAndReason::operator<(const PriorityAndReason& other) const {
-  return Compare(other) < 0;
-}
-
-bool PriorityAndReason::operator>(const PriorityAndReason& other) const {
-  return Compare(other) > 0;
+bool operator==(const PriorityAndReason& lhs, const PriorityAndReason& rhs) {
+  return lhs.priority_ == rhs.priority_ &&
+         ReasonCompare(lhs.reason_, rhs.reason_) == 0;
 }
 
 }  // namespace execution_context_priority
diff --git a/components/performance_manager/features.cc b/components/performance_manager/features.cc
index 541b5a2..b72e600 100644
--- a/components/performance_manager/features.cc
+++ b/components/performance_manager/features.cc
@@ -17,7 +17,7 @@
 #if !BUILDFLAG(IS_ANDROID)
 BASE_FEATURE(kBackgroundTabLoadingFromPerformanceManager,
              "BackgroundTabLoadingFromPerformanceManager",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE_PARAM(size_t,
                    kBackgroundTabLoadingMinSiteEngagement,
diff --git a/components/performance_manager/public/execution_context_priority/execution_context_priority.h b/components/performance_manager/public/execution_context_priority/execution_context_priority.h
index 41b275e..0864133 100644
--- a/components/performance_manager/public/execution_context_priority/execution_context_priority.h
+++ b/components/performance_manager/public/execution_context_priority/execution_context_priority.h
@@ -38,16 +38,15 @@
   base::TaskPriority priority() const { return priority_; }
   const char* reason() const { return reason_; }
 
-  // Returns -1, 0 or 1 indicating the outcome of a comparison of this value
-  // and |other|.
-  int Compare(const PriorityAndReason& other) const;
-
-  bool operator==(const PriorityAndReason& other) const;
-  bool operator!=(const PriorityAndReason& other) const;
-  bool operator<=(const PriorityAndReason& other) const;
-  bool operator>=(const PriorityAndReason& other) const;
-  bool operator<(const PriorityAndReason& other) const;
-  bool operator>(const PriorityAndReason& other) const;
+  friend bool operator==(const PriorityAndReason& lhs,
+                         const PriorityAndReason& rhs);
+  friend auto operator<=>(const PriorityAndReason& lhs,
+                          const PriorityAndReason& rhs) {
+    if (lhs.priority_ != rhs.priority_) {
+      return lhs.priority_ <=> rhs.priority_;
+    }
+    return ReasonCompare(lhs.reason_, rhs.reason_) <=> 0;
+  }
 
  private:
   base::TaskPriority priority_ = base::TaskPriority::LOWEST;
diff --git a/components/performance_manager/public/resource_attribution/type_helpers.h b/components/performance_manager/public/resource_attribution/type_helpers.h
index 6ab9763..edbadfd01 100644
--- a/components/performance_manager/public/resource_attribution/type_helpers.h
+++ b/components/performance_manager/public/resource_attribution/type_helpers.h
@@ -118,24 +118,11 @@
   return std::holds_alternative<T>(a) && std::get<T>(a) == b;
 }
 
-template <typename T, typename V>
-  requires(kIsVariantAlternative<T, V>)
-constexpr bool operator!=(const T& a, const V& b) {
-  return !std::holds_alternative<T>(b) || a != std::get<T>(b);
-}
-
-template <typename T, typename V>
-  requires(kIsVariantAlternative<T, V>)
-constexpr bool operator!=(const V& a, const T& b) {
-  return !std::holds_alternative<T>(a) || std::get<T>(a) != b;
-}
-
 }  // namespace internal
 
 // Enable extended comparators for variants defined in the resource_attribution
 // namespace.
 using internal::operator==;
-using internal::operator!=;
 
 }  // namespace resource_attribution
 
diff --git a/components/performance_manager/public/voting/voting.h b/components/performance_manager/public/voting/voting.h
index 5047ff6..07072ec 100644
--- a/components/performance_manager/public/voting/voting.h
+++ b/components/performance_manager/public/voting/voting.h
@@ -54,8 +54,7 @@
 #include "base/types/id_type.h"
 #include "base/types/pass_key.h"
 
-namespace performance_manager {
-namespace voting {
+namespace performance_manager::voting {
 
 // Contains a single vote. Specifically allows copying, etc, so as to be STL
 // container friendly.
@@ -78,7 +77,6 @@
   const char* reason() const { return reason_; }
 
   bool operator==(const Vote& vote) const;
-  bool operator!=(const Vote& vote) const;
 
   // Returns true if the vote is valid. A valid vote must have a |reason_|.
   bool IsValid() const;
@@ -247,12 +245,6 @@
 }
 
 template <typename ContextType, typename VoteType, VoteType DefaultVote>
-bool Vote<ContextType, VoteType, DefaultVote>::operator!=(
-    const Vote<ContextType, VoteType, DefaultVote>& vote) const {
-  return !(*this == vote);
-}
-
-template <typename ContextType, typename VoteType, VoteType DefaultVote>
 bool Vote<ContextType, VoteType, DefaultVote>::IsValid() const {
   return reason_;
 }
@@ -409,7 +401,6 @@
   --voting_channels_outstanding_;
 }
 
-}  // namespace voting
-}  // namespace performance_manager
+}  // namespace performance_manager::voting
 
 #endif  // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_VOTING_VOTING_H_
diff --git a/components/performance_manager/render_process_user_data.cc b/components/performance_manager/render_process_user_data.cc
index b999894a..30252ad8 100644
--- a/components/performance_manager/render_process_user_data.cc
+++ b/components/performance_manager/render_process_user_data.cc
@@ -49,8 +49,8 @@
 }
 
 RenderProcessUserData::~RenderProcessUserData() {
-  PerformanceManagerImpl::DeleteNode(std::move(process_node_));
   host_->RemoveObserver(this);
+  PerformanceManagerImpl::DeleteNode(std::move(process_node_));
 
   if (destruction_observer_) {
     destruction_observer_->OnRenderProcessUserDataDestroying(host_);
diff --git a/components/policy/core/common/cloud/cloud_external_data_manager.cc b/components/policy/core/common/cloud/cloud_external_data_manager.cc
index 10aef2bb..716ca66 100644
--- a/components/policy/core/common/cloud/cloud_external_data_manager.cc
+++ b/components/policy/core/common/cloud/cloud_external_data_manager.cc
@@ -19,11 +19,6 @@
       hash(hash) {
 }
 
-bool CloudExternalDataManager::MetadataEntry::operator!=(
-    const MetadataEntry& other) const {
-  return url != other.url || hash != other.hash;
-}
-
 CloudExternalDataManager::MetadataKey::MetadataKey() = default;
 
 CloudExternalDataManager::MetadataKey::MetadataKey(const std::string& policy)
diff --git a/components/policy/core/common/cloud/cloud_external_data_manager.h b/components/policy/core/common/cloud/cloud_external_data_manager.h
index 3263657b..db42de90 100644
--- a/components/policy/core/common/cloud/cloud_external_data_manager.h
+++ b/components/policy/core/common/cloud/cloud_external_data_manager.h
@@ -31,7 +31,8 @@
     MetadataEntry();
     MetadataEntry(const std::string& url, const std::string& hash);
 
-    bool operator!=(const MetadataEntry& other) const;
+    friend bool operator==(const MetadataEntry&,
+                           const MetadataEntry&) = default;
 
     std::string url;
     std::string hash;
diff --git a/components/policy/core/common/cloud/dm_auth.cc b/components/policy/core/common/cloud/dm_auth.cc
index b013460e..36c202da 100644
--- a/components/policy/core/common/cloud/dm_auth.cc
+++ b/components/policy/core/common/cloud/dm_auth.cc
@@ -42,14 +42,6 @@
 DMAuth::DMAuth(const std::string& token, DMAuthTokenType token_type)
     : token_(token), token_type_(token_type) {}
 
-bool DMAuth::operator==(const DMAuth& other) const {
-  return token_ == other.token_ && token_type_ == other.token_type_;
-}
-
-bool DMAuth::operator!=(const DMAuth& other) const {
-  return !(*this == other);
-}
-
 DMAuth DMAuth::Clone() const {
   return DMAuth(token_, token_type_);
 }
diff --git a/components/policy/core/common/cloud/dm_auth.h b/components/policy/core/common/cloud/dm_auth.h
index 091f0ac..5acdf14d 100644
--- a/components/policy/core/common/cloud/dm_auth.h
+++ b/components/policy/core/common/cloud/dm_auth.h
@@ -51,8 +51,7 @@
   DMAuth(DMAuth&& other);
   DMAuth& operator=(DMAuth&& other);
 
-  bool operator==(const DMAuth& other) const;
-  bool operator!=(const DMAuth& other) const;
+  friend bool operator==(const DMAuth&, const DMAuth&) = default;
 
   // Creates a copy of DMAuth.
   DMAuth Clone() const;
diff --git a/components/policy/core/common/policy_namespace.cc b/components/policy/core/common/policy_namespace.cc
index 43d1b2e..57fe781 100644
--- a/components/policy/core/common/policy_namespace.cc
+++ b/components/policy/core/common/policy_namespace.cc
@@ -15,29 +15,11 @@
     : domain(domain),
       component_id(component_id) {}
 
-PolicyNamespace::PolicyNamespace(const PolicyNamespace& other)
-    : domain(other.domain),
-      component_id(other.component_id) {}
+PolicyNamespace::PolicyNamespace(const PolicyNamespace& other) = default;
+
+PolicyNamespace& PolicyNamespace::operator=(const PolicyNamespace& other) =
+    default;
 
 PolicyNamespace::~PolicyNamespace() = default;
 
-PolicyNamespace& PolicyNamespace::operator=(const PolicyNamespace& other) {
-  domain = other.domain;
-  component_id = other.component_id;
-  return *this;
-}
-
-bool PolicyNamespace::operator<(const PolicyNamespace& other) const {
-  return std::tie(domain, component_id) <
-         std::tie(other.domain, other.component_id);
-}
-
-bool PolicyNamespace::operator==(const PolicyNamespace& other) const {
-  return domain == other.domain && component_id == other.component_id;
-}
-
-bool PolicyNamespace::operator!=(const PolicyNamespace& other) const {
-  return !(*this == other);
-}
-
 }  // namespace policy
diff --git a/components/policy/core/common/policy_namespace.h b/components/policy/core/common/policy_namespace.h
index 9519facc..54e8371 100644
--- a/components/policy/core/common/policy_namespace.h
+++ b/components/policy/core/common/policy_namespace.h
@@ -40,12 +40,13 @@
   PolicyNamespace();
   PolicyNamespace(PolicyDomain domain, const std::string& component_id);
   PolicyNamespace(const PolicyNamespace& other);
+  PolicyNamespace& operator=(const PolicyNamespace& other);
   ~PolicyNamespace();
 
-  PolicyNamespace& operator=(const PolicyNamespace& other);
-  bool operator<(const PolicyNamespace& other) const;
-  bool operator==(const PolicyNamespace& other) const;
-  bool operator!=(const PolicyNamespace& other) const;
+  friend bool operator==(const PolicyNamespace&,
+                         const PolicyNamespace&) = default;
+  friend auto operator<=>(const PolicyNamespace&,
+                          const PolicyNamespace&) = default;
 
   PolicyDomain domain;
   std::string component_id;
diff --git a/components/reading_list/core/dual_reading_list_model.cc b/components/reading_list/core/dual_reading_list_model.cc
index 5a5d65c..65e36479 100644
--- a/components/reading_list/core/dual_reading_list_model.cc
+++ b/components/reading_list/core/dual_reading_list_model.cc
@@ -231,32 +231,7 @@
 void DualReadingListModel::MarkAllForUploadToSyncServerIfNeeded() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (!account_model_->IsTrackingSyncMetadata()) {
-    return;
-  }
-
-  base::AutoReset<bool> auto_reset_suppress_observer_notifications(
-      &suppress_observer_notifications_, true);
-
-  for (const GURL& url : local_or_syncable_model_->GetKeys()) {
-    scoped_refptr<ReadingListEntry> entry = GetEntryByURL(url)->Clone();
-    local_or_syncable_model_->RemoveEntryByURL(url, FROM_HERE);
-    // If the url already exists in the account model, remove the account entry
-    // first before adding the "merged" entry back to the account model.
-    // Note: This workaround is used than just using AddOrReplaceEntry() to
-    // avoid ReadingListModelBeganBatchUpdates() being triggered inside
-    // AddOrReplaceEntry(), which causes observers to be notified even though
-    // this particular function does not need to send any notifications at all
-    // (including ReadingListModelBeganBatchUpdates).
-    account_model_->RemoveEntryByURL(url, FROM_HERE);
-    account_model_->AddEntry(std::move(entry),
-                             reading_list::ADDED_VIA_CURRENT_APP);
-    // The entry state counters do not need to updated since no value was
-    // "effectively" removed from the dual reading list model.
-  }
-  // Ensure that the local model is empty since all the entries should have been
-  // moved to the account model, including the common entries.
-  CHECK_EQ(0u, local_or_syncable_model_->size());
+  MarkEntriesForUploadToSyncServerIfNeeded(local_or_syncable_model_->GetKeys());
 }
 
 const ReadingListEntry& DualReadingListModel::AddOrReplaceEntry(
@@ -800,6 +775,41 @@
   return local_or_syncable_model_->GetKeys();
 }
 
+void DualReadingListModel::MarkEntriesForUploadToSyncServerIfNeeded(
+    const base::flat_set<GURL>& urls) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!account_model_->IsTrackingSyncMetadata()) {
+    return;
+  }
+
+  base::AutoReset<bool> auto_reset_suppress_observer_notifications(
+      &suppress_observer_notifications_, true);
+
+  for (const GURL& url : urls) {
+    if (!local_or_syncable_model_->GetEntryByURL(url)) {
+      // Entry with url does not exist in the local model, so there is nothing
+      // to upload.
+      continue;
+    }
+    scoped_refptr<ReadingListEntry> entry = GetEntryByURL(url)->Clone();
+
+    local_or_syncable_model_->RemoveEntryByURL(url, FROM_HERE);
+    // If the url already exists in the account model, remove the account entry
+    // first before adding the "merged" entry back to the account model.
+    // Note: This workaround is used than just using AddOrReplaceEntry() to
+    // avoid ReadingListModelBeganBatchUpdates() being triggered inside
+    // AddOrReplaceEntry(), which causes observers to be notified even though
+    // this particular function does not need to send any notifications at all
+    // (including ReadingListModelBeganBatchUpdates).
+    account_model_->RemoveEntryByURL(url, FROM_HERE);
+    account_model_->AddEntry(std::move(entry),
+                             reading_list::ADDED_VIA_CURRENT_APP);
+    // The entry state counters do not need to be updated since no value was
+    // "effectively" removed from the dual reading list model.
+  }
+}
+
 ReadingListModel* DualReadingListModel::GetLocalOrSyncableModel() {
   return local_or_syncable_model_.get();
 }
diff --git a/components/reading_list/core/dual_reading_list_model.h b/components/reading_list/core/dual_reading_list_model.h
index e03998c..badd437 100644
--- a/components/reading_list/core/dual_reading_list_model.h
+++ b/components/reading_list/core/dual_reading_list_model.h
@@ -137,6 +137,12 @@
   // sync.
   base::flat_set<GURL> GetKeysThatNeedUploadToSyncServer() const;
 
+  // Uploads entries corresponding to `keys` that required upload to sync
+  // server. The upload itself may take long to complete (depending on network
+  // connectivity and many other factors).
+  void MarkEntriesForUploadToSyncServerIfNeeded(
+      const base::flat_set<GURL>& keys);
+
   StorageStateForTesting GetStorageStateForURLForTesting(const GURL& url);
 
   // Returns the model responsible for the local/syncable reading list.
diff --git a/components/reading_list/core/dual_reading_list_model_unittest.cc b/components/reading_list/core/dual_reading_list_model_unittest.cc
index 2a4d4df..32693455 100644
--- a/components/reading_list/core/dual_reading_list_model_unittest.cc
+++ b/components/reading_list/core/dual_reading_list_model_unittest.cc
@@ -811,6 +811,80 @@
             StorageStateForTesting::kExistsInAccountModelOnly);
 }
 
+TEST_F(DualReadingListModelTest, MarkEntriesForUploadToSyncServerIfNeeded) {
+  const GURL kLocalURL1("http://local_url1.com/");
+  const GURL kLocalURL2("http://local_url2.com/");
+  const GURL kCommonURL1("http://common_url1.com/");
+  const GURL kCommonURL2("http://common_url2.com/");
+  const GURL kAccountURL("http://account_url.com/");
+
+  ASSERT_TRUE(ResetStorageAndMimicSignedInSyncDisabled(
+      /*initial_local_entries_builders=*/{TestEntryBuilder(kLocalURL1,
+                                                           clock_.Now())
+                                              .SetTitle("local_entry_title1"),
+                                          TestEntryBuilder(kLocalURL2,
+                                                           clock_.Now())
+                                              .SetTitle("local_entry_title2"),
+                                          TestEntryBuilder(kCommonURL1,
+                                                           clock_.Now())
+                                              .SetTitle("common_entry_title1"),
+                                          TestEntryBuilder(kCommonURL2,
+                                                           clock_.Now())
+                                              .SetTitle("common_entry_title2")},
+      /*initial_account_entries_builders=*/{
+          TestEntryBuilder(kAccountURL, clock_.Now())
+              .SetTitle("account_entry_title"),
+          TestEntryBuilder(kCommonURL1, clock_.Now())
+              .SetTitle("common_entry_title1"),
+          TestEntryBuilder(kCommonURL2, clock_.Now())
+              .SetTitle("common_entry_title2")}));
+
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalURL1),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalURL2),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonURL1),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonURL2),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kAccountURL),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+
+  EXPECT_CALL(observer_, ReadingListWillRemoveEntry).Times(0);
+  EXPECT_CALL(observer_, ReadingListWillAddEntry).Times(0);
+  EXPECT_CALL(observer_, ReadingListDidApplyChanges).Times(0);
+
+  dual_model_->MarkEntriesForUploadToSyncServerIfNeeded(
+      {kLocalURL1, kCommonURL1});
+
+  EXPECT_THAT(dual_model_->GetEntryByURL(kLocalURL1),
+              MatchesEntry(kLocalURL1, "local_entry_title1"));
+  EXPECT_THAT(dual_model_->GetEntryByURL(kLocalURL2),
+              MatchesEntry(kLocalURL2, "local_entry_title2"));
+  EXPECT_THAT(dual_model_->GetEntryByURL(kCommonURL1),
+              MatchesEntry(kCommonURL1, "common_entry_title1"));
+  EXPECT_THAT(dual_model_->GetEntryByURL(kCommonURL2),
+              MatchesEntry(kCommonURL2, "common_entry_title2"));
+  EXPECT_THAT(dual_model_->GetEntryByURL(kAccountURL),
+              MatchesEntry(kAccountURL, "account_entry_title"));
+
+  // Although the entry was originally local only, it has been effectively moved
+  // when the entry got uploaded.
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalURL1),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonURL1),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+
+  // The non-selected entry did not get uploaded.
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalURL2),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonURL2),
+            StorageStateForTesting::kExistsInBothModels);
+
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kAccountURL),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+}
+
 TEST_F(DualReadingListModelTest, RemoveNonExistingEntryByUrl) {
   ASSERT_TRUE(ResetStorageAndTriggerLoadCompletion());
 
@@ -3796,6 +3870,59 @@
                                             /*unread_size=*/3ul));
 }
 
+TEST_F(DualReadingListModelTest,
+       ShouldMaintainCountsWhenMarkEntriesForUploadToSyncServerIfNeeded) {
+  const GURL kLocalUrl1("http://local_url1.com/");
+  const GURL kLocalUrl2("http://local_url2.com/");
+  const GURL kCommonUrl1("http://common_ur1.com/");
+  const GURL kCommonUrl2("http://common_url2.com/");
+  const GURL kAccountUrl("http://account_url.com/");
+
+  ASSERT_TRUE(ResetStorageAndMimicSignedInSyncDisabled(
+      /*initial_local_or_syncable_entries_builders=*/
+      {TestEntryBuilder(kLocalUrl1, clock_.Now()),
+       TestEntryBuilder(kLocalUrl2, clock_.Now()),
+       TestEntryBuilder(kCommonUrl1, clock_.Now()),
+       TestEntryBuilder(kCommonUrl2, clock_.Now())},
+      /*initial_account_entries_builders=*/{
+          TestEntryBuilder(kCommonUrl1, clock_.Now()),
+          TestEntryBuilder(kCommonUrl2, clock_.Now()),
+          TestEntryBuilder(kAccountUrl, clock_.Now())}));
+  ASSERT_TRUE(dual_model_->loaded());
+
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalUrl1),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalUrl2),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonUrl1),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonUrl2),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+
+  ASSERT_THAT(dual_model_, HasCountersEqual(/*size=*/5ul, /*unseen_size=*/5ul,
+                                            /*unread_size=*/5ul));
+
+  dual_model_->MarkEntriesForUploadToSyncServerIfNeeded(
+      {kLocalUrl1, kCommonUrl1});
+
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalUrl1),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonUrl1),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalUrl2),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonUrl2),
+            StorageStateForTesting::kExistsInBothModels);
+
+  EXPECT_THAT(dual_model_, HasCountersEqual(/*size=*/5ul, /*unseen_size=*/5ul,
+                                            /*unread_size=*/5ul));
+}
+
 TEST_F(
     DualReadingListModelTest,
     ShouldMaintainSeenAndReadStatusWhenMarkAllForUploadToSyncServerIfNeeded) {
@@ -3886,6 +4013,100 @@
                                             /*unread_size=*/6ul));
 }
 
+TEST_F(
+    DualReadingListModelTest,
+    ShouldMaintainSeenAndReadStatusWhenMarkEntriesForUploadToSyncServerIfNeeded) {
+  const GURL kUnseenLocalUrl("http://unseen_local_url.com/");
+  const GURL kUnreadLocalUrl("http://unread_local_url.com/");
+  const GURL kReadLocalUrl("http://read_local_url.com/");
+  const GURL kUnseenAccountUrl("http://unseen_account_url.com/");
+  const GURL kUnreadAccountUrl("http://unread_account_url.com/");
+  const GURL kReadAccountUrl("http://read_account_url.com/");
+  // Seen in account model but unseen in local model.
+  const GURL kUnreadCommonUrl1("http://unread_common_url_1.com/");
+  // Seen in local model but unseen in account model.
+  const GURL kUnreadCommonUrl2("http://unread_common_url_2.com/");
+  // Read in account model but unread in local model.
+  const GURL kReadCommonUrl1("http://read_common_url_1.com/");
+  // Read in local model but unread in account model.
+  const GURL kReadCommonUrl2("http://read_common_url_2.com/");
+
+  ASSERT_TRUE(ResetStorageAndMimicSignedInSyncDisabled(
+      /*initial_local_or_syncable_entries_builders=*/
+      {TestEntryBuilder(kUnseenLocalUrl, clock_.Now()),
+       TestEntryBuilder(kUnreadLocalUrl, clock_.Now()).SetRead(false),
+       TestEntryBuilder(kReadLocalUrl, clock_.Now()).SetRead(),
+       TestEntryBuilder(kUnreadCommonUrl1, clock_.Now()),
+       TestEntryBuilder(kUnreadCommonUrl2, clock_.Now()).SetRead(false),
+       TestEntryBuilder(kReadCommonUrl1, clock_.Now()),
+       TestEntryBuilder(kReadCommonUrl2, clock_.Now())
+           .SetRead(clock_.Now() + base::Seconds(1))},
+      /*initial_account_entries_builders=*/{
+          TestEntryBuilder(kUnseenAccountUrl, clock_.Now()),
+          TestEntryBuilder(kUnreadAccountUrl, clock_.Now()).SetRead(false),
+          TestEntryBuilder(kReadAccountUrl, clock_.Now()).SetRead(),
+          TestEntryBuilder(kUnreadCommonUrl1, clock_.Now()).SetRead(false),
+          TestEntryBuilder(kUnreadCommonUrl2, clock_.Now()),
+          TestEntryBuilder(kReadCommonUrl1, clock_.Now())
+              .SetRead(clock_.Now() + base::Seconds(1)),
+          TestEntryBuilder(kReadCommonUrl2, clock_.Now())}));
+  ASSERT_TRUE(dual_model_->loaded());
+
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnseenLocalUrl),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadLocalUrl),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadLocalUrl),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnseenAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadCommonUrl1),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadCommonUrl2),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadCommonUrl1),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadCommonUrl2),
+            StorageStateForTesting::kExistsInBothModels);
+
+  ASSERT_THAT(dual_model_, HasCountersEqual(/*size=*/10ul, /*unseen_size=*/2ul,
+                                            /*unread_size=*/6ul));
+
+  dual_model_->MarkEntriesForUploadToSyncServerIfNeeded(
+      {kUnseenLocalUrl, kReadLocalUrl, kUnreadCommonUrl1, kReadCommonUrl1});
+
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnseenLocalUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadLocalUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadCommonUrl1),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadCommonUrl1),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadLocalUrl),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnseenAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadAccountUrl),
+            StorageStateForTesting::kExistsInAccountModelOnly);
+
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadCommonUrl2),
+            StorageStateForTesting::kExistsInBothModels);
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadCommonUrl2),
+            StorageStateForTesting::kExistsInBothModels);
+
+  EXPECT_THAT(dual_model_, HasCountersEqual(/*size=*/10ul, /*unseen_size=*/2ul,
+                                            /*unread_size=*/6ul));
+}
+
 TEST_F(DualReadingListModelTest,
        ShouldClearLocalModelUponMarkAllForUploadToSyncServerIfNeeded) {
   const GURL kLocalURL("http://local_url.com/");
diff --git a/components/reporting/util/status.cc b/components/reporting/util/status.cc
index 88e6a47..d5c2dc79 100644
--- a/components/reporting/util/status.cc
+++ b/components/reporting/util/status.cc
@@ -76,10 +76,6 @@
       error_message_{error_code != error::OK ? std::move(error_message)
                                              : std::string()} {}
 
-bool Status::operator==(const Status& x) const {
-  return error_code_ == x.error_code_ && error_message_ == x.error_message_;
-}
-
 std::string Status::ToString() const {
   if (error_code_ == error::OK) {
     return "OK";
diff --git a/components/reporting/util/status.h b/components/reporting/util/status.h
index 1f694f65..89b17216 100644
--- a/components/reporting/util/status.h
+++ b/components/reporting/util/status.h
@@ -79,8 +79,7 @@
   const std::string& error_message() const { return error_message_; }
   const std::string& message() const { return error_message_; }
 
-  bool operator==(const Status& x) const;
-  bool operator!=(const Status& x) const { return !operator==(x); }
+  friend bool operator==(const Status&, const Status&) = default;
 
   // Return a combination of the error code name and message.
   std::string ToString() const;
diff --git a/components/resources/search_engine_choice_scaled_resources.grdp b/components/resources/search_engine_choice_scaled_resources.grdp
index 92d853bd..656fbe83 100644
--- a/components/resources/search_engine_choice_scaled_resources.grdp
+++ b/components/resources/search_engine_choice_scaled_resources.grdp
@@ -4,6 +4,7 @@
 <grit-part>
   <if expr="_google_chrome">
     <structure type="chrome_scaled_image" name="IDR_GOOGLE_COM_PNG" file="google_chrome/google_search_logo.png" />
+    <structure type="chrome_scaled_image" name="IDR_SEARCH_ENGINE_GOOGLE_IMAGE" file="google_chrome/google_search_logo.png" />
   </if>
   <structure type="chrome_scaled_image" name="IDR_AR_YAHOO_COM_PNG" file="search_engine_choice/yahoo_com.png" />
   <structure type="chrome_scaled_image" name="IDR_AT_YAHOO_COM_PNG" file="search_engine_choice/yahoo_com.png" />
diff --git a/components/safe_browsing/core/browser/db/prefix_iterator.h b/components/safe_browsing/core/browser/db/prefix_iterator.h
index 1f19724..b8213bb 100644
--- a/components/safe_browsing/core/browser/db/prefix_iterator.h
+++ b/components/safe_browsing/core/browser/db/prefix_iterator.h
@@ -69,9 +69,6 @@
   bool operator==(const PrefixIterator& rhs) const {
     return index_ == rhs.index_;
   }
-  bool operator!=(const PrefixIterator& rhs) const {
-    return index_ != rhs.index_;
-  }
   bool operator>(const PrefixIterator& rhs) const {
     return index_ > rhs.index_;
   }
diff --git a/components/safe_browsing/core/browser/db/util.cc b/components/safe_browsing/core/browser/db/util.cc
index 6d05eb9..c8f50bf3 100644
--- a/components/safe_browsing/core/browser/db/util.cc
+++ b/components/safe_browsing/core/browser/db/util.cc
@@ -22,16 +22,6 @@
 
 ThreatMetadata::~ThreatMetadata() = default;
 
-bool ThreatMetadata::operator==(const ThreatMetadata& other) const {
-  return threat_pattern_type == other.threat_pattern_type &&
-         api_permissions == other.api_permissions &&
-         subresource_filter_match == other.subresource_filter_match;
-}
-
-bool ThreatMetadata::operator!=(const ThreatMetadata& other) const {
-  return !operator==(other);
-}
-
 std::unique_ptr<base::trace_event::TracedValue> ThreatMetadata::ToTracedValue()
     const {
   auto value = std::make_unique<base::trace_event::TracedValue>();
diff --git a/components/safe_browsing/core/browser/db/util.h b/components/safe_browsing/core/browser/db/util.h
index 8a8fcaa..5584f21 100644
--- a/components/safe_browsing/core/browser/db/util.h
+++ b/components/safe_browsing/core/browser/db/util.h
@@ -43,9 +43,7 @@
 // Metadata that was returned by a GetFullHash call. This is the parsed version
 // of the PB (from Pver3, or Pver4 local) or JSON (from Pver4 via GMSCore).
 // Some fields are only applicable to certain lists.
-//
-// When adding elements to this struct, make sure you update operator== and
-// ToTracedValue.
+// When adding elements to this struct, make sure you update ToTracedValue.
 struct ThreatMetadata {
   ThreatMetadata();
   ThreatMetadata(const ThreatMetadata& other);
@@ -54,8 +52,8 @@
   ThreatMetadata& operator=(ThreatMetadata&& other);
   ~ThreatMetadata();
 
-  bool operator==(const ThreatMetadata& other) const;
-  bool operator!=(const ThreatMetadata& other) const;
+  friend bool operator==(const ThreatMetadata&,
+                         const ThreatMetadata&) = default;
 
   // Returns the metadata in a format tracing can support.
   std::unique_ptr<base::trace_event::TracedValue> ToTracedValue() const;
diff --git a/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.cc b/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.cc
index 8dc0f11..ba8877b 100644
--- a/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.cc
+++ b/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.cc
@@ -211,15 +211,6 @@
 
 FullHashInfo::~FullHashInfo() = default;
 
-bool FullHashInfo::operator==(const FullHashInfo& other) const {
-  return full_hash == other.full_hash && list_id == other.list_id &&
-         positive_expiry == other.positive_expiry && metadata == other.metadata;
-}
-
-bool FullHashInfo::operator!=(const FullHashInfo& other) const {
-  return !operator==(other);
-}
-
 // V4GetHashProtocolManager implementation --------------------------------
 
 // static
diff --git a/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.h b/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.h
index b7b0b42..34034f43 100644
--- a/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.h
+++ b/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.h
@@ -65,8 +65,7 @@
   FullHashInfo(const FullHashInfo& other);
   ~FullHashInfo();
 
-  bool operator==(const FullHashInfo& other) const;
-  bool operator!=(const FullHashInfo& other) const;
+  friend bool operator==(const FullHashInfo&, const FullHashInfo&) = default;
 
  private:
   FullHashInfo();
diff --git a/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc b/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc
index 0d12005..1f5e13f 100644
--- a/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc
+++ b/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc
@@ -191,14 +191,6 @@
 
 StoreAndHashPrefix::~StoreAndHashPrefix() = default;
 
-bool StoreAndHashPrefix::operator==(const StoreAndHashPrefix& other) const {
-  return list_id == other.list_id && hash_prefix == other.hash_prefix;
-}
-
-bool StoreAndHashPrefix::operator!=(const StoreAndHashPrefix& other) const {
-  return !operator==(other);
-}
-
 size_t StoreAndHashPrefix::hash() const {
   std::size_t first = list_id.hash();
   std::size_t second = std::hash<std::string>()(hash_prefix);
@@ -223,16 +215,6 @@
   return true;
 }
 
-bool ListIdentifier::operator==(const ListIdentifier& other) const {
-  return platform_type_ == other.platform_type_ &&
-         threat_entry_type_ == other.threat_entry_type_ &&
-         threat_type_ == other.threat_type_;
-}
-
-bool ListIdentifier::operator!=(const ListIdentifier& other) const {
-  return !operator==(other);
-}
-
 size_t ListIdentifier::hash() const {
   std::size_t first = std::hash<unsigned int>()(platform_type_);
   std::size_t second = std::hash<unsigned int>()(threat_entry_type_);
diff --git a/components/safe_browsing/core/browser/db/v4_protocol_manager_util.h b/components/safe_browsing/core/browser/db/v4_protocol_manager_util.h
index 25ef4191..b13314bf 100644
--- a/components/safe_browsing/core/browser/db/v4_protocol_manager_util.h
+++ b/components/safe_browsing/core/browser/db/v4_protocol_manager_util.h
@@ -227,8 +227,8 @@
                  ThreatType threat_type);
   explicit ListIdentifier(const ListUpdateResponse&);
 
-  bool operator==(const ListIdentifier& other) const;
-  bool operator!=(const ListIdentifier& other) const;
+  friend bool operator==(const ListIdentifier&,
+                         const ListIdentifier&) = default;
   size_t hash() const;
 
   PlatformType platform_type() const { return platform_type_; }
@@ -277,8 +277,8 @@
   StoreAndHashPrefix(ListIdentifier list_id, const HashPrefixStr& hash_prefix);
   ~StoreAndHashPrefix();
 
-  bool operator==(const StoreAndHashPrefix& other) const;
-  bool operator!=(const StoreAndHashPrefix& other) const;
+  friend bool operator==(const StoreAndHashPrefix&,
+                         const StoreAndHashPrefix&) = default;
   size_t hash() const;
 
  private:
diff --git a/components/search/start_suggest_service.h b/components/search/start_suggest_service.h
index b363c0f..f01f2294 100644
--- a/components/search/start_suggest_service.h
+++ b/components/search/start_suggest_service.h
@@ -32,12 +32,8 @@
 
 class QuerySuggestion {
  public:
-  bool operator==(const QuerySuggestion& other) const {
-    return query == other.query && destination_url == other.destination_url;
-  }
-  bool operator!=(const QuerySuggestion& other) const {
-    return !(this == &other);
-  }
+  friend bool operator==(const QuerySuggestion&,
+                         const QuerySuggestion&) = default;
 
   // Query suggestion.
   std::u16string query;
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn
index 005e0e6..06d2976b 100644
--- a/components/search_engines/BUILD.gn
+++ b/components/search_engines/BUILD.gn
@@ -132,6 +132,7 @@
     deps += [
       ":generate_search_engine_icons",
       "//components/resources:components_scaled_resources_grit",
+      "//third_party/search_engines_data:search_engines_scaled_resources",
       "//ui/resources",
     ]
   }
diff --git a/components/search_engines/enterprise/enterprise_search_manager.cc b/components/search_engines/enterprise/enterprise_search_manager.cc
index 90d63ad1..ff742b3 100644
--- a/components/search_engines/enterprise/enterprise_search_manager.cc
+++ b/components/search_engines/enterprise/enterprise_search_manager.cc
@@ -77,22 +77,19 @@
 }
 
 bool EnterpriseSearchManager::GetRequireShortcutValue() const {
-  // Use the `require_shortcut` preference value if set by policy.
-  const PrefService::Preference* pref = pref_service_->FindPreference(
-      kEnterpriseSearchAggregatorSettingsRequireShortcutPrefName);
-  if (pref && pref->IsManaged()) {
-    return pref->GetValue()->GetBool();
+  // Prefer mock `require_shortcut` over `require_shortcut` from pref.
+  // TODO(crbug.com/402175538): Remove the ability to override pref engines via
+  // feature.
+  if (!omnibox_feature_configs::SearchAggregatorProvider::Get()
+           .AreMockEnginesValid()) {
+    // Use the `require_shortcut` preference value if set by policy.
+    const PrefService::Preference* pref = pref_service_->FindPreference(
+        kEnterpriseSearchAggregatorSettingsRequireShortcutPrefName);
+    return pref && pref->GetValue()->GetBool();
   }
 
-  // Fallback to mock settings if policy is not set and mock engine is valid.
-  if (omnibox_feature_configs::SearchAggregatorProvider::Get()
-          .AreMockEnginesValid()) {
-    return omnibox_feature_configs::SearchAggregatorProvider::Get()
-        .require_shortcut;
-  }
-
-  // Use the pref's default value if neither policy nor mock settings apply.
-  return pref && pref->GetValue()->GetBool();
+  return omnibox_feature_configs::SearchAggregatorProvider::Get()
+      .require_shortcut;
 }
 
 void EnterpriseSearchManager::OnPrefChanged() {
diff --git a/components/search_engines/enterprise/enterprise_search_manager_unittest.cc b/components/search_engines/enterprise/enterprise_search_manager_unittest.cc
index 9745430e..ee0c3f1 100644
--- a/components/search_engines/enterprise/enterprise_search_manager_unittest.cc
+++ b/components/search_engines/enterprise/enterprise_search_manager_unittest.cc
@@ -453,7 +453,7 @@
     {
         .policy_require_shortcut = false,
         .mock_require_shortcut = true,
-        .expected_result = false,
+        .expected_result = true,
     },
     {
         .policy_require_shortcut = true,
@@ -463,7 +463,7 @@
     {
         .policy_require_shortcut = true,
         .mock_require_shortcut = false,
-        .expected_result = true,
+        .expected_result = false,
     },
     {
         .policy_require_shortcut = true,
diff --git a/components/search_engines/template_url_data.cc b/components/search_engines/template_url_data.cc
index b44f36f..2c76f73 100644
--- a/components/search_engines/template_url_data.cc
+++ b/components/search_engines/template_url_data.cc
@@ -11,6 +11,7 @@
 #include "base/containers/flat_map.h"
 #include "base/i18n/case_conversion.h"
 #include "base/pickle.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -78,6 +79,7 @@
     std::string_view contextual_search_url,
     std::string_view logo_url,
     std::string_view doodle_url,
+    std::string_view base_builtin_resource_id,
     std::string_view search_url_post_params,
     std::string_view suggest_url_post_params,
     std::string_view image_url_post_params,
@@ -100,6 +102,7 @@
       contextual_search_url(contextual_search_url),
       logo_url(logo_url),
       doodle_url(doodle_url),
+      base_builtin_resource_id(base_builtin_resource_id),
       search_url_post_params(search_url_post_params),
       suggestions_url_post_params(suggest_url_post_params),
       image_url_post_params(image_url_post_params),
@@ -182,6 +185,13 @@
   return result;
 }
 
+std::string TemplateURLData::GetBuiltinImageResourceId() const {
+  if (base_builtin_resource_id.empty()) {
+    return "IDR_DEFAULT_FAVICON";
+  }
+  return base::StrCat({base_builtin_resource_id, "_IMAGE"});
+}
+
 void TemplateURLData::GenerateSyncGUID() {
   sync_guid = GenerateGUID(prepopulate_id, starter_pack_id);
 }
diff --git a/components/search_engines/template_url_data.h b/components/search_engines/template_url_data.h
index ada5185..01dbf0c9 100644
--- a/components/search_engines/template_url_data.h
+++ b/components/search_engines/template_url_data.h
@@ -50,6 +50,7 @@
                   std::string_view contextual_search_url,
                   std::string_view logo_url,
                   std::string_view doodle_url,
+                  std::string_view base_builtin_resource_id,
                   std::string_view search_url_post_params,
                   std::string_view suggest_url_post_params,
                   std::string_view image_url_post_params,
@@ -85,6 +86,9 @@
   // Generate the deterministic hash of data within this TemplateURL.
   std::vector<uint8_t> GenerateHash() const;
 
+  // Retrieve builtin image resource ID for this engine.
+  std::string GetBuiltinImageResourceId() const;
+
   // Recomputes |sync_guid| using the same logic as in the constructor. This
   // means a random GUID is generated, except for built-in search engines,
   // which generate GUIDs deterministically based on |prepopulate_id| or
@@ -123,6 +127,9 @@
   // Optional URL for the Doodle.
   GURL doodle_url;
 
+  // Builtin base resource ID used to construct derived resource IDs.
+  std::string_view base_builtin_resource_id;
+
   // The following post_params are comma-separated lists used to specify the
   // post parameters for the corresponding URL.
   std::string search_url_post_params;
diff --git a/components/search_engines/template_url_data_unittest.cc b/components/search_engines/template_url_data_unittest.cc
index bbc0a72..53f035a 100644
--- a/components/search_engines/template_url_data_unittest.cc
+++ b/components/search_engines/template_url_data_unittest.cc
@@ -15,28 +15,28 @@
 #include "third_party/search_engines_data/resources/definitions/prepopulated_engines.h"
 
 namespace {
-TemplateURLData BuildDataForRegulatoryExtensions(
+TemplateURLData BuildTestTemplateURLData(
+    int id,
     base::span<TemplateURLData::RegulatoryExtension> extensions) {
   return TemplateURLData(
-      u"shortname", u"keyword", "https://cs.chromium.org", std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), {}, std::string_view(),
-      std::string_view(), std::u16string_view(), base::Value::List(), false,
-      false, 0, extensions);
+      /*name=*/u"shortname", /*keyword=*/u"keyword",
+      /*search_url=*/"https://cs.chromium.org",
+      /*suggest_url=*/{}, /*image_url=*/{}, /*image_translate_url=*/{},
+      /*new_tab_url=*/{}, /*contextual_search_url=*/{}, /*logo_url=*/{},
+      /*doodle_url=*/{}, /*base_builtin_resource_id=*/{},
+      /*search_url_post_params=*/{},
+      /*suggest_url_post_params=*/{}, /*image_url_post_params=*/{},
+      /*image_translate_source_language_param_key=*/{},
+      /*image_translate_target_language_param_key=*/{},
+      /*search_intent_params=*/{}, /*favicon_url=*/{}, /*encoding=*/{},
+      /*image_search_branding_label=*/{}, /*alternate_urls_list=*/{},
+      /*preconnect_to_search_url=*/false, /*prefetch_likely_navigations=*/false,
+      /*id=*/id, /*regulatory_extensions=*/extensions);
 }
 }  // namespace
 
 TEST(TemplateURLDataTest, Trim) {
-  TemplateURLData data(
-      u" shortname ", u" keyword ", "https://cs.chromium.org",
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(), {},
-      std::string_view(), std::string_view(), std::u16string_view(),
-      base::Value::List(), false, false, 0, {});
+  TemplateURLData data(BuildTestTemplateURLData(0, {}));
 
   EXPECT_EQ(u"shortname", data.short_name());
   EXPECT_EQ(u"keyword", data.keyword());
@@ -62,7 +62,7 @@
        .suggest_params = "android_eea_suggest"},
   }};
 
-  auto data = BuildDataForRegulatoryExtensions(extensions);
+  auto data = BuildTestTemplateURLData(0, extensions);
   EXPECT_EQ("default_search",
             data.regulatory_extensions.at(RegulatoryExtensionType::kDefault)
                 ->search_params);
@@ -84,8 +84,7 @@
       {RegulatoryExtensionType::kDefault, "android_eea_data"},
   }};
 
-  EXPECT_DEATH_IF_SUPPORTED(BuildDataForRegulatoryExtensions(duplicate_data),
-                            "");
+  EXPECT_DEATH_IF_SUPPORTED(BuildTestTemplateURLData(0, duplicate_data), "");
 }
 #endif
 
@@ -95,26 +94,12 @@
   ASSERT_EQ(data1.prepopulate_id, 0);
   EXPECT_EQ(data1.is_active, TemplateURLData::ActiveStatus::kUnspecified);
 
-  TemplateURLData data2(
-      u" shortname ", u" keyword ", "https://cs.chromium.org",
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(), {},
-      std::string_view(), std::string_view(), std::u16string_view(),
-      base::Value::List(), false, false, /*prepopulate_id=*/0, {});
+  TemplateURLData data2(BuildTestTemplateURLData(0, {}));
   ASSERT_EQ(data2.prepopulate_id, 0);
   EXPECT_EQ(data2.is_active, TemplateURLData::ActiveStatus::kUnspecified);
 
   // Prepopulated engines also have active status as kUnspecified by default.
-  TemplateURLData data3(
-      u" shortname ", u" keyword ", "https://cs.chromium.org",
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), std::string_view(), {},
-      std::string_view(), std::string_view(), std::u16string_view(),
-      base::Value::List(), false, false, /*prepopulate_id=*/1, {});
+  TemplateURLData data3(BuildTestTemplateURLData(1, {}));
   ASSERT_EQ(data3.prepopulate_id, 1);
   EXPECT_EQ(data3.is_active, TemplateURLData::ActiveStatus::kUnspecified);
 }
diff --git a/components/search_engines/template_url_data_util.cc b/components/search_engines/template_url_data_util.cc
index 3a737ad3..38da87e1 100644
--- a/components/search_engines/template_url_data_util.cc
+++ b/components/search_engines/template_url_data_util.cc
@@ -336,6 +336,7 @@
       ToStringView(engine.new_tab_url),
       ToStringView(engine.contextual_search_url), ToStringView(engine.logo_url),
       ToStringView(engine.doodle_url),
+      ToStringView(engine.base_builtin_resource_id),
       ToStringView(engine.search_url_post_params),
       ToStringView(engine.suggest_url_post_params),
       ToStringView(engine.image_url_post_params),
@@ -398,6 +399,7 @@
     std::string contextual_search_url;
     std::string logo_url;
     std::string doodle_url;
+    std::string base_builtin_resource_id;
     std::string search_url_post_params;
     std::string suggest_url_post_params;
     std::string image_url_post_params;
@@ -436,6 +438,10 @@
     if (string_value) {
       doodle_url = *string_value;
     }
+    string_value = engine_dict.FindString("base_builtin_resource_id");
+    if (string_value) {
+      base_builtin_resource_id = *string_value;
+    }
     string_value = engine_dict.FindString("search_url_post_params");
     if (string_value) {
       search_url_post_params = *string_value;
@@ -484,7 +490,8 @@
     return std::make_unique<TemplateURLData>(
         name, keyword, search_url, suggest_url, image_url, image_translate_url,
         new_tab_url, contextual_search_url, logo_url, doodle_url,
-        search_url_post_params, suggest_url_post_params, image_url_post_params,
+        base_builtin_resource_id, search_url_post_params,
+        suggest_url_post_params, image_url_post_params,
         image_translate_source_language_param_key,
         image_translate_target_language_param_key,
         std::move(search_intent_params), favicon_url, encoding,
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc
index ba74880d..2f0660b 100644
--- a/components/search_engines/template_url_service.cc
+++ b/components/search_engines/template_url_service.cc
@@ -2101,8 +2101,9 @@
     // updating turl with a new TemplateURL containing only the local data
     // instead of just dropping the account data to ensure all the mappings are
     // correctly updated. Else, remove turl.
-    base::UmaHistogramBoolean("Sync.SearchEngine.HasLocalDataDuringStopSyncing",
-                              turl->GetLocalData().has_value());
+    base::UmaHistogramBoolean(
+        "Sync.SearchEngine.HasLocalDataDuringStopSyncing2",
+        turl->GetLocalData().has_value());
     if (turl->GetLocalData()) {
       Update(turl, TemplateURL(*turl->GetLocalData()));
       ++i;
@@ -2121,6 +2122,15 @@
   }
 }
 
+void TemplateURLService::OnBrowserShutdown(syncer::DataType type) {
+  CHECK_EQ(type, syncer::SEARCH_ENGINES);
+  models_associated_ = false;
+  sync_processor_.reset();
+  // Skip removing the account search engines on browser shutdown, as this is
+  // not really needed, plus the TemplateURLs will all be regenerated upon
+  // browser startup.
+}
+
 void TemplateURLService::ProcessTemplateURLChange(
     const base::Location& from_here,
     TemplateURL* turl,
diff --git a/components/search_engines/template_url_service.h b/components/search_engines/template_url_service.h
index fd3d4fe..0222422 100644
--- a/components/search_engines/template_url_service.h
+++ b/components/search_engines/template_url_service.h
@@ -537,6 +537,7 @@
       const syncer::SyncDataList& initial_sync_data,
       std::unique_ptr<syncer::SyncChangeProcessor> sync_processor) override;
   void StopSyncing(syncer::DataType type) override;
+  void OnBrowserShutdown(syncer::DataType type) override;
   base::WeakPtr<SyncableService> AsWeakPtr() override;
 
   // Processes a TemplateURL change for Sync. `turl` is the TemplateURL
diff --git a/components/search_engines/template_url_service_util_unittest.cc b/components/search_engines/template_url_service_util_unittest.cc
index 2574bb9..f2b7967 100644
--- a/components/search_engines/template_url_service_util_unittest.cc
+++ b/components/search_engines/template_url_service_util_unittest.cc
@@ -45,8 +45,9 @@
       u"Search engine name", base::ASCIIToUTF16(keyword), "https://search.url",
       "" /* suggest_url */, "" /* image_url */, "" /* image_translate_url */,
       "" /* new_tab_url */, "" /* contextual_search_url */, "" /* logo_url */,
-      "" /* doodle_url */, "" /* search_url_post_params */,
-      "" /* suggest_url_post_params */, "" /* image_url_post_params */,
+      "" /* doodle_url */, "" /* base_builtin_resource_id */,
+      "" /* search_url_post_params */, "" /* suggest_url_post_params */,
+      "" /* image_url_post_params */,
       "" /* image_translate_source_language_param_key */,
       "" /* image_translate_target_language_param_key */,
       std::vector<std::string>() /* search_intent_params */,
diff --git a/components/security_interstitials/core/https_only_mode_ui_util.h b/components/security_interstitials/core/https_only_mode_ui_util.h
index 98728bc..94f370d 100644
--- a/components/security_interstitials/core/https_only_mode_ui_util.h
+++ b/components/security_interstitials/core/https_only_mode_ui_util.h
@@ -14,6 +14,9 @@
 }
 
 // Populates |load_time_data| for interstitial HTML.
+//
+// TODO(http://crbug.com/415341199): Remove `august2024_refresh_enabled`
+// parameter once iOS is switched over to the new UI.
 void PopulateHttpsOnlyModeStringsForBlockingPage(
     base::Value::Dict& load_time_data,
     const GURL& url,
diff --git a/components/sessions/core/session_id.h b/components/sessions/core/session_id.h
index 2c882e4..b429067 100644
--- a/components/sessions/core/session_id.h
+++ b/components/sessions/core/session_id.h
@@ -44,24 +44,15 @@
     inline std::size_t operator()(SessionID id) const { return id.id(); }
   };
 
+  friend bool operator==(const SessionID&, const SessionID&) = default;
+  friend auto operator<=>(const SessionID&, const SessionID&) = default;
+
  private:
   explicit constexpr SessionID(id_type id) : id_(id) {}
 
   id_type id_;
 };
 
-inline bool operator==(SessionID lhs, SessionID rhs) {
-  return lhs.id() == rhs.id();
-}
-
-inline bool operator!=(SessionID lhs, SessionID rhs) {
-  return lhs.id() != rhs.id();
-}
-
-inline bool operator<(SessionID lhs, SessionID rhs) {
-  return lhs.id() < rhs.id();
-}
-
 // For use in gtest-based unit tests.
 SESSIONS_EXPORT std::ostream& operator<<(std::ostream& out, SessionID id);
 
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/TestAccounts.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/TestAccounts.java
index c020efb..9df2abb 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/TestAccounts.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/TestAccounts.java
@@ -33,7 +33,10 @@
                     .accountImage(createAvatar())
                     .build();
 
-    /* Use ACCOUNT2 when signing in or adding a default adult user to the device as a secondary user.*/
+    /*
+     * Use ACCOUNT2 when signing in or adding a default adult user to the device as a secondary
+     * user.
+     */
     public static final AccountInfo ACCOUNT2 =
             new AccountInfo.Builder(
                             "test2@gmail.com", FakeAccountManagerFacade.toGaiaId("test2@gmail.com"))
@@ -42,7 +45,7 @@
                     .accountImage(createAvatar())
                     .build();
 
-    /* Use CHILD_ACCOUNT when you need a supervised user signed in */
+    /* Use CHILD_ACCOUNT when you need a supervised user signed in. */
     public static final AccountInfo CHILD_ACCOUNT =
             new AccountInfo.Builder(
                             FakeAccountManagerFacade.generateChildEmail(ACCOUNT1.getEmail()),
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc
index 33c2e087..c52ce73 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -342,10 +342,6 @@
   return tie(*this) == tie(rhs);
 }
 
-bool Configuration::operator!=(const Configuration& rhs) const {
-  return !(*this == rhs);
-}
-
 std::unique_ptr<base::trace_event::TracedValue>
 Configuration::ActivationConditions::ToTracedValue() const {
   auto value = std::make_unique<base::trace_event::TracedValue>();
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h
index 22f56f69..41ba85b 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -103,7 +103,6 @@
   Configuration& operator=(Configuration&&);
 
   bool operator==(const Configuration& rhs) const;
-  bool operator!=(const Configuration& rhs) const;
 
   void AddToValue(base::trace_event::TracedValue*) const;
   std::unique_ptr<base::trace_event::TracedValue> ToTracedValue() const;
diff --git a/components/subresource_filter/tools/rule_parser/rule.cc b/components/subresource_filter/tools/rule_parser/rule.cc
index ceef4e8e..a8759b2f 100644
--- a/components/subresource_filter/tools/rule_parser/rule.cc
+++ b/components/subresource_filter/tools/rule_parser/rule.cc
@@ -149,11 +149,6 @@
 
 CssRule& CssRule::operator=(const CssRule&) = default;
 
-bool CssRule::operator==(const CssRule& other) const {
-  return is_allowlist == other.is_allowlist && domains == other.domains &&
-         css_selector == other.css_selector;
-}
-
 url_pattern_index::proto::CssRule CssRule::ToProtobuf() const {
   url_pattern_index::proto::CssRule result;
 
diff --git a/components/subresource_filter/tools/rule_parser/rule.h b/components/subresource_filter/tools/rule_parser/rule.h
index 3fd4cf77..38f2521 100644
--- a/components/subresource_filter/tools/rule_parser/rule.h
+++ b/components/subresource_filter/tools/rule_parser/rule.h
@@ -52,7 +52,6 @@
   UrlRule& operator=(const UrlRule&);
 
   bool operator==(const UrlRule& other) const;
-  bool operator!=(const UrlRule& other) const { return !operator==(other); }
 
   // Returns a protobuf representation of the rule.
   url_pattern_index::proto::UrlRule ToProtobuf() const;
@@ -102,8 +101,7 @@
   ~CssRule();
   CssRule& operator=(const CssRule&);
 
-  bool operator==(const CssRule& other) const;
-  bool operator!=(const CssRule& other) const { return !operator==(other); }
+  friend bool operator==(const CssRule&, const CssRule&) = default;
 
   // Returns a protobuf representation of the rule.
   url_pattern_index::proto::CssRule ToProtobuf() const;
diff --git a/components/tab_groups/tab_group_visual_data.h b/components/tab_groups/tab_group_visual_data.h
index e042003..aa20fe0 100644
--- a/components/tab_groups/tab_group_visual_data.h
+++ b/components/tab_groups/tab_group_visual_data.h
@@ -40,9 +40,6 @@
   bool operator==(const TabGroupVisualData& other) const {
     return title_ == other.title_ && color_ == other.color_;
   }
-  bool operator!=(const TabGroupVisualData& other) const {
-    return !(*this == other);
-  }
 
   void SetTitle(const std::u16string& title) { title_ = title; }
 
diff --git a/components/tab_groups/token_id.h b/components/tab_groups/token_id.h
index 0683269..316e61ea 100644
--- a/components/tab_groups/token_id.h
+++ b/components/tab_groups/token_id.h
@@ -33,13 +33,8 @@
 
   TokenId<T>& operator=(const TokenId<T>& other) = default;
 
-  bool operator==(const TokenId<T>& other) const {
-    return token_ == other.token_;
-  }
-  bool operator!=(const TokenId<T>& other) const { return !(*this == other); }
-  bool operator<(const TokenId<T>& other) const {
-    return token_ < other.token_;
-  }
+  friend bool operator==(const TokenId<T>&, const TokenId<T>&) = default;
+  friend auto operator<=>(const TokenId<T>&, const TokenId<T>&) = default;
 
   const base::Token& token() const { return token_; }
 
diff --git a/components/tabs/public/supports_handles.h b/components/tabs/public/supports_handles.h
index 41d1b7e..b6306df 100644
--- a/components/tabs/public/supports_handles.h
+++ b/components/tabs/public/supports_handles.h
@@ -114,15 +114,8 @@
   ObjectType* Get() const;
 
   // Handles are comparable and sortable.
-  bool operator==(const Handle& other) const {
-    return raw_value_ == other.raw_value_;
-  }
-  bool operator!=(const Handle& other) const {
-    return raw_value_ != other.raw_value_;
-  }
-  bool operator<(const Handle& other) const {
-    return raw_value_ < other.raw_value_;
-  }
+  friend bool operator==(const Handle&, const Handle&) = default;
+  friend auto operator<=>(const Handle&, const Handle&) = default;
 
   // Explicitly provide the null value and handle.
   static constexpr int32_t NullValue = 0;
diff --git a/components/update_client/component.cc b/components/update_client/component.cc
index 2f6dec3..21c7596 100644
--- a/components/update_client/component.cc
+++ b/components/update_client/component.cc
@@ -154,9 +154,10 @@
     MakePipeline(
         update_context_->config, update_context_->get_available_space,
         update_context_->is_foreground, update_context_->session_id,
-        update_context_->crx_cache_, crx_component_->crx_format_requirement,
-        crx_component_->app_id, crx_component_->pk_hash,
-        crx_component_->install_data_index, crx_component_->installer,
+        update_context_->config->GetCrxCache(),
+        crx_component_->crx_format_requirement, crx_component_->app_id,
+        crx_component_->pk_hash, crx_component_->install_data_index,
+        crx_component_->installer,
         base::BindRepeating(
             [](base::raw_ref<Component> component, ComponentState state) {
               component->state_hint_ = state;
@@ -514,8 +515,8 @@
 
   CHECK(component.crx_component_);
   if (!component.crx_component_->allow_cached_copies) {
-    component.update_context_->crx_cache_->RemoveAll(
-        component.crx_component()->app_id);
+    component.config()->GetCrxCache()->RemoveAll(
+        component.crx_component()->app_id, base::DoNothing());
   }
 
   if (component.error_category_ != ErrorCategory::kNone) {
diff --git a/components/update_client/configurator.h b/components/update_client/configurator.h
index e94cdf6..92a350d 100644
--- a/components/update_client/configurator.h
+++ b/components/update_client/configurator.h
@@ -26,6 +26,7 @@
 
 namespace update_client {
 
+class CrxCache;
 class CrxDownloaderFactory;
 class NetworkFetcherFactory;
 class PatcherFactory;
@@ -142,9 +143,8 @@
   // embedder includes an updater. Returns a null callback otherwise.
   virtual UpdaterStateProvider GetUpdaterStateProvider() const = 0;
 
-  // Returns the filepath where installed crx's should be cached for
-  // puffin patches.
-  virtual std::optional<base::FilePath> GetCrxCachePath() const = 0;
+  // Returns the CrxCache.
+  virtual scoped_refptr<CrxCache> GetCrxCache() const = 0;
 
   virtual bool IsConnectionMetered() const = 0;
 
diff --git a/components/update_client/crx_cache.cc b/components/update_client/crx_cache.cc
index 13fec0c4..0fda314 100644
--- a/components/update_client/crx_cache.cc
+++ b/components/update_client/crx_cache.cc
@@ -8,8 +8,10 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <vector>
 
 #include "base/check.h"
+#include "base/containers/contains.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -43,6 +45,7 @@
       const std::string& hash,
       const std::string& fp) = 0;
   virtual void RemoveAll(const std::string& app_id) = 0;
+  virtual void RemoveIfNot(const std::vector<std::string>& app_ids) = 0;
 };
 
 // CrxCacheImpl uses a metadata.json file of the following format:
@@ -77,6 +80,7 @@
       const std::string& hash,
       const std::string& fp) override;
   void RemoveAll(const std::string& app_id) override;
+  void RemoveIfNot(const std::vector<std::string>& app_ids) override;
 
  private:
   void Remove(const std::string& hash);
@@ -225,6 +229,16 @@
   }
 }
 
+void CrxCacheImpl::RemoveIfNot(const std::vector<std::string>& app_ids) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  absl::flat_hash_set<std::string> retained_ids(app_ids.begin(), app_ids.end());
+  for (const auto& [id, hash] : ListHashesByAppId()) {
+    if (!base::Contains(retained_ids, id)) {
+      RemoveAll(id);
+    }
+  }
+}
+
 void CrxCacheImpl::Remove(const std::string& hash) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   base::DeleteFile(cache_root_.AppendUTF8(hash));
@@ -266,6 +280,9 @@
   void RemoveAll(const std::string& app_id) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   }
+  void RemoveIfNot(const std::vector<std::string>& app_ids) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
 
  private:
   SEQUENCE_CHECKER(sequence_checker_);
@@ -324,9 +341,20 @@
       .Then(std::move(callback));
 }
 
-void CrxCache::RemoveAll(const std::string& app_id) {
+void CrxCache::RemoveAll(const std::string& app_id,
+                         base::OnceClosure callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  delegate_.AsyncCall(&CrxCacheSynchronous::RemoveAll).WithArgs(app_id);
+  delegate_.AsyncCall(&CrxCacheSynchronous::RemoveAll)
+      .WithArgs(app_id)
+      .Then(std::move(callback));
+}
+
+void CrxCache::RemoveIfNot(const std::vector<std::string>& app_ids,
+                           base::OnceClosure callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  delegate_.AsyncCall(&CrxCacheSynchronous::RemoveIfNot)
+      .WithArgs(app_ids)
+      .Then(std::move(callback));
 }
 
 }  // namespace update_client
diff --git a/components/update_client/crx_cache.h b/components/update_client/crx_cache.h
index 42871a1..930564c 100644
--- a/components/update_client/crx_cache.h
+++ b/components/update_client/crx_cache.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <optional>
 #include <string>
+#include <vector>
 
 #include "base/functional/callback_forward.h"
 #include "base/memory/ref_counted.h"
@@ -77,7 +78,12 @@
           callback);
 
   // Removes all entries associated with a particular app ID. O(N) time.
-  void RemoveAll(const std::string& app_id);
+  void RemoveAll(const std::string& app_id, base::OnceClosure callback);
+
+  // Removes all entries that are not associated with any of the listed
+  // app IDs. O(N+M) time.
+  void RemoveIfNot(const std::vector<std::string>& app_ids,
+                   base::OnceClosure callback);
 
  private:
   friend class base::RefCountedThreadSafe<CrxCache>;
diff --git a/components/update_client/crx_cache_unittest.cc b/components/update_client/crx_cache_unittest.cc
index 555a90c..fc37461 100644
--- a/components/update_client/crx_cache_unittest.cc
+++ b/components/update_client/crx_cache_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
@@ -145,7 +146,7 @@
              "hash", "fp", ExpectError(UnpackerError::kCrxCacheNotProvided));
   cache->GetByFp("fp", ExpectError(UnpackerError::kCrxCacheNotProvided));
   cache->GetByHash("hash", ExpectError(UnpackerError::kCrxCacheNotProvided));
-  cache->RemoveAll("appid");
+  cache->RemoveAll("appid", base::DoNothing());
   cache->ListHashesByAppId(ExpectHashes({}).Then(Quit()));
   RunLoop();
 }
@@ -174,10 +175,10 @@
   cache->ListHashesByAppId(
       ExpectHashes({{"appid", "hash"}, {"appid2", "hash2"}}).Then(Quit()));
   RunLoop();
-  cache->RemoveAll("appid");
+  cache->RemoveAll("appid", base::DoNothing());
   cache->ListHashesByAppId(ExpectHashes({{"appid2", "hash2"}}).Then(Quit()));
   RunLoop();
-  cache->RemoveAll("appid2");
+  cache->RemoveAll("appid2", base::DoNothing());
   cache->ListHashesByAppId(ExpectHashes({}).Then(Quit()));
   RunLoop();
 }
diff --git a/components/update_client/ping_manager_unittest.cc b/components/update_client/ping_manager_unittest.cc
index 6b900c8..1416698 100644
--- a/components/update_client/ping_manager_unittest.cc
+++ b/components/update_client/ping_manager_unittest.cc
@@ -15,7 +15,6 @@
 #include <vector>
 
 #include "base/check_deref.h"
-#include "base/files/scoped_temp_dir.h"
 #include "base/functional/bind.h"
 #include "base/json/json_reader.h"
 #include "base/memory/ref_counted.h"
@@ -100,14 +99,9 @@
 }
 
 scoped_refptr<UpdateContext> PingManagerTest::MakeMockUpdateContext() const {
-  base::ScopedTempDir temp_dir;
-  if (!temp_dir.CreateUniqueTempDir()) {
-    return nullptr;
-  }
   return base::MakeRefCounted<UpdateContext>(
-      config_, base::MakeRefCounted<CrxCache>(temp_dir.GetPath()), false, false,
-      std::vector<std::string>(), UpdateClient::CrxStateChangeCallback(),
-      UpdateEngine::Callback(), nullptr,
+      config_, false, false, std::vector<std::string>(),
+      UpdateClient::CrxStateChangeCallback(), UpdateEngine::Callback(), nullptr,
       /*is_update_check_only=*/false);
 }
 
diff --git a/components/update_client/test_configurator.cc b/components/update_client/test_configurator.cc
index eff3220..5304688 100644
--- a/components/update_client/test_configurator.cc
+++ b/components/update_client/test_configurator.cc
@@ -23,6 +23,7 @@
 #include "components/services/patch/in_process_file_patcher.h"
 #include "components/services/unzip/in_process_unzipper.h"
 #include "components/update_client/activity_data_service.h"
+#include "components/update_client/crx_cache.h"
 #include "components/update_client/crx_downloader_factory.h"
 #include "components/update_client/net/network_chromium.h"
 #include "components/update_client/patch/patch_impl.h"
@@ -66,6 +67,9 @@
           [](bool /*is_machine*/) { return UpdaterStateAttributes(); })),
       is_network_connection_metered_(false) {
   std::ignore = crx_cache_root_temp_dir_.CreateUniqueTempDir();
+  crx_cache_ =
+      base::MakeRefCounted<CrxCache>(crx_cache_root_temp_dir_.GetPath().Append(
+          FILE_PATH_LITERAL("crx_cache")));
   auto activity = std::make_unique<TestActivityDataService>();
   activity_data_service_ = activity.get();
   persisted_data_ = CreatePersistedData(
@@ -217,14 +221,9 @@
   return updater_state_provider_;
 }
 
-std::optional<base::FilePath> TestConfigurator::GetCrxCachePath() const {
+scoped_refptr<CrxCache> TestConfigurator::GetCrxCache() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!crx_cache_root_temp_dir_.IsValid()) {
-    return std::nullopt;
-  }
-  return std::optional<base::FilePath>(
-      crx_cache_root_temp_dir_.GetPath().Append(
-          FILE_PATH_LITERAL("crx_cache")));
+  return crx_cache_;
 }
 
 bool TestConfigurator::IsConnectionMetered() const {
diff --git a/components/update_client/test_configurator.h b/components/update_client/test_configurator.h
index 7d317da..e9c6039 100644
--- a/components/update_client/test_configurator.h
+++ b/components/update_client/test_configurator.h
@@ -30,6 +30,7 @@
 
 namespace update_client {
 
+class CrxCache;
 class CrxDownloaderFactory;
 class NetworkFetcherFactory;
 class PatchChromiumFactory;
@@ -107,7 +108,7 @@
       const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
   void SetOnDemandTime(base::TimeDelta seconds);
@@ -153,6 +154,7 @@
   std::optional<bool> is_machine_externally_managed_;
   bool is_network_connection_metered_;
   base::ScopedTempDir crx_cache_root_temp_dir_;
+  scoped_refptr<CrxCache> crx_cache_;
 };
 
 }  // namespace update_client
diff --git a/components/update_client/update_checker.cc b/components/update_client/update_checker.cc
index e149201a..d3be186 100644
--- a/components/update_client/update_checker.cc
+++ b/components/update_client/update_checker.cc
@@ -112,7 +112,7 @@
       &UpdateCheckerImpl::CheckForUpdatesHelper, weak_factory_.GetWeakPtr(),
       context, config_->UpdateUrl(), additional_attributes);
 
-  context->crx_cache_->ListHashesByAppId(base::BindOnce(
+  context->config->GetCrxCache()->ListHashesByAppId(base::BindOnce(
       [](base::OnceCallback<void(const std::multimap<std::string, std::string>&,
                                  const UpdaterStateAttributes&,
                                  const std::set<std::string>&)>
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc
index 324d57e..a6f6ee82 100644
--- a/components/update_client/update_checker_unittest.cc
+++ b/components/update_client/update_checker_unittest.cc
@@ -104,7 +104,6 @@
   scoped_refptr<UpdateContext> MakeMockUpdateContext() const;
 
   base::OnceClosure quit_closure_;
-  base::ScopedTempDir temp_dir_;
 };
 
 // This test is parameterized for |is_foreground|.
@@ -130,7 +129,6 @@
 
   error_ = 0;
   retry_after_sec_ = 0;
-  EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
   update_context_ = MakeMockUpdateContext();
   update_context_->is_foreground = is_foreground_;
   update_context_->components_to_check_for_updates = {kUpdateItemId};
@@ -173,9 +171,8 @@
 
 scoped_refptr<UpdateContext> UpdateCheckerTest::MakeMockUpdateContext() const {
   return base::MakeRefCounted<UpdateContext>(
-      config_, base::MakeRefCounted<CrxCache>(temp_dir_.GetPath()), false,
-      false, std::vector<std::string>(), UpdateClient::CrxStateChangeCallback(),
-      UpdateEngine::Callback(), nullptr,
+      config_, false, false, std::vector<std::string>(),
+      UpdateClient::CrxStateChangeCallback(), UpdateEngine::Callback(), nullptr,
       /*is_update_check_only=*/false);
 }
 
diff --git a/components/update_client/update_engine.cc b/components/update_client/update_engine.cc
index f392d3ca..75159b5 100644
--- a/components/update_client/update_engine.cc
+++ b/components/update_client/update_engine.cc
@@ -62,7 +62,6 @@
 
 UpdateContext::UpdateContext(
     scoped_refptr<Configurator> config,
-    scoped_refptr<CrxCache> crx_cache,
     bool is_foreground,
     bool is_install,
     const std::vector<std::string>& ids,
@@ -72,7 +71,6 @@
     bool is_update_check_only,
     base::RepeatingCallback<int64_t(const base::FilePath&)> get_available_space)
     : config(config),
-      crx_cache_(crx_cache),
       is_foreground(is_foreground),
       is_install(is_install),
       ids(ids),
@@ -99,8 +97,7 @@
     : config_(config),
       update_checker_factory_(update_checker_factory),
       ping_manager_(ping_manager),
-      notify_observers_callback_(notify_observers_callback),
-      crx_cache_(base::MakeRefCounted<CrxCache>(config->GetCrxCachePath())) {}
+      notify_observers_callback_(notify_observers_callback) {}
 
 UpdateEngine::~UpdateEngine() = default;
 
@@ -154,7 +151,7 @@
 
   scoped_refptr<UpdateContext> update_context =
       base::MakeRefCounted<UpdateContext>(
-          config_, crx_cache_, is_foreground, is_install, ids,
+          config_, is_foreground, is_install, ids,
           crx_state_change_callback
               ? base::BindRepeating(
                     [](UpdateClient::CrxStateChangeCallback a,
diff --git a/components/update_client/update_engine.h b/components/update_client/update_engine.h
index eafe5b46..04b7816 100644
--- a/components/update_client/update_engine.h
+++ b/components/update_client/update_engine.h
@@ -124,8 +124,6 @@
   // Called when CRX state changes occur.
   const UpdateClient::CrxStateChangeCallback notify_observers_callback_;
 
-  scoped_refptr<CrxCache> crx_cache_;
-
   // Contains the contexts associated with each update in progress.
   UpdateContexts update_contexts_;
 };
@@ -133,7 +131,6 @@
 // Describes a group of components which are installed or updated together.
 struct UpdateContext : public base::RefCountedThreadSafe<UpdateContext> {
   UpdateContext(scoped_refptr<Configurator> config,
-                scoped_refptr<CrxCache> crx_cache,
                 bool is_foreground,
                 bool is_install,
                 const std::vector<std::string>& ids,
@@ -151,8 +148,6 @@
 
   scoped_refptr<Configurator> config;
 
-  scoped_refptr<CrxCache> crx_cache_;
-
   // True if the component is updated as a result of user interaction.
   bool is_foreground = false;
 
diff --git a/components/user_education/common/feature_promo/feature_promo_precondition.h b/components/user_education/common/feature_promo/feature_promo_precondition.h
index 0d31cee9..f1a44a0 100644
--- a/components/user_education/common/feature_promo/feature_promo_precondition.h
+++ b/components/user_education/common/feature_promo/feature_promo_precondition.h
@@ -286,7 +286,6 @@
     explicit operator bool() const { return result_; }
     bool operator!() const { return !result_; }
     bool operator==(const CheckResult&) const = default;
-    bool operator!=(const CheckResult&) const = default;
 
    private:
     // The result of checking the list; success if no preconditions failed.
diff --git a/components/user_education/common/feature_promo/feature_promo_result.h b/components/user_education/common/feature_promo/feature_promo_result.h
index f67d1552..e379d00 100644
--- a/components/user_education/common/feature_promo/feature_promo_result.h
+++ b/components/user_education/common/feature_promo/feature_promo_result.h
@@ -119,14 +119,9 @@
   // NOLINTNEXTLINE(google-explicit-constructor)
   constexpr operator bool() const { return !failure_.has_value(); }
   constexpr bool operator!() const { return failure_.has_value(); }
-  constexpr bool operator==(const FeaturePromoResult& other) const {
-    return failure_ == other.failure_;
-  }
-  constexpr bool operator!=(const FeaturePromoResult& other) const {
-    return failure_ != other.failure_;
-  }
+  friend constexpr bool operator==(const FeaturePromoResult&,
+                                   const FeaturePromoResult&) = default;
   constexpr bool operator==(Failure other) const { return failure_ == other; }
-  constexpr bool operator!=(Failure other) const { return failure_ != other; }
   constexpr auto failure() const { return failure_; }
 
  private:
diff --git a/components/user_education/common/help_bubble/help_bubble_params.cc b/components/user_education/common/help_bubble/help_bubble_params.cc
index 775b84e9..45a0e5b5 100644
--- a/components/user_education/common/help_bubble/help_bubble_params.cc
+++ b/components/user_education/common/help_bubble/help_bubble_params.cc
@@ -37,16 +37,6 @@
   return *this;
 }
 
-bool HelpBubbleParams::ExtendedProperties::operator==(
-    const ExtendedProperties& other) const {
-  return dict_ == other.dict_;
-}
-
-bool HelpBubbleParams::ExtendedProperties::operator!=(
-    const ExtendedProperties& other) const {
-  return dict_ != other.dict_;
-}
-
 HelpBubbleParams::ExtendedProperties::~ExtendedProperties() = default;
 
 HelpBubbleParams::HelpBubbleParams() = default;
diff --git a/components/user_education/common/help_bubble/help_bubble_params.h b/components/user_education/common/help_bubble/help_bubble_params.h
index 8a9d3648..d03753a 100644
--- a/components/user_education/common/help_bubble/help_bubble_params.h
+++ b/components/user_education/common/help_bubble/help_bubble_params.h
@@ -67,8 +67,8 @@
     ExtendedProperties& operator=(ExtendedProperties&&) noexcept;
     ~ExtendedProperties();
 
-    bool operator==(const ExtendedProperties&) const;
-    bool operator!=(const ExtendedProperties&) const;
+    friend bool operator==(const ExtendedProperties&,
+                           const ExtendedProperties&) = default;
 
     base::Value::Dict& values() { return dict_; }
     const base::Value::Dict& values() const { return dict_; }
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 20370262..c3389430 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -2704,13 +2704,25 @@
   const gfx::HDRMetadata& src_hdr_metadata =
       resource_provider()->GetHDRMetadata(quad->resource_id);
 
-  const bool needs_tone_map =
-      ((quad->is_video_frame && src_color_space.IsHDR()) ||
-       src_color_space.IsToneMappedByDefault()) &&
-      // Don't do tone mapping for stream video unless
-      // FixAndroidToneMapping is enabled.
-      (!quad->is_stream_video ||
-       base::FeatureList::IsEnabled(kFixAndroidToneMapping));
+  const bool needs_tone_map = [&]() {
+    // Don't do tone mapping for stream video unless FixAndroidToneMapping is
+    // enabled.
+    if (quad->is_stream_video &&
+        !base::FeatureList::IsEnabled(kFixAndroidToneMapping)) {
+      return false;
+    }
+    if (quad->is_video_frame && src_color_space.IsHDR()) {
+      return true;
+    }
+    if (src_color_space.IsToneMappedByDefault()) {
+      return true;
+    }
+    if (gfx::HdrMetadataAgtm::IsEnabled() &&
+        src_hdr_metadata.agtm.has_value()) {
+      return true;
+    }
+    return false;
+  }();
 
   sk_sp<SkColorSpace> override_color_space;
   if (overlay_color_space) {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index d5efbd5d..a6355a4 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -815,11 +815,6 @@
       frame_sink_type_ == mojom::CompositorFrameSinkType::kVideo) {
     ApplyPreferredFrameRate(frame.metadata.begin_frame_ack.frame_id.source_id);
   }
-  if (base::FeatureList::IsEnabled(
-          features::kThrottleFrameRateOnManyDidNotProduceFrame) &&
-      frame_sink_type_ == mojom::CompositorFrameSinkType::kLayerTree) {
-    ApplyPreferredFrameRate(frame.metadata.begin_frame_ack.frame_id.source_id);
-  }
 
   Surface* prev_surface =
       surface_manager_->GetSurfaceForId(last_created_surface_id_);
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc
index edbfec5..8dbdbe67 100644
--- a/components/viz/service/layers/layer_context_impl.cc
+++ b/components/viz/service/layers/layer_context_impl.cc
@@ -452,6 +452,7 @@
   layer.SetShouldCheckBackfaceVisibility(wire.should_check_backface_visibility);
   if (wire.rare_properties) {
     layer.SetFilterQuality(wire.rare_properties->filter_quality);
+    layer.SetDynamicRangeLimit(wire.rare_properties->dynamic_range_limit);
     layer.SetCaptureBounds(wire.rare_properties->capture_bounds);
   }
   layer.SetMayContainVideo(wire.may_contain_video);
diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h
index 0c58512..998ea32 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/components/web_modal/web_contents_modal_dialog_manager.h
@@ -127,8 +127,7 @@
   void WebContentsDestroyed() override;
 
   // Delegate for notifying our owner about stuff. Not owned by us.
-  raw_ptr<WebContentsModalDialogManagerDelegate, AcrossTasksDanglingUntriaged>
-      delegate_ = nullptr;
+  raw_ptr<WebContentsModalDialogManagerDelegate> delegate_ = nullptr;
 
   // All active dialogs.
   base::circular_deque<DialogState> child_dialogs_;
diff --git a/components/web_package/signed_web_bundles/ed25519_public_key.cc b/components/web_package/signed_web_bundles/ed25519_public_key.cc
index 44f7664..70e786b3 100644
--- a/components/web_package/signed_web_bundles/ed25519_public_key.cc
+++ b/components/web_package/signed_web_bundles/ed25519_public_key.cc
@@ -24,14 +24,6 @@
 
 Ed25519PublicKey::~Ed25519PublicKey() = default;
 
-bool Ed25519PublicKey::operator==(const Ed25519PublicKey& other) const {
-  return *bytes_ == *other.bytes_;
-}
-
-bool Ed25519PublicKey::operator!=(const Ed25519PublicKey& other) const {
-  return !(*this == other);
-}
-
 base::expected<Ed25519PublicKey, std::string> Ed25519PublicKey::Create(
     base::span<const uint8_t> key) {
   auto sized_key = key.to_fixed_extent<kLength>();
diff --git a/components/web_package/signed_web_bundles/ed25519_public_key.h b/components/web_package/signed_web_bundles/ed25519_public_key.h
index a7622b7..76479d7 100644
--- a/components/web_package/signed_web_bundles/ed25519_public_key.h
+++ b/components/web_package/signed_web_bundles/ed25519_public_key.h
@@ -45,8 +45,8 @@
 
   ~Ed25519PublicKey();
 
-  bool operator==(const Ed25519PublicKey&) const;
-  bool operator!=(const Ed25519PublicKey&) const;
+  friend bool operator==(const Ed25519PublicKey&,
+                         const Ed25519PublicKey&) = default;
 
   const std::array<uint8_t, kLength>& bytes() const { return *bytes_; }
 
diff --git a/components/web_package/signed_web_bundles/ed25519_signature.cc b/components/web_package/signed_web_bundles/ed25519_signature.cc
index d97611d..62e24ae 100644
--- a/components/web_package/signed_web_bundles/ed25519_signature.cc
+++ b/components/web_package/signed_web_bundles/ed25519_signature.cc
@@ -28,14 +28,6 @@
   return Create(*sized_bytes);
 }
 
-bool Ed25519Signature::operator==(const Ed25519Signature& other) const {
-  return *bytes_ == *other.bytes_;
-}
-
-bool Ed25519Signature::operator!=(const Ed25519Signature& other) const {
-  return !operator==(other);
-}
-
 // static
 Ed25519Signature Ed25519Signature::Create(
     base::span<const uint8_t, kLength> bytes) {
diff --git a/components/web_package/signed_web_bundles/ed25519_signature.h b/components/web_package/signed_web_bundles/ed25519_signature.h
index 92f3cad..531df26 100644
--- a/components/web_package/signed_web_bundles/ed25519_signature.h
+++ b/components/web_package/signed_web_bundles/ed25519_signature.h
@@ -34,8 +34,8 @@
   Ed25519Signature& operator=(const Ed25519Signature&) = default;
   Ed25519Signature& operator=(Ed25519Signature&&) = default;
 
-  bool operator==(const Ed25519Signature& other) const;
-  bool operator!=(const Ed25519Signature& other) const;
+  friend bool operator==(const Ed25519Signature&,
+                         const Ed25519Signature&) = default;
 
   [[nodiscard]] bool Verify(base::span<const uint8_t> message,
                             const Ed25519PublicKey& public_key) const;
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.cc b/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.cc
index fcee85ac..8991e89c 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.cc
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.cc
@@ -59,10 +59,4 @@
 SignedWebBundleIntegrityBlock& SignedWebBundleIntegrityBlock::operator=(
     const SignedWebBundleIntegrityBlock&) = default;
 
-bool SignedWebBundleIntegrityBlock::operator==(
-    const SignedWebBundleIntegrityBlock& other) const = default;
-
-bool SignedWebBundleIntegrityBlock::operator!=(
-    const SignedWebBundleIntegrityBlock& other) const = default;
-
 }  // namespace web_package
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.h b/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.h
index 14ecb09f..695d7ccd 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.h
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.h
@@ -42,8 +42,8 @@
 
   ~SignedWebBundleIntegrityBlock();
 
-  bool operator==(const SignedWebBundleIntegrityBlock& other) const;
-  bool operator!=(const SignedWebBundleIntegrityBlock& other) const;
+  friend bool operator==(const SignedWebBundleIntegrityBlock&,
+                         const SignedWebBundleIntegrityBlock&) = default;
 
   // Returns the size of this integrity block in bytes. This is useful for
   // finding out where the actual Web Bundle starts.
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.cc b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.cc
index 8e547ed..28832277 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.cc
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.cc
@@ -85,16 +85,6 @@
 
 SignedWebBundleSignatureStack::~SignedWebBundleSignatureStack() = default;
 
-bool SignedWebBundleSignatureStack::operator==(
-    const SignedWebBundleSignatureStack& other) const {
-  return entries() == other.entries();
-}
-
-bool SignedWebBundleSignatureStack::operator!=(
-    const SignedWebBundleSignatureStack& other) const {
-  return !operator==(other);
-}
-
 std::vector<PublicKey> SignedWebBundleSignatureStack::public_keys() const {
   std::vector<PublicKey> public_keys;
   for (const auto& signature : entries()) {
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.h b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.h
index 1f708099..280754e 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.h
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.h
@@ -35,8 +35,8 @@
 
   ~SignedWebBundleSignatureStack();
 
-  bool operator==(const SignedWebBundleSignatureStack& other) const;
-  bool operator!=(const SignedWebBundleSignatureStack& other) const;
+  friend bool operator==(const SignedWebBundleSignatureStack&,
+                         const SignedWebBundleSignatureStack&) = default;
 
   // Returns the signature stack entries. There is guaranteed to be at least one
   // entry. The first entry corresponds to the entry at the bottom of the stack.
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.cc b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.cc
index 745d15d..2b6f1a4 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.cc
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.cc
@@ -12,17 +12,6 @@
     : attributes_cbor_(attributes_cbor),
       signature_info_(std::move(signature_info)) {}
 
-bool SignedWebBundleSignatureStackEntry::operator==(
-    const SignedWebBundleSignatureStackEntry& other) const {
-  return attributes_cbor_ == other.attributes_cbor_ &&
-         signature_info_ == other.signature_info_;
-}
-
-bool SignedWebBundleSignatureStackEntry::operator!=(
-    const SignedWebBundleSignatureStackEntry& other) const {
-  return !operator==(other);
-}
-
 SignedWebBundleSignatureStackEntry::SignedWebBundleSignatureStackEntry(
     const SignedWebBundleSignatureStackEntry&) = default;
 
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.h b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.h
index 5e3d0d2e..7f9c3031 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.h
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_signature_stack_entry.h
@@ -35,8 +35,6 @@
 
   bool operator==(const SignedWebBundleSignatureInfoBase& other) const =
       default;
-  bool operator!=(const SignedWebBundleSignatureInfoBase& other) const =
-      default;
 
   const PublicKey& public_key() const { return public_key_; }
   const Signature& signature() const { return signature_; }
@@ -95,8 +93,8 @@
 
   ~SignedWebBundleSignatureStackEntry();
 
-  bool operator==(const SignedWebBundleSignatureStackEntry& other) const;
-  bool operator!=(const SignedWebBundleSignatureStackEntry& other) const;
+  friend bool operator==(const SignedWebBundleSignatureStackEntry&,
+                         const SignedWebBundleSignatureStackEntry&) = default;
 
   const std::vector<uint8_t>& attributes_cbor() const {
     return attributes_cbor_;
diff --git a/components/webapps/isolated_web_apps/BUILD.gn b/components/webapps/isolated_web_apps/BUILD.gn
index b6b3546..055a3e1 100644
--- a/components/webapps/isolated_web_apps/BUILD.gn
+++ b/components/webapps/isolated_web_apps/BUILD.gn
@@ -9,6 +9,8 @@
     "iwa_key_distribution_histograms.h",
     "iwa_key_distribution_info_provider.cc",
     "iwa_key_distribution_info_provider.h",
+    "update_channel.cc",
+    "update_channel.h",
   ]
 
   public_deps = [ "//components/webapps/isolated_web_apps/proto" ]
diff --git a/components/webapps/isolated_web_apps/update_channel.cc b/components/webapps/isolated_web_apps/update_channel.cc
new file mode 100644
index 0000000..656e208
--- /dev/null
+++ b/components/webapps/isolated_web_apps/update_channel.cc
@@ -0,0 +1,52 @@
+// Copyright 2025 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/webapps/isolated_web_apps/update_channel.h"
+
+#include <string>
+#include <utility>
+
+#include "base/no_destructor.h"
+#include "base/strings/string_util.h"
+
+namespace web_app {
+
+UpdateChannel::UpdateChannel(std::string channel_name)
+    : name_(std::move(channel_name)) {}
+
+UpdateChannel::UpdateChannel(const UpdateChannel&) = default;
+
+UpdateChannel::UpdateChannel(UpdateChannel&&) = default;
+
+UpdateChannel& UpdateChannel::operator=(const UpdateChannel&) = default;
+
+UpdateChannel& UpdateChannel::operator=(UpdateChannel&&) = default;
+
+UpdateChannel::~UpdateChannel() = default;
+
+bool UpdateChannel::operator==(const UpdateChannel& other) const = default;
+auto UpdateChannel::operator<=>(const UpdateChannel& other) const = default;
+bool UpdateChannel::operator<(const UpdateChannel& other) const = default;
+
+// static
+const UpdateChannel& UpdateChannel::default_channel() {
+  static const base::NoDestructor<UpdateChannel> kDefaultChannel(
+      [] { return *UpdateChannel::Create("default"); }());
+  return *kDefaultChannel;
+}
+
+// static
+base::expected<UpdateChannel, std::monostate> UpdateChannel::Create(
+    std::string input) {
+  if (input.empty() || !base::IsStringUTF8(input)) {
+    return base::unexpected(std::monostate());
+  }
+  return UpdateChannel(std::move(input));
+}
+
+void PrintTo(const UpdateChannel& channel, std::ostream* ostr) {
+  *ostr << channel.ToString();
+}
+
+}  // namespace web_app
diff --git a/components/webapps/isolated_web_apps/update_channel.h b/components/webapps/isolated_web_apps/update_channel.h
new file mode 100644
index 0000000..b31772f
--- /dev/null
+++ b/components/webapps/isolated_web_apps/update_channel.h
@@ -0,0 +1,47 @@
+// Copyright 2025 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_WEBAPPS_ISOLATED_WEB_APPS_UPDATE_CHANNEL_H_
+#define COMPONENTS_WEBAPPS_ISOLATED_WEB_APPS_UPDATE_CHANNEL_H_
+
+#include <string>
+#include <variant>
+
+#include "base/types/expected.h"
+
+namespace web_app {
+
+class UpdateChannel {
+ public:
+  // Returns an instance of the "default" update channel.
+  static const UpdateChannel& default_channel();
+
+  static base::expected<UpdateChannel, std::monostate> Create(
+      std::string input);
+
+  UpdateChannel(const UpdateChannel&);
+  UpdateChannel(UpdateChannel&&);
+  UpdateChannel& operator=(const UpdateChannel&);
+  UpdateChannel& operator=(UpdateChannel&&);
+
+  ~UpdateChannel();
+
+  bool operator==(const UpdateChannel& other) const;
+  auto operator<=>(const UpdateChannel& other) const;
+  bool operator<(const UpdateChannel& other) const;
+
+  const std::string& ToString() const { return name_; }
+
+  // For gtest
+  friend void PrintTo(const UpdateChannel& channel, std::ostream* ostr);
+
+ private:
+  explicit UpdateChannel(std::string channel_name);
+
+  std::string name_;
+};
+
+}  // namespace web_app
+
+#endif  // COMPONENTS_WEBAPPS_ISOLATED_WEB_APPS_UPDATE_CHANNEL_H_
diff --git a/components/webauthn/android/internal_authenticator_android.cc b/components/webauthn/android/internal_authenticator_android.cc
index 0d01b4f..445d884 100644
--- a/components/webauthn/android/internal_authenticator_android.cc
+++ b/components/webauthn/android/internal_authenticator_android.cc
@@ -38,11 +38,18 @@
 
 InternalAuthenticatorAndroid::InternalAuthenticatorAndroid(
     content::RenderFrameHost* render_frame_host)
-    : render_frame_host_id_(render_frame_host->GetGlobalId()) {
+    : render_frame_host_id_(render_frame_host
+                                ? render_frame_host->GetGlobalId()
+                                : content::GlobalRenderFrameHostId()) {
   JNIEnv* env = AttachCurrentThread();
-  java_internal_authenticator_ref_ = Java_InternalAuthenticator_create(
-      env, reinterpret_cast<intptr_t>(this),
-      render_frame_host->GetJavaRenderFrameHost());
+  if (render_frame_host) {
+    java_internal_authenticator_ref_ = Java_InternalAuthenticator_create(
+        env, reinterpret_cast<intptr_t>(this),
+        render_frame_host->GetJavaRenderFrameHost());
+  } else {
+    java_internal_authenticator_ref_ = Java_InternalAuthenticator_create(
+        env, reinterpret_cast<intptr_t>(this));
+  }
 }
 
 InternalAuthenticatorAndroid::~InternalAuthenticatorAndroid() {
@@ -226,9 +233,15 @@
 JavaRef<jobject>& InternalAuthenticatorAndroid::GetJavaObject() {
   if (java_internal_authenticator_ref_.is_null()) {
     JNIEnv* env = AttachCurrentThread();
-    java_internal_authenticator_ref_ = Java_InternalAuthenticator_create(
-        env, reinterpret_cast<intptr_t>(this),
-        GetRenderFrameHost()->GetJavaRenderFrameHost());
+    content::RenderFrameHost* render_frame_host = GetRenderFrameHost();
+    if (render_frame_host) {
+      java_internal_authenticator_ref_ = Java_InternalAuthenticator_create(
+          env, reinterpret_cast<intptr_t>(this),
+          render_frame_host->GetJavaRenderFrameHost());
+    } else {
+      java_internal_authenticator_ref_ = Java_InternalAuthenticator_create(
+          env, reinterpret_cast<intptr_t>(this));
+    }
   }
   return java_internal_authenticator_ref_;
 }
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java
index 85e4c39..cb5ba84f 100644
--- a/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java
+++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java
@@ -49,8 +49,8 @@
 public final class AuthenticatorImpl implements Authenticator, AuthenticationContextProvider {
     private final @Nullable Context mContext;
     private final @Nullable WebContents mWebContents;
-    private final FidoIntentSender mIntentSender;
-    private final RenderFrameHost mRenderFrameHost;
+    private final @Nullable FidoIntentSender mIntentSender;
+    private final @Nullable RenderFrameHost mRenderFrameHost;
     private final @Nullable CreateConfirmationUiDelegate mCreateConfirmationUiDelegate;
 
     /** Ensures only one request is processed at a time. */
@@ -58,7 +58,8 @@
 
     /**
      * The origin of the request. This may be overridden by an internal request from the browser
-     * process.
+     * process. <code>mOrigin</code> will be set when a RenderFrameHost is provided at construction
+     * and null otherwise.
      */
     private @Nullable Origin mOrigin;
 
@@ -88,27 +89,29 @@
      *
      * @param context The context of the AndroidWindow that triggered this operation.
      * @param intentSender The interface that will be used to start {@link Intent}s from Play
-     *     Services.
+     *     Services. May only be null for calls that do not go to Play Services such as {@link
+     *     #getMatchingCredentialIds()}.
      * @param createConfirmationUiDelegate If not null, is an object that will be called before
      *     creating a credential to show a confirmation UI.
-     * @param renderFrameHost The host of the frame that has invoked the API.
+     * @param renderFrameHost The host of the frame that has invoked the API. Null if created
+     *     unrelated to a renderer context, and when renderFrameHost is null {@link
+     *     #makeCredential()} and {@link #getCredential()} will fail, do not call them.
      * @param topOrigin The origin of the main frame.
      */
     public AuthenticatorImpl(
             @Nullable Context context,
             @Nullable WebContents webContents,
-            FidoIntentSender intentSender,
+            @Nullable FidoIntentSender intentSender,
             @Nullable CreateConfirmationUiDelegate createConfirmationUiDelegate,
-            RenderFrameHost renderFrameHost,
+            @Nullable RenderFrameHost renderFrameHost,
             @Nullable Origin topOrigin) {
-        assert renderFrameHost != null;
         assert WebauthnModeProvider.getInstance().getWebauthnMode(webContents) != WebauthnMode.NONE;
 
         mContext = context;
         mWebContents = webContents;
         mIntentSender = intentSender;
         mRenderFrameHost = renderFrameHost;
-        mOrigin = mRenderFrameHost.getLastCommittedOrigin();
+        mOrigin = mRenderFrameHost == null ? null : mRenderFrameHost.getLastCommittedOrigin();
         mTopOrigin = topOrigin;
         mCreateConfirmationUiDelegate = createConfirmationUiDelegate;
     }
@@ -146,6 +149,8 @@
     @Override
     public void makeCredential(
             PublicKeyCredentialCreationOptions options, MakeCredential_Response callback) {
+        assert mIntentSender != null;
+        assert mRenderFrameHost != null;
         if (mIsOperationPending) {
             callback.call(AuthenticatorStatus.PENDING_REQUEST, null, null);
             return;
@@ -200,6 +205,8 @@
     @Override
     public void getCredential(
             PublicKeyCredentialRequestOptions options, GetCredential_Response callback) {
+        assert mIntentSender != null;
+        assert mRenderFrameHost != null;
         if (mIsOperationPending) {
             callback.call(
                     getCredentialResponseForAssertion(AuthenticatorStatus.PENDING_REQUEST, null));
@@ -476,12 +483,13 @@
     }
 
     @Override
-    public RenderFrameHost getRenderFrameHost() {
+    public @Nullable RenderFrameHost getRenderFrameHost() {
         return mRenderFrameHost;
     }
 
     @Override
     public FidoIntentSender getIntentSender() {
+        assert mIntentSender != null;
         return mIntentSender;
     }
 
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/InternalAuthenticator.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/InternalAuthenticator.java
index 32488d9..35a6134a 100644
--- a/components/webauthn/android/java/src/org/chromium/components/webauthn/InternalAuthenticator.java
+++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/InternalAuthenticator.java
@@ -14,6 +14,7 @@
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.blink.mojom.AuthenticatorStatus;
 import org.chromium.blink.mojom.PaymentOptions;
 import org.chromium.blink.mojom.PublicKeyCredentialCreationOptions;
@@ -45,8 +46,8 @@
             long nativeInternalAuthenticatorAndroid,
             @Nullable Context context,
             @Nullable WebContents webContents,
-            FidoIntentSender intentSender,
-            RenderFrameHost renderFrameHost,
+            @Nullable FidoIntentSender intentSender,
+            @Nullable RenderFrameHost renderFrameHost,
             @Nullable Origin topOrigin) {
         mNativeInternalAuthenticatorAndroid = nativeInternalAuthenticatorAndroid;
         WebauthnModeProvider.getInstance().setGlobalWebauthnMode(WebauthnMode.CHROME);
@@ -88,6 +89,17 @@
     }
 
     @CalledByNative
+    public static InternalAuthenticator create(long nativeInternalAuthenticatorAndroid) {
+        return new InternalAuthenticator(
+                nativeInternalAuthenticatorAndroid,
+                ContextUtils.getApplicationContext(),
+                /* webContents= */ null,
+                /* intentSender= */ null,
+                /* renderFrameHost= */ null,
+                /* topOrigin= */ null);
+    }
+
+    @CalledByNative
     public void clearNativePtr() {
         mNativeInternalAuthenticatorAndroid = 0;
     }
diff --git a/components/webauthn/android/junit/src/org/chromium/components/webauthn/AuthenticatorImplTest.java b/components/webauthn/android/junit/src/org/chromium/components/webauthn/AuthenticatorImplTest.java
index 28cfe531..c67e63b 100644
--- a/components/webauthn/android/junit/src/org/chromium/components/webauthn/AuthenticatorImplTest.java
+++ b/components/webauthn/android/junit/src/org/chromium/components/webauthn/AuthenticatorImplTest.java
@@ -5,6 +5,7 @@
 package org.chromium.components.webauthn;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -191,4 +192,80 @@
         }
         throw new AssertionError("Capability '" + name + "' not found.");
     }
+
+    /** Test that makeCredential() throws when the renderFrameHost is not set. */
+    @Test
+    public void testMakeCredential_requiresRenderFrameHost() {
+        AuthenticatorImpl authenticator =
+                new AuthenticatorImpl(
+                        ApplicationProvider.getApplicationContext(),
+                        mWebContents,
+                        mIntentSender,
+                        /* createConfirmationUiDelegate= */ null,
+                        /* renderFrameHost= */ null,
+                        mTopOrigin);
+
+        assertThrows(
+                AssertionError.class,
+                () -> {
+                    authenticator.makeCredential(/* options= */ null, /* callback= */ null);
+                });
+    }
+
+    /** Test that makeCredential() throws when the intenSender is not set. */
+    @Test
+    public void testMakeCredential_requiresIntentSender() {
+        AuthenticatorImpl authenticator =
+                new AuthenticatorImpl(
+                        ApplicationProvider.getApplicationContext(),
+                        mWebContents,
+                        /* intentSender= */ null,
+                        /* createConfirmationUiDelegate= */ null,
+                        mRenderFrameHost,
+                        mTopOrigin);
+
+        assertThrows(
+                AssertionError.class,
+                () -> {
+                    authenticator.makeCredential(/* options= */ null, /* callback= */ null);
+                });
+    }
+
+    /** Test that getCredential() throws when the renderFrameHost is not set. */
+    @Test
+    public void testGetCredential_requiresRenderFrameHost() {
+        AuthenticatorImpl authenticator =
+                new AuthenticatorImpl(
+                        ApplicationProvider.getApplicationContext(),
+                        mWebContents,
+                        mIntentSender,
+                        /* createConfirmationUiDelegate= */ null,
+                        /* renderFrameHost= */ null,
+                        mTopOrigin);
+
+        assertThrows(
+                AssertionError.class,
+                () -> {
+                    authenticator.getCredential(/* options= */ null, /* callback= */ null);
+                });
+    }
+
+    /** Test that getCredential() throws when the intentSender is not set. */
+    @Test
+    public void testGetCredential_requiresIntentSender() {
+        AuthenticatorImpl authenticator =
+                new AuthenticatorImpl(
+                        ApplicationProvider.getApplicationContext(),
+                        mWebContents,
+                        /* intentSender= */ null,
+                        /* createConfirmationUiDelegate= */ null,
+                        mRenderFrameHost,
+                        mTopOrigin);
+
+        assertThrows(
+                AssertionError.class,
+                () -> {
+                    authenticator.getCredential(/* options= */ null, /* callback= */ null);
+                });
+    }
 }
diff --git a/components/webauthn/ios/BUILD.gn b/components/webauthn/ios/BUILD.gn
new file mode 100644
index 0000000..72f7316
--- /dev/null
+++ b/components/webauthn/ios/BUILD.gn
@@ -0,0 +1,50 @@
+# Copyright 2025 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/features.gni")
+import("//ios/web/public/js_messaging/optimize_ts.gni")
+
+source_set("ios") {
+  deps = [
+    ":passkey_controller_js",
+    "//base",
+    "//ios/web/public/js_messaging",
+  ]
+
+  sources = [
+    "passkey_java_script_feature.h",
+    "passkey_java_script_feature.mm",
+  ]
+}
+
+optimize_ts("passkey_controller_js") {
+  visibility = [
+    ":ios",
+    ":js_tests",
+  ]
+
+  sources = [ "resources/passkey_controller.ts" ]
+
+  deps = [ "//ios/web/public/js_messaging:util_scripts" ]
+}
+
+source_set("features") {
+  sources = [
+    "features.h",
+    "features.mm",
+  ]
+  public_deps = [ "//base" ]
+}
+
+source_set("js_tests") {
+  testonly = true
+  sources = [ "passkey_controller_javascript_test.mm" ]
+  deps = [
+    ":passkey_controller_js",
+    "//ios/web/public/test:javascript_test",
+    "//ios/web/public/test:util",
+    "//net:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/webauthn/ios/DEPS b/components/webauthn/ios/DEPS
new file mode 100644
index 0000000..92ecbeb
--- /dev/null
+++ b/components/webauthn/ios/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+ios/web/public",
+  "+net/test/embedded_test_server",
+]
diff --git a/components/webauthn/ios/OWNERS b/components/webauthn/ios/OWNERS
new file mode 100644
index 0000000..2b18348
--- /dev/null
+++ b/components/webauthn/ios/OWNERS
@@ -0,0 +1,2 @@
+rgod@google.com
+tmartino@chromium.org
diff --git a/components/webauthn/ios/features.h b/components/webauthn/ios/features.h
new file mode 100644
index 0000000..adefb76
--- /dev/null
+++ b/components/webauthn/ios/features.h
@@ -0,0 +1,15 @@
+// Copyright 2025 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_WEBAUTHN_IOS_FEATURES_H_
+#define COMPONENTS_WEBAUTHN_IOS_FEATURES_H_
+
+#include "base/feature_list.h"
+
+// Shim the WebKit implementation of navigator.credentials to enable enhanced
+// passkey-related features.
+// Keep as a kill switch after enabling by default.
+BASE_DECLARE_FEATURE(kIOSPasskeyShim);
+
+#endif  // COMPONENTS_WEBAUTHN_IOS_FEATURES_H_
diff --git a/components/webauthn/ios/features.mm b/components/webauthn/ios/features.mm
new file mode 100644
index 0000000..06804ecc
--- /dev/null
+++ b/components/webauthn/ios/features.mm
@@ -0,0 +1,9 @@
+// Copyright 2025 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/webauthn/ios/features.h"
+
+BASE_FEATURE(kIOSPasskeyShim,
+             "IOSPasskeyShim",
+             base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/webauthn/ios/passkey_controller_javascript_test.mm b/components/webauthn/ios/passkey_controller_javascript_test.mm
new file mode 100644
index 0000000..82df2d0e
--- /dev/null
+++ b/components/webauthn/ios/passkey_controller_javascript_test.mm
@@ -0,0 +1,130 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/test/ios/wait_util.h"
+#import "ios/web/public/test/javascript_test.h"
+#import "ios/web/public/test/js_test_util.h"
+#import "net/test/embedded_test_server/embedded_test_server.h"
+#import "net/test/embedded_test_server/http_response.h"
+#import "testing/gtest_mac.h"
+#import "url/gurl.h"
+
+namespace {
+
+const char kNavigatorCredentialsCreateUrl[] = "/credentialsCreate";
+const char kNavigatorCredentialsGetUrl[] = "/credentialsGet";
+
+const char kNavigatorCredentialsCreatePageHtml[] =
+    "<html><body><script>"
+    "navigator.credentials.create({ publicKey: {} });"
+    "</script></body></html>";
+const char kNavigatorCredentialsGetPageHtml[] =
+    "<html><body><script>"
+    "navigator.credentials.get({ publicKey: {} });"
+    "</script></body></html>";
+
+// Provides responses for initial page and destination URLs.
+std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
+    const net::test_server::HttpRequest& request) {
+  std::unique_ptr<net::test_server::BasicHttpResponse> http_response =
+      std::make_unique<net::test_server::BasicHttpResponse>();
+  http_response->set_code(net::HTTP_OK);
+
+  if (request.relative_url == kNavigatorCredentialsCreateUrl) {
+    http_response->set_content(kNavigatorCredentialsCreatePageHtml);
+  } else if (request.relative_url == kNavigatorCredentialsGetUrl) {
+    http_response->set_content(kNavigatorCredentialsGetPageHtml);
+  } else {
+    return nullptr;
+  }
+  return std::move(http_response);
+}
+
+}  // namespace
+
+@interface PasskeyScriptMessageHandler : NSObject <WKScriptMessageHandler>
+@property(nonatomic, strong) WKScriptMessage* lastReceivedMessage;
+@end
+
+@implementation PasskeyScriptMessageHandler
+
+- (void)configureForWebView:(WKWebView*)webView {
+  [webView.configuration.userContentController
+      addScriptMessageHandler:self
+                         name:@"PasskeyInteractionHandler"];
+}
+
+- (void)userContentController:(WKUserContentController*)userContentController
+      didReceiveScriptMessage:(WKScriptMessage*)message {
+  self.lastReceivedMessage = message;
+}
+
+@end
+
+// Test fixture for passkey_controller.ts.
+// TODO(crbug.com/369629469): Explore adding EG tests that verify original JS
+// APIs still working with shim injected. It is infeasible in JS tests since
+// navigator.credentials APIs for public key credentials require some user
+// interaction with system UI.
+class PasskeyControllerJavaScriptTest : public web::JavascriptTest {
+ protected:
+  PasskeyControllerJavaScriptTest()
+      : server_(net::EmbeddedTestServer::TYPE_HTTP),
+        message_handler_([[PasskeyScriptMessageHandler alloc] init]) {}
+  ~PasskeyControllerJavaScriptTest() override {}
+
+  void SetUp() override {
+    JavascriptTest::SetUp();
+
+    AddUserScript(@"passkey_controller");
+
+    server_.RegisterRequestHandler(base::BindRepeating(&StandardResponse));
+    ASSERT_TRUE(server_.Start());
+
+    [message_handler_ configureForWebView:web_view()];
+  }
+
+  const net::EmbeddedTestServer& server() { return server_; }
+  PasskeyScriptMessageHandler* message_handler() { return message_handler_; }
+
+ private:
+  net::EmbeddedTestServer server_;
+  PasskeyScriptMessageHandler* message_handler_;
+};
+
+TEST_F(PasskeyControllerJavaScriptTest,
+       NavigatorCredentialsCreateMessageReceived) {
+  GURL URL = server().GetURL(kNavigatorCredentialsCreateUrl);
+  ASSERT_TRUE(LoadUrl(URL));
+
+  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForPageLoadTimeout, ^{
+        return message_handler().lastReceivedMessage != nil;
+      }));
+
+  NSDictionary* body = message_handler().lastReceivedMessage.body;
+  NSArray* allKeys = body.allKeys;
+  EXPECT_EQ(allKeys.count, 1ul);
+  EXPECT_TRUE([allKeys containsObject:@"event"]);
+
+  EXPECT_NSEQ(@"createRequested", body[@"event"]);
+}
+
+TEST_F(PasskeyControllerJavaScriptTest,
+       NavigatorCredentialsGetMessageReceived) {
+  GURL URL = server().GetURL(kNavigatorCredentialsGetUrl);
+  ASSERT_TRUE(LoadUrl(URL));
+
+  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForPageLoadTimeout, ^{
+        return message_handler().lastReceivedMessage != nil;
+      }));
+
+  NSDictionary* body = message_handler().lastReceivedMessage.body;
+  NSArray* allKeys = body.allKeys;
+  EXPECT_EQ(allKeys.count, 1ul);
+  EXPECT_TRUE([allKeys containsObject:@"event"]);
+
+  EXPECT_NSEQ(@"getRequested", body[@"event"]);
+}
diff --git a/components/webauthn/ios/passkey_java_script_feature.h b/components/webauthn/ios/passkey_java_script_feature.h
new file mode 100644
index 0000000..6bf79019
--- /dev/null
+++ b/components/webauthn/ios/passkey_java_script_feature.h
@@ -0,0 +1,39 @@
+// Copyright 2025 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_WEBAUTHN_IOS_PASSKEY_JAVA_SCRIPT_FEATURE_H_
+#define COMPONENTS_WEBAUTHN_IOS_PASSKEY_JAVA_SCRIPT_FEATURE_H_
+
+#import "base/no_destructor.h"
+#import "ios/web/public/js_messaging/java_script_feature.h"
+
+// Communicates with the JavaScript file passkey_controller.ts, which contains
+// a shim of the navigator.credentials API.
+//
+// The main intent of the shim is to facilitate certain passkey functionality
+// (e.g. assertion / creation) in Chromium, hence the name of this class. It is
+// worth noting though, that the navigator.credentials API might be used for any
+// type of credential. Requests for non-passkey credentials are not handled by
+// this feature (with a possible exception of logging metrics).
+class PasskeyJavaScriptFeature : public web::JavaScriptFeature {
+ public:
+  // This feature holds no state, so only a single static instance is ever
+  // needed.
+  static PasskeyJavaScriptFeature* GetInstance();
+
+ private:
+  friend class base::NoDestructor<PasskeyJavaScriptFeature>;
+
+  PasskeyJavaScriptFeature();
+  PasskeyJavaScriptFeature(const PasskeyJavaScriptFeature&) = delete;
+  PasskeyJavaScriptFeature& operator=(const PasskeyJavaScriptFeature&) = delete;
+  ~PasskeyJavaScriptFeature() override;
+
+  // web::JavaScriptFeature:
+  std::optional<std::string> GetScriptMessageHandlerName() const override;
+  void ScriptMessageReceived(web::WebState* web_state,
+                             const web::ScriptMessage& message) override;
+};
+
+#endif  // COMPONENTS_WEBAUTHN_IOS_PASSKEY_JAVA_SCRIPT_FEATURE_H_
diff --git a/components/webauthn/ios/passkey_java_script_feature.mm b/components/webauthn/ios/passkey_java_script_feature.mm
new file mode 100644
index 0000000..fb25865b
--- /dev/null
+++ b/components/webauthn/ios/passkey_java_script_feature.mm
@@ -0,0 +1,89 @@
+// Copyright 2025 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/webauthn/ios/passkey_java_script_feature.h"
+
+#import <optional>
+
+#import "base/metrics/histogram_functions.h"
+#import "base/no_destructor.h"
+#import "base/values.h"
+#import "ios/web/public/js_messaging/java_script_feature_util.h"
+#import "ios/web/public/js_messaging/script_message.h"
+
+namespace {
+
+constexpr char kScriptName[] = "passkey_controller";
+constexpr char kHandlerName[] = "PasskeyInteractionHandler";
+
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused.
+//
+// LINT.IfChange
+enum class WebAuthenticationIOSContentAreaEvent {
+  kGetRequested,
+  kCreateRequested,
+  kMaxValue = kCreateRequested,
+};
+// LINT.ThenChange(//tools/metrics/histograms/metadata/webauthn/enums.xml)
+
+// Logs metrics indicating that an event occurred, with the event type
+// determined by the given string.
+void LogEvent(WebAuthenticationIOSContentAreaEvent event) {
+  base::UmaHistogramEnumeration("WebAuthentication.IOS.ContentAreaEvent",
+                                event);
+}
+
+}  // namespace
+
+// static
+PasskeyJavaScriptFeature* PasskeyJavaScriptFeature::GetInstance() {
+  static base::NoDestructor<PasskeyJavaScriptFeature> instance;
+  return instance.get();
+}
+
+PasskeyJavaScriptFeature::PasskeyJavaScriptFeature()
+    : web::JavaScriptFeature(
+          // This is a shim, so it needs to be in the page content world.
+          web::ContentWorld::kPageContentWorld,
+          {FeatureScript::CreateWithFilename(
+              kScriptName,
+              FeatureScript::InjectionTime::kDocumentStart,
+              // It's valid for passkey flows to happen not in a main frame,
+              // though it requires appropriate permissions policy to be set
+              // (https://w3c.github.io/webauthn/#sctn-permissions-policy).
+              FeatureScript::TargetFrames::kAllFrames,
+              FeatureScript::ReinjectionBehavior::kInjectOncePerWindow)},
+          {web::java_script_features::GetCommonJavaScriptFeature(),
+           web::java_script_features::GetMessageJavaScriptFeature()}) {}
+
+PasskeyJavaScriptFeature::~PasskeyJavaScriptFeature() = default;
+
+std::optional<std::string>
+PasskeyJavaScriptFeature::GetScriptMessageHandlerName() const {
+  return kHandlerName;
+}
+
+void PasskeyJavaScriptFeature::ScriptMessageReceived(
+    web::WebState* web_state,
+    const web::ScriptMessage& message) {
+  base::Value* body = message.body();
+  if (!body || !body->is_dict()) {
+    return;
+  }
+
+  const base::Value::Dict& dict = body->GetDict();
+  const std::string* event = dict.FindString("event");
+  if (!event || event->empty()) {
+    return;
+  }
+
+  if (*event == "getRequested") {
+    LogEvent(WebAuthenticationIOSContentAreaEvent::kGetRequested);
+  } else if (*event == "createRequested") {
+    LogEvent(WebAuthenticationIOSContentAreaEvent::kCreateRequested);
+  }
+
+  // TODO(crbug.com/369629469): Log other types of events.
+}
diff --git a/components/webauthn/ios/resources/passkey_controller.ts b/components/webauthn/ios/resources/passkey_controller.ts
new file mode 100644
index 0000000..7834183
--- /dev/null
+++ b/components/webauthn/ios/resources/passkey_controller.ts
@@ -0,0 +1,52 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Enables passkey-related interactions between the browser and
+ * the renderer by shimming the `navigator.credentials` API.
+ */
+
+import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
+
+// Must be kept in sync with passkey_java_script_feature.mm.
+const HANDLER_NAME = 'PasskeyInteractionHandler';
+
+/**
+ * Caches the existing value of WebKit's navigator.credentials, so that the
+ * calls can be forwarded to it, if needed.
+ */
+const cachedNavigatorCredentials: CredentialsContainer = navigator.credentials;
+
+/**
+ * Chromium-specific implementation of CredentialsContainer.
+ */
+const credentialsContainer: CredentialsContainer = {
+  get: function(options?: CredentialRequestOptions|undefined):
+      Promise<Credential|null> {
+        // Only process WebAuthn requests.
+        if (options?.publicKey) {
+          sendWebKitMessage(HANDLER_NAME, {'event': 'getRequested'});
+        }
+        return cachedNavigatorCredentials.get(options);
+      },
+  create: function(options?: CredentialCreationOptions|undefined):
+      Promise<Credential|null> {
+        // Only process WebAuthn requests.
+        if (options?.publicKey) {
+          sendWebKitMessage(HANDLER_NAME, {'event': 'createRequested'});
+        }
+        return cachedNavigatorCredentials.create(options);
+      },
+  preventSilentAccess: function(): Promise<any> {
+    return cachedNavigatorCredentials.preventSilentAccess();
+  },
+  store: function(credentials?: any): Promise<any> {
+    return cachedNavigatorCredentials.store(credentials);
+  },
+};
+
+// Override the existing value of `navigator.credentials` with our own. The use
+// of Object.defineProperty (versus just doing `navigator.credentials = ...`) is
+// a workaround for the fact that `navigator.credentials` is readonly.
+Object.defineProperty(navigator, 'credentials', {value: credentialsContainer});
diff --git a/components/webcrypto/algorithms/test_helpers.cc b/components/webcrypto/algorithms/test_helpers.cc
index cb408ac..966c7a9 100644
--- a/components/webcrypto/algorithms/test_helpers.cc
+++ b/components/webcrypto/algorithms/test_helpers.cc
@@ -75,10 +75,6 @@
          a.error_details() == b.error_details();
 }
 
-bool operator!=(const Status& a, const Status& b) {
-  return !(a == b);
-}
-
 static std::string ErrorTypeToString(blink::WebCryptoErrorType type) {
   switch (type) {
     case blink::kWebCryptoErrorTypeNotSupported:
diff --git a/components/webcrypto/algorithms/test_helpers.h b/components/webcrypto/algorithms/test_helpers.h
index d85c46e..315e714 100644
--- a/components/webcrypto/algorithms/test_helpers.h
+++ b/components/webcrypto/algorithms/test_helpers.h
@@ -49,7 +49,6 @@
 // webcrypto::Status.
 void PrintTo(const Status& status, ::std::ostream* os);
 bool operator==(const Status& a, const Status& b);
-bool operator!=(const Status& a, const Status& b);
 
 // Gives a human-readable description of |status| and any error it represents.
 std::string StatusToString(const Status& status);
diff --git a/components/webxr/android/java/src/org/chromium/components/webxr/XrSessionCoordinator.java b/components/webxr/android/java/src/org/chromium/components/webxr/XrSessionCoordinator.java
index e470194..d4eca4b 100644
--- a/components/webxr/android/java/src/org/chromium/components/webxr/XrSessionCoordinator.java
+++ b/components/webxr/android/java/src/org/chromium/components/webxr/XrSessionCoordinator.java
@@ -198,6 +198,7 @@
 
         if (needsSeparateActivity) {
             Intent intent = XrHostActivity.createIntent(getApplicationContext());
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             getApplicationContext().startActivity(intent);
         } else {
             XrSessionCoordinatorJni.get()
diff --git a/components/zucchini/encoded_view.h b/components/zucchini/encoded_view.h
index fcc2502a..18996b3 100644
--- a/components/zucchini/encoded_view.h
+++ b/components/zucchini/encoded_view.h
@@ -100,8 +100,6 @@
 
     friend bool operator==(Iterator a, Iterator b) { return a.pos_ == b.pos_; }
 
-    friend bool operator!=(Iterator a, Iterator b) { return !(a == b); }
-
     friend bool operator<(Iterator a, Iterator b) { return a.pos_ < b.pos_; }
 
     friend bool operator>(Iterator a, Iterator b) { return b < a; }
diff --git a/components/zucchini/typed_value.h b/components/zucchini/typed_value.h
index effc5ae7..1cec99f 100644
--- a/components/zucchini/typed_value.h
+++ b/components/zucchini/typed_value.h
@@ -30,12 +30,7 @@
   explicit operator T() const { return value_; }
   const T value() const { return value_; }
 
-  friend bool operator==(const TypedValue& a, const TypedValue& b) {
-    return a.value_ == b.value_;
-  }
-  friend bool operator!=(const TypedValue& a, const TypedValue& b) {
-    return !(a == b);
-  }
+  friend bool operator==(const TypedValue&, const TypedValue&) = default;
   friend bool operator<(const TypedValue& a, const TypedValue& b) {
     return a.value_ < b.value_;
   }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 86e30304..f2a64f8 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -289,7 +289,6 @@
     "//third_party/blink/public/strings",
     "//third_party/boringssl",
     "//third_party/brotli:dec",
-    "//third_party/distributed_point_functions",
     "//third_party/icu",
     "//third_party/inspector_protocol:crdtp",
     "//third_party/libyuv",
diff --git a/content/browser/aggregation_service/DEPS b/content/browser/aggregation_service/DEPS
index 8589af7..4437dd3f9 100644
--- a/content/browser/aggregation_service/DEPS
+++ b/content/browser/aggregation_service/DEPS
@@ -1,5 +1,3 @@
 include_rules = [
   "+components/aggregation_service",
-  "+third_party/distributed_point_functions/shim",
-  "+third_party/distributed_point_functions/dpf/distributed_point_function.pb.h",
 ]
diff --git a/content/browser/aggregation_service/aggregatable_report.cc b/content/browser/aggregation_service/aggregatable_report.cc
index 80580de..70a31eb 100644
--- a/content/browser/aggregation_service/aggregatable_report.cc
+++ b/content/browser/aggregation_service/aggregatable_report.cc
@@ -45,14 +45,9 @@
 #include "third_party/abseil-cpp/absl/numeric/int128.h"
 #include "third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom.h"
 #include "third_party/boringssl/src/include/openssl/hpke.h"
-#include "third_party/distributed_point_functions/shim/buildflags.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
-#if BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-#include "third_party/distributed_point_functions/shim/distributed_point_function_shim.h"
-#endif
-
 namespace content {
 
 namespace {
@@ -63,112 +58,19 @@
 constexpr std::string_view kHistogramValue = "histogram";
 constexpr std::string_view kOperationKey = "operation";
 
-std::vector<GURL> GetDefaultProcessingUrls(
-    blink::mojom::AggregationServiceMode aggregation_mode,
+std::optional<GURL> GetProcessingUrl(
     const std::optional<url::Origin>& aggregation_coordinator_origin) {
-  switch (aggregation_mode) {
-    case blink::mojom::AggregationServiceMode::kTeeBased:
-      if (!aggregation_coordinator_origin.has_value()) {
-        return {GetAggregationServiceProcessingUrl(
-            ::aggregation_service::GetDefaultAggregationCoordinatorOrigin())};
-      }
-      if (!::aggregation_service::IsAggregationCoordinatorOriginAllowed(
-              *aggregation_coordinator_origin)) {
-        return {};
-      }
-      return {
-          GetAggregationServiceProcessingUrl(*aggregation_coordinator_origin)};
-    case blink::mojom::AggregationServiceMode::kExperimentalPoplar:
-      // TODO(crbug.com/40214439): Update default processing urls.
-      return {GURL("https://server1.example"), GURL("https://server2.example")};
+  if (!aggregation_coordinator_origin.has_value()) {
+    return GetAggregationServiceProcessingUrl(
+        ::aggregation_service::GetDefaultAggregationCoordinatorOrigin());
   }
+  if (!::aggregation_service::IsAggregationCoordinatorOriginAllowed(
+          *aggregation_coordinator_origin)) {
+    return std::nullopt;
+  }
+  return GetAggregationServiceProcessingUrl(*aggregation_coordinator_origin);
 }
 
-#if BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-using DpfKey = distributed_point_functions::DpfKey;
-using DpfParameters = distributed_point_functions::DpfParameters;
-
-// Returns parameters that support each possible prefix length in
-// `[1, kBucketDomainBitLength]` with the same element_bitsize of
-// `kValueDomainBitLength`.
-std::vector<DpfParameters> ConstructDpfParameters() {
-  std::vector<DpfParameters> parameters(
-      AggregatableReport::kBucketDomainBitLength);
-  for (size_t i = 0; i < AggregatableReport::kBucketDomainBitLength; i++) {
-    parameters[i].set_log_domain_size(i + 1);
-
-    parameters[i].mutable_value_type()->mutable_integer()->set_bitsize(
-        AggregatableReport::kValueDomainBitLength);
-  }
-
-  return parameters;
-}
-
-// Returns empty vector in case of error.
-std::vector<DpfKey> GenerateDpfKeys(
-    const AggregationServicePayloadContents& contents) {
-  CHECK_EQ(contents.operation,
-           AggregationServicePayloadContents::Operation::kHistogram);
-  CHECK_EQ(contents.aggregation_mode,
-           blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-  CHECK_EQ(contents.contributions.size(), 1u);
-
-  std::optional<std::pair<DpfKey, DpfKey>> maybe_dpf_keys =
-      distributed_point_functions::GenerateKeysIncremental(
-          ConstructDpfParameters(),
-          /*alpha=*/contents.contributions[0].bucket,
-          // We want the same beta, no matter which prefix length is used.
-          /*beta=*/
-          std::vector<absl::uint128>(AggregatableReport::kBucketDomainBitLength,
-                                     contents.contributions[0].value));
-
-  if (!maybe_dpf_keys.has_value()) {
-    return {};
-  }
-
-  std::vector<DpfKey> dpf_keys;
-  dpf_keys.push_back(std::move(maybe_dpf_keys->first));
-  dpf_keys.push_back(std::move(maybe_dpf_keys->second));
-  return dpf_keys;
-}
-
-// Returns a vector with a serialized CBOR map for each processing url. See
-// the AggregatableReport documentation for more detail on the expected format.
-// Returns an empty vector in case of error.
-std::vector<std::vector<uint8_t>>
-ConstructUnencryptedExperimentalPoplarPayloads(
-    const AggregationServicePayloadContents& payload_contents) {
-  std::vector<DpfKey> dpf_keys = GenerateDpfKeys(payload_contents);
-  if (dpf_keys.empty()) {
-    return {};
-  }
-  CHECK_EQ(dpf_keys.size(), 2u);
-
-  std::vector<std::vector<uint8_t>> unencrypted_payloads;
-  for (const DpfKey& dpf_key : dpf_keys) {
-    std::vector<uint8_t> serialized_key(dpf_key.ByteSizeLong());
-    bool succeeded =
-        dpf_key.SerializeToArray(serialized_key.data(), serialized_key.size());
-    CHECK(succeeded);
-
-    cbor::Value::MapValue value;
-    value.emplace(kOperationKey, kHistogramValue);
-    value.emplace("dpf_key", std::move(serialized_key));
-
-    std::optional<std::vector<uint8_t>> unencrypted_payload =
-        cbor::Writer::Write(cbor::Value(std::move(value)));
-
-    if (!unencrypted_payload.has_value()) {
-      return {};
-    }
-
-    unencrypted_payloads.push_back(std::move(unencrypted_payload.value()));
-  }
-
-  return unencrypted_payloads;
-}
-#endif  // BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-
 // TODO(crbug.com/40215445): Replace with `base/numerics/byte_conversions.h` if
 // available.
 std::array<uint8_t, 16u> U128ToBigEndian(absl::uint128 integer) {
@@ -212,7 +114,7 @@
 // Returns a serialized CBOR map. See the `AggregatableReport` documentation for
 // more detail on the expected format. Returns `std::nullopt` if serialization
 // fails.
-std::optional<std::vector<uint8_t>> ConstructUnencryptedTeeBasedPayload(
+std::optional<std::vector<uint8_t>> ConstructUnencryptedPayload(
     const AggregationServicePayloadContents& payload_contents) {
   cbor::Value::MapValue value;
   value.emplace(kOperationKey, kHistogramValue);
@@ -259,11 +161,11 @@
   return std::nullopt;
 }
 
-// Computes the length in bytes of a TEE-based payload's plaintext CBOR
-// serialization. Returns `std::nullopt` if the computation would overflow or if
+// Computes the length in bytes of a payload's plaintext CBOR serialization.
+// Returns `std::nullopt` if the computation would overflow or if
 // `num_contributions` exceeds the maximum value of `uint32_t`. See
 // `AggregatableReport::AggregationServicePayload` for the format's definition.
-constexpr std::optional<size_t> ComputeTeeBasedPayloadLengthInBytes(
+constexpr std::optional<size_t> ComputePayloadLengthInBytes(
     size_t num_contributions,
     size_t filtering_id_max_bytes) {
   constexpr base::CheckedNumeric<size_t> kPayloadLenBeforeArray{
@@ -326,19 +228,6 @@
         /*value=*/contribution_proto.value(), filtering_id);
   }
 
-  blink::mojom::AggregationServiceMode aggregation_mode =
-      blink::mojom::AggregationServiceMode::kTeeBased;
-  switch (proto.aggregation_mode()) {
-    case proto::AggregationServiceMode::TEE_BASED:
-      break;
-    case proto::AggregationServiceMode::EXPERIMENTAL_POPLAR:
-      aggregation_mode =
-          blink::mojom::AggregationServiceMode::kExperimentalPoplar;
-      break;
-    default:
-      return std::nullopt;
-  }
-
   std::optional<url::Origin> aggregation_coordinator_origin;
   if (proto.has_aggregation_coordinator_origin()) {
     aggregation_coordinator_origin =
@@ -361,7 +250,7 @@
   }
 
   return AggregationServicePayloadContents(
-      operation, std::move(contributions), aggregation_mode,
+      operation, std::move(contributions),
       std::move(aggregation_coordinator_origin), max_contributions_allowed,
       filtering_id_max_bytes);
 }
@@ -466,16 +355,6 @@
     }
   }
 
-  switch (payload_contents.aggregation_mode) {
-    case blink::mojom::AggregationServiceMode::kTeeBased:
-      out->set_aggregation_mode(proto::AggregationServiceMode::TEE_BASED);
-      break;
-    case blink::mojom::AggregationServiceMode::kExperimentalPoplar:
-      out->set_aggregation_mode(
-          proto::AggregationServiceMode::EXPERIMENTAL_POPLAR);
-      break;
-  }
-
   if (payload_contents.aggregation_coordinator_origin.has_value()) {
     out->set_aggregation_coordinator_origin(
         payload_contents.aggregation_coordinator_origin->Serialize());
@@ -570,13 +449,11 @@
     Operation operation,
     std::vector<blink::mojom::AggregatableReportHistogramContribution>
         contributions,
-    blink::mojom::AggregationServiceMode aggregation_mode,
     std::optional<url::Origin> aggregation_coordinator_origin,
     base::StrictNumeric<size_t> max_contributions_allowed,
     size_t filtering_id_max_bytes)
     : operation(operation),
       contributions(std::move(contributions)),
-      aggregation_mode(aggregation_mode),
       aggregation_coordinator_origin(std::move(aggregation_coordinator_origin)),
       max_contributions_allowed(max_contributions_allowed),
       filtering_id_max_bytes(filtering_id_max_bytes) {}
@@ -669,19 +546,22 @@
     std::optional<uint64_t> debug_key,
     base::flat_map<std::string, std::string> additional_fields,
     int failed_send_attempts) {
-  std::vector<GURL> processing_urls =
-      GetDefaultProcessingUrls(payload_contents.aggregation_mode,
-                               payload_contents.aggregation_coordinator_origin);
-  return CreateInternal(std::move(processing_urls), std::move(payload_contents),
-                        std::move(shared_info), delay_type,
-                        std::move(reporting_path), debug_key,
-                        std::move(additional_fields), failed_send_attempts);
+  if (std::optional<GURL> processing_url =
+          GetProcessingUrl(payload_contents.aggregation_coordinator_origin);
+      processing_url.has_value()) {
+    return CreateInternal(*std::move(processing_url),
+                          std::move(payload_contents), std::move(shared_info),
+                          delay_type, std::move(reporting_path), debug_key,
+                          std::move(additional_fields), failed_send_attempts);
+  }
+
+  return std::nullopt;
 }
 
 // static
 std::optional<AggregatableReportRequest>
 AggregatableReportRequest::CreateForTesting(
-    std::vector<GURL> processing_urls,
+    GURL processing_url,
     AggregationServicePayloadContents payload_contents,
     AggregatableReportSharedInfo shared_info,
     std::optional<AggregatableReportRequest::DelayType> delay_type,
@@ -689,7 +569,7 @@
     std::optional<uint64_t> debug_key,
     base::flat_map<std::string, std::string> additional_fields,
     int failed_send_attempts) {
-  return CreateInternal(std::move(processing_urls), std::move(payload_contents),
+  return CreateInternal(std::move(processing_url), std::move(payload_contents),
                         std::move(shared_info), delay_type,
                         std::move(reporting_path), debug_key,
                         std::move(additional_fields), failed_send_attempts);
@@ -698,7 +578,7 @@
 // static
 std::optional<AggregatableReportRequest>
 AggregatableReportRequest::CreateInternal(
-    std::vector<GURL> processing_urls,
+    GURL processing_url,
     AggregationServicePayloadContents payload_contents,
     AggregatableReportSharedInfo shared_info,
     std::optional<AggregatableReportRequest::DelayType> delay_type,
@@ -706,22 +586,8 @@
     std::optional<uint64_t> debug_key,
     base::flat_map<std::string, std::string> additional_fields,
     int failed_send_attempts) {
-  if (!AggregatableReport::IsNumberOfProcessingUrlsValid(
-          processing_urls.size(), payload_contents.aggregation_mode)) {
-    DVLOG(1) << "Invalid number of processing URLs";
-    return std::nullopt;
-  }
-
-  if (!std::ranges::all_of(processing_urls,
-                           network::IsUrlPotentiallyTrustworthy)) {
-    DVLOG(1) << "Not all processing URLs are potentially trustworthy";
-    return std::nullopt;
-  }
-
-  if (!AggregatableReport::IsNumberOfHistogramContributionsValid(
-          payload_contents.contributions.size(),
-          payload_contents.aggregation_mode)) {
-    DVLOG(1) << "Invalid number of contributions";
+  if (!network::IsUrlPotentiallyTrustworthy(processing_url)) {
+    DVLOG(1) << "Processing URL is not potentially trustworthy";
     return std::nullopt;
   }
 
@@ -770,18 +636,14 @@
     return std::nullopt;
   }
 
-  // Ensure the ordering of urls is deterministic. This is required for
-  // AggregatableReport construction later.
-  std::ranges::sort(processing_urls);
-
   return AggregatableReportRequest(
-      std::move(processing_urls), std::move(payload_contents),
+      std::move(processing_url), std::move(payload_contents),
       std::move(shared_info), delay_type, std::move(reporting_path), debug_key,
       std::move(additional_fields), failed_send_attempts);
 }
 
 AggregatableReportRequest::AggregatableReportRequest(
-    std::vector<GURL> processing_urls,
+    GURL processing_url,
     AggregationServicePayloadContents payload_contents,
     AggregatableReportSharedInfo shared_info,
     std::optional<AggregatableReportRequest::DelayType> delay_type,
@@ -789,7 +651,7 @@
     std::optional<uint64_t> debug_key,
     base::flat_map<std::string, std::string> additional_fields,
     int failed_send_attempts)
-    : processing_urls_(std::move(processing_urls)),
+    : processing_url_(std::move(processing_url)),
       payload_contents_(std::move(payload_contents)),
       shared_info_(std::move(shared_info)),
       reporting_path_(std::move(reporting_path)),
@@ -859,12 +721,12 @@
     default;
 
 AggregatableReport::AggregatableReport(
-    std::vector<AggregationServicePayload> payloads,
+    std::optional<AggregationServicePayload> payload,
     std::string shared_info,
     std::optional<uint64_t> debug_key,
     base::flat_map<std::string, std::string> additional_fields,
     std::optional<url::Origin> aggregation_coordinator_origin)
-    : payloads_(std::move(payloads)),
+    : payload_(std::move(payload)),
       shared_info_(std::move(shared_info)),
       debug_key_(debug_key),
       additional_fields_(std::move(additional_fields)),
@@ -897,58 +759,23 @@
 AggregatableReport::Provider::~Provider() = default;
 
 std::optional<AggregatableReport>
-AggregatableReport::Provider::CreateFromRequestAndPublicKeys(
+AggregatableReport::Provider::CreateFromRequestAndPublicKey(
     const AggregatableReportRequest& report_request,
-    std::vector<PublicKey> public_keys) const {
-  const size_t num_processing_urls = public_keys.size();
-  CHECK_EQ(num_processing_urls, report_request.processing_urls().size());
-
-  // The urls must be sorted so we can ensure the ordering (and assignment of
-  // DpfKey parties for the `kExperimentalPoplar` aggregation mode) is
-  // deterministic.
-  CHECK(std::ranges::is_sorted(report_request.processing_urls()));
-
-  std::vector<std::vector<uint8_t>> unencrypted_payloads;
-
-  switch (report_request.payload_contents().aggregation_mode) {
-    case blink::mojom::AggregationServiceMode::kTeeBased: {
-      std::optional<std::vector<uint8_t>> payload =
-          ConstructUnencryptedTeeBasedPayload(
-              report_request.payload_contents());
-      if (!payload.has_value()) {
-        return std::nullopt;
-      }
-
-      // Validate that the payload length is a deterministic function of
-      // `max_contributions_allowed` and `filtering_id_max_bytes`.
-      const size_t expected_payload_length =
-          ComputeTeeBasedPayloadLengthInBytes(
-              report_request.payload_contents().max_contributions_allowed,
-              report_request.payload_contents().filtering_id_max_bytes)
-              .value();
-      CHECK_EQ(payload->size(), expected_payload_length);
-
-      unencrypted_payloads.emplace_back(*std::move(payload));
-      break;
-    }
-    case blink::mojom::AggregationServiceMode::kExperimentalPoplar: {
-#if BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-      unencrypted_payloads = ConstructUnencryptedExperimentalPoplarPayloads(
-          report_request.payload_contents());
-
-      if (unencrypted_payloads.empty()) {
-        return std::nullopt;
-      }
-      break;
-#else
-      LOG(WARNING)
-          << "Cannot create AggregatableReport for kExperimentalPoplar because "
-             "Chrome was compiled with use_distributed_point_functions=false";
-      return std::nullopt;
-#endif  // BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-    }
+    PublicKey public_key) const {
+  std::optional<std::vector<uint8_t>> unencrypted_payload =
+      ConstructUnencryptedPayload(report_request.payload_contents());
+  if (!unencrypted_payload.has_value()) {
+    return std::nullopt;
   }
-  CHECK(!unencrypted_payloads.empty());
+
+  // Validate that the payload length is a deterministic function of
+  // `max_contributions_allowed` and `filtering_id_max_bytes`.
+  const size_t expected_payload_length =
+      ComputePayloadLengthInBytes(
+          report_request.payload_contents().max_contributions_allowed,
+          report_request.payload_contents().filtering_id_max_bytes)
+          .value();
+  CHECK_EQ(unencrypted_payload->size(), expected_payload_length);
 
   std::string encoded_shared_info =
       report_request.shared_info().SerializeAsJson();
@@ -958,35 +785,30 @@
   base::span<const uint8_t> authenticated_info =
       base::as_byte_span(authenticated_info_str);
 
-  std::vector<AggregatableReport::AggregationServicePayload> encrypted_payloads;
-  CHECK_EQ(unencrypted_payloads.size(), num_processing_urls);
-  for (size_t i = 0; i < num_processing_urls; ++i) {
-    std::vector<uint8_t> encrypted_payload =
-        g_disable_encryption_for_testing_tool_
-            ? unencrypted_payloads[i]
-            : EncryptAggregatableReportPayloadWithHpke(
-                  /*report_payload_plaintext=*/unencrypted_payloads[i],
-                  /*public_key=*/public_keys[i].key,
-                  /*report_authenticated_info=*/authenticated_info);
+  std::vector<uint8_t> encrypted_payload =
+      g_disable_encryption_for_testing_tool_
+          ? *unencrypted_payload
+          : EncryptAggregatableReportPayloadWithHpke(
+                /*report_payload_plaintext=*/*unencrypted_payload,
+                /*public_key=*/public_key.key,
+                /*report_authenticated_info=*/authenticated_info);
 
-    if (encrypted_payload.empty()) {
-      return std::nullopt;
-    }
+  if (encrypted_payload.empty()) {
+    return std::nullopt;
+  }
 
-    std::optional<std::vector<uint8_t>> debug_cleartext_payload;
-    if (report_request.shared_info().debug_mode ==
-        AggregatableReportSharedInfo::DebugMode::kEnabled) {
-      debug_cleartext_payload = std::move(unencrypted_payloads[i]);
-    }
-
-    encrypted_payloads.emplace_back(std::move(encrypted_payload),
-                                    std::move(public_keys[i]).id,
-                                    std::move(debug_cleartext_payload));
+  std::optional<std::vector<uint8_t>> debug_cleartext_payload;
+  if (report_request.shared_info().debug_mode ==
+      AggregatableReportSharedInfo::DebugMode::kEnabled) {
+    debug_cleartext_payload = *std::move(unencrypted_payload);
   }
 
   return AggregatableReport(
-      std::move(encrypted_payloads), std::move(encoded_shared_info),
-      report_request.debug_key(), report_request.additional_fields(),
+      AggregationServicePayload(std::move(encrypted_payload),
+                                std::move(public_key).id,
+                                std::move(debug_cleartext_payload)),
+      std::move(encoded_shared_info), report_request.debug_key(),
+      report_request.additional_fields(),
       report_request.payload_contents().aggregation_coordinator_origin);
 }
 
@@ -995,24 +817,20 @@
 
   value.Set("shared_info", shared_info_);
 
-  // When invoked for reports being shown in the WebUI, `payloads_` may be empty
-  // prior to assembly or if assembly failed.
-  if (!payloads_.empty()) {
-    base::Value::List payloads_list_value;
-    for (const AggregationServicePayload& payload : payloads_) {
-      base::Value::Dict payload_dict_value;
-      payload_dict_value.Set("payload", base::Base64Encode(payload.payload));
-      payload_dict_value.Set("key_id", payload.key_id);
-      if (payload.debug_cleartext_payload.has_value()) {
-        payload_dict_value.Set(
-            "debug_cleartext_payload",
-            base::Base64Encode(payload.debug_cleartext_payload.value()));
-      }
-
-      payloads_list_value.Append(std::move(payload_dict_value));
+  // When invoked for reports being shown in the WebUI, `payload_` may be
+  // `std::nullopt` prior to assembly or if assembly failed.
+  if (payload_.has_value()) {
+    base::Value::Dict payload_dict_value;
+    payload_dict_value.Set("payload", base::Base64Encode(payload_->payload));
+    payload_dict_value.Set("key_id", payload_->key_id);
+    if (payload_->debug_cleartext_payload.has_value()) {
+      payload_dict_value.Set(
+          "debug_cleartext_payload",
+          base::Base64Encode(payload_->debug_cleartext_payload.value()));
     }
 
-    value.Set("aggregation_service_payloads", std::move(payloads_list_value));
+    value.Set("aggregation_service_payloads",
+              base::Value::List().Append(std::move(payload_dict_value)));
   }
 
   if (debug_key_.has_value()) {
@@ -1036,44 +854,17 @@
 }
 
 // static
-bool AggregatableReport::IsNumberOfProcessingUrlsValid(
-    size_t number,
-    blink::mojom::AggregationServiceMode aggregation_mode) {
-  switch (aggregation_mode) {
-    case blink::mojom::AggregationServiceMode::kTeeBased:
-      return number == 1u;
-    case blink::mojom::AggregationServiceMode::kExperimentalPoplar:
-      return number == 2u;
-  }
-}
-
-// static
-bool AggregatableReport::IsNumberOfHistogramContributionsValid(
-    size_t number,
-    blink::mojom::AggregationServiceMode aggregation_mode) {
-  // Note: APIs using the aggregation service may impose their own limits.
-  switch (aggregation_mode) {
-    case blink::mojom::AggregationServiceMode::kTeeBased:
-      return true;
-    case blink::mojom::AggregationServiceMode::kExperimentalPoplar:
-      return number == 1u;
-  }
-}
-
-// static
 std::optional<std::vector<uint8_t>>
-AggregatableReport::SerializeTeeBasedPayloadForTesting(
+AggregatableReport::SerializePayloadForTesting(
     const AggregationServicePayloadContents& payload_contents) {
-  return ConstructUnencryptedTeeBasedPayload(payload_contents);
+  return ConstructUnencryptedPayload(payload_contents);
 }
 
 // static
-std::optional<size_t>
-AggregatableReport::ComputeTeeBasedPayloadLengthInBytesForTesting(
+std::optional<size_t> AggregatableReport::ComputePayloadLengthInBytesForTesting(
     size_t num_contributions,
     size_t filtering_id_max_bytes) {
-  return ComputeTeeBasedPayloadLengthInBytes(num_contributions,
-                                             filtering_id_max_bytes);
+  return ComputePayloadLengthInBytes(num_contributions, filtering_id_max_bytes);
 }
 
 std::vector<uint8_t> EncryptAggregatableReportPayloadWithHpke(
diff --git a/content/browser/aggregation_service/aggregatable_report.h b/content/browser/aggregation_service/aggregatable_report.h
index 3d2c381..aa963c38 100644
--- a/content/browser/aggregation_service/aggregatable_report.h
+++ b/content/browser/aggregation_service/aggregatable_report.h
@@ -53,7 +53,6 @@
       Operation operation,
       std::vector<blink::mojom::AggregatableReportHistogramContribution>
           contributions,
-      blink::mojom::AggregationServiceMode aggregation_mode,
       std::optional<url::Origin> aggregation_coordinator_origin,
       base::StrictNumeric<size_t> max_contributions_allowed,
       size_t filtering_id_max_bytes);
@@ -70,7 +69,6 @@
   Operation operation;
   std::vector<blink::mojom::AggregatableReportHistogramContribution>
       contributions;
-  blink::mojom::AggregationServiceMode aggregation_mode;
   std::optional<url::Origin> aggregation_coordinator_origin;
   size_t max_contributions_allowed;
   size_t filtering_id_max_bytes;
@@ -139,8 +137,8 @@
 
     // This payload is constructed using the data in the
     // AggregationServicePayloadContents and then encrypted with one of
-    // `url`'s public keys. For the `kTeeBased` aggregation mode, the plaintext
-    // of the encrypted payload is a serialized CBOR map structured as follows:
+    // `url`'s public keys. The plaintext of the encrypted payload is a
+    // serialized CBOR map structured as follows:
     // {
     //   "operation": "<chosen operation as string>",
     //   "data": [{
@@ -148,10 +146,6 @@
     //     "value": <a 4-byte (i.e. 32-bit) big-endian bytestring>
     //   }, ...],
     // }
-    // Note that the "data" array may contain multiple contributions.
-    // For the `kExperimentalPoplar` aggregation mode, the "data" field is
-    // replaced with:
-    //   "dpf_key": <binary serialization of the DPF key>
     std::vector<uint8_t> payload;
 
     // Indicates the chosen encryption key.
@@ -162,18 +156,17 @@
     std::optional<std::vector<uint8_t>> debug_cleartext_payload;
   };
 
-  // Used to allow mocking `CreateFromRequestAndPublicKeys()` in tests.
+  // Used to allow mocking `CreateFromRequestAndPublicKey()` in tests.
   class CONTENT_EXPORT Provider {
    public:
     virtual ~Provider();
 
     // Processes and serializes the information in `report_request` and encrypts
-    // using the `public_keys` as necessary. The order of `public_keys` should
-    // correspond to `report_request.processing_urls`, which should be
-    // sorted. Returns `std::nullopt` if an error occurred during construction.
-    virtual std::optional<AggregatableReport> CreateFromRequestAndPublicKeys(
+    // using the `public_key` as necessary. Returns `std::nullopt` if an error
+    // occurred during construction.
+    virtual std::optional<AggregatableReport> CreateFromRequestAndPublicKey(
         const AggregatableReportRequest& report_request,
-        std::vector<PublicKey> public_keys) const;
+        PublicKey public_key) const;
 
     // Sets whether to disable encryption of the payload(s). Should only be used
     // by the AggregationServiceTool.
@@ -197,7 +190,7 @@
   static constexpr std::string_view kDomainSeparationPrefix =
       "aggregation_service";
 
-  AggregatableReport(std::vector<AggregationServicePayload> payloads,
+  AggregatableReport(std::optional<AggregationServicePayload> payload,
                      std::string shared_info,
                      std::optional<uint64_t> debug_key,
                      base::flat_map<std::string, std::string> additional_fields,
@@ -208,8 +201,8 @@
   AggregatableReport& operator=(AggregatableReport&& other);
   ~AggregatableReport();
 
-  const std::vector<AggregationServicePayload>& payloads() const {
-    return payloads_;
+  const std::optional<AggregationServicePayload>& payload() const {
+    return payload_;
   }
   std::string_view shared_info() const { return shared_info_; }
   std::optional<uint64_t> debug_key() const { return debug_key_; }
@@ -227,10 +220,6 @@
   //     {
   //       "payload": "<base64 encoded encrypted data>",
   //       "key_id": "<string identifying public key used>"
-  //     },
-  //     {
-  //       "payload": "<base64 encoded encrypted data>",
-  //       "key_id": "<string identifying public key used>"
   //     }
   //   ]
   // }
@@ -257,30 +246,17 @@
   // TODO(crbug.com/40196851): Expose static method to validate that a
   // base::Value appears to represent a valid report.
 
-  // Returns whether `number` is a valid number of processing URLs for the
-  // `aggregation_mode`.
-  static bool IsNumberOfProcessingUrlsValid(
-      size_t number,
-      blink::mojom::AggregationServiceMode aggregation_mode);
-
-  // Returns whether `number` is a valid number of histogram contributions for
-  // the `aggregation_mode`.
-  static bool IsNumberOfHistogramContributionsValid(
-      size_t number,
-      blink::mojom::AggregationServiceMode aggregation_mode);
-
-  static std::optional<std::vector<uint8_t>> SerializeTeeBasedPayloadForTesting(
+  static std::optional<std::vector<uint8_t>> SerializePayloadForTesting(
       const AggregationServicePayloadContents& payload_contents);
 
-  static std::optional<size_t> ComputeTeeBasedPayloadLengthInBytesForTesting(
+  static std::optional<size_t> ComputePayloadLengthInBytesForTesting(
       size_t num_contributions,
       size_t filtering_id_max_bytes);
 
  private:
-  // This vector should have an entry for each processing URL specified in
-  // the original AggregatableReportRequest. Might be empty for reports created
-  // for the WebUI if prior to assembly or if assembly failed.
-  std::vector<AggregationServicePayload> payloads_;
+  // Might be `std::nullopt` for reports created for the WebUI if prior to
+  // assembly or if assembly failed.
+  std::optional<AggregationServicePayload> payload_;
 
   std::string shared_info_;
 
@@ -325,10 +301,6 @@
 
   // Returns `std::nullopt` if any of the following are true:
   //
-  //   * The number of contributions within `payload_contents` is invalid for
-  //     the `payload_contents.aggregation_mode` (see
-  //     `IsNumberOfHistogramContributionsValid()`).
-  //
   //   * `payload_contents.max_contributions_allowed` is less than the number of
   //     contributions.
   //
@@ -359,10 +331,8 @@
       int failed_send_attempts = 0);
 
   // Returns `std:nullopt` whenever `Create()` would for that condition too.
-  // Also returns `std::nullopt` if `processing_url.size()` is not valid for the
-  // `payload_contents.aggregation_mode` (see `IsNumberOfProcessingUrlsValid`).
   static std::optional<AggregatableReportRequest> CreateForTesting(
-      std::vector<GURL> processing_urls,
+      GURL processing_url,
       AggregationServicePayloadContents payload_contents,
       AggregatableReportSharedInfo shared_info,
       std::optional<AggregatableReportRequest::DelayType> delay_type =
@@ -382,7 +352,7 @@
   AggregatableReportRequest& operator=(AggregatableReportRequest&& other);
   ~AggregatableReportRequest();
 
-  const std::vector<GURL>& processing_urls() const { return processing_urls_; }
+  const GURL& processing_url() const { return processing_url_; }
   const AggregationServicePayloadContents& payload_contents() const {
     return payload_contents_;
   }
@@ -408,7 +378,7 @@
 
  private:
   static std::optional<AggregatableReportRequest> CreateInternal(
-      std::vector<GURL> processing_urls,
+      GURL processing_url,
       AggregationServicePayloadContents payload_contents,
       AggregatableReportSharedInfo shared_info,
       std::optional<AggregatableReportRequest::DelayType> delay_type,
@@ -418,7 +388,7 @@
       int failed_send_attempts);
 
   AggregatableReportRequest(
-      std::vector<GURL> processing_urls,
+      GURL processing_url,
       AggregationServicePayloadContents payload_contents,
       AggregatableReportSharedInfo shared_info,
       std::optional<AggregatableReportRequest::DelayType> delay_type,
@@ -427,7 +397,7 @@
       base::flat_map<std::string, std::string> additional_fields,
       int failed_send_attempts);
 
-  std::vector<GURL> processing_urls_;
+  GURL processing_url_;
   AggregationServicePayloadContents payload_contents_;
   AggregatableReportSharedInfo shared_info_;
 
diff --git a/content/browser/aggregation_service/aggregatable_report_assembler.cc b/content/browser/aggregation_service/aggregatable_report_assembler.cc
index 2920dec4..0a734182 100644
--- a/content/browser/aggregation_service/aggregatable_report_assembler.cc
+++ b/content/browser/aggregation_service/aggregatable_report_assembler.cc
@@ -8,7 +8,6 @@
 #include <memory>
 #include <optional>
 #include <utility>
-#include <vector>
 
 #include "base/check.h"
 #include "base/check_op.h"
@@ -72,11 +71,8 @@
 
 AggregatableReportAssembler::PendingRequest::PendingRequest(
     AggregatableReportRequest report_request,
-    AggregatableReportAssembler::AssemblyCallback callback,
-    size_t num_processing_urls)
-    : report_request(std::move(report_request)),
-      callback(std::move(callback)),
-      processing_url_keys(num_processing_urls) {
+    AggregatableReportAssembler::AssemblyCallback callback)
+    : report_request(std::move(report_request)), callback(std::move(callback)) {
   CHECK(this->callback);
 }
 
@@ -111,11 +107,6 @@
 void AggregatableReportAssembler::AssembleReport(
     AggregatableReportRequest report_request,
     AssemblyCallback callback) {
-  CHECK(std::ranges::is_sorted(report_request.processing_urls()));
-  const size_t num_processing_urls = report_request.processing_urls().size();
-  CHECK(AggregatableReport::IsNumberOfProcessingUrlsValid(
-      num_processing_urls, report_request.payload_contents().aggregation_mode));
-
   const AggregationServicePayloadContents& contents =
       report_request.payload_contents();
 
@@ -137,22 +128,18 @@
   const PendingRequest& pending_request =
       pending_requests_
           .emplace(id, PendingRequest(std::move(report_request),
-                                      std::move(callback), num_processing_urls))
+                                      std::move(callback)))
           .first->second;
 
-  for (size_t i = 0; i < num_processing_urls; ++i) {
-    // `fetcher_` is owned by `this`, so `base::Unretained()` is safe.
-    fetcher_->GetPublicKey(
-        pending_request.report_request.processing_urls()[i],
-        base::BindOnce(&AggregatableReportAssembler::OnPublicKeyFetched,
-                       base::Unretained(this), /*report_id=*/id,
-                       /*processing_url_index=*/i));
-  }
+  // `fetcher_` is owned by `this`, so `base::Unretained()` is safe.
+  fetcher_->GetPublicKey(
+      pending_request.report_request.processing_url(),
+      base::BindOnce(&AggregatableReportAssembler::OnPublicKeyFetched,
+                     base::Unretained(this), /*report_id=*/id));
 }
 
 void AggregatableReportAssembler::OnPublicKeyFetched(
     int64_t report_id,
-    size_t processing_url_index,
     std::optional<PublicKey> key,
     AggregationServiceKeyFetcher::PublicKeyFetchStatus status) {
   CHECK_EQ(key.has_value(),
@@ -164,36 +151,19 @@
 
   // TODO(crbug.com/40199738): Consider implementing some retry logic.
 
-  ++pending_request.num_returned_key_fetches;
-  pending_request.processing_url_keys[processing_url_index] = std::move(key);
+  if (!key.has_value()) {
+    RecordAssemblyStatus(AssemblyStatus::kPublicKeyFetchFailed);
 
-  if (pending_request.num_returned_key_fetches ==
-      pending_request.report_request.processing_urls().size()) {
-    OnAllPublicKeysFetched(report_id, pending_request);
-  }
-}
-
-void AggregatableReportAssembler::OnAllPublicKeysFetched(
-    int64_t report_id,
-    PendingRequest& pending_request) {
-  std::vector<PublicKey> public_keys;
-  for (std::optional<PublicKey> elem : pending_request.processing_url_keys) {
-    if (!elem.has_value()) {
-      RecordAssemblyStatus(AssemblyStatus::kPublicKeyFetchFailed);
-
-      std::move(pending_request.callback)
-          .Run(std::move(pending_request.report_request), std::nullopt,
-               AssemblyStatus::kPublicKeyFetchFailed);
-      pending_requests_.erase(report_id);
-      return;
-    }
-
-    public_keys.push_back(std::move(elem.value()));
+    std::move(pending_request.callback)
+        .Run(std::move(pending_request.report_request), std::nullopt,
+             AssemblyStatus::kPublicKeyFetchFailed);
+    pending_requests_.erase(report_id);
+    return;
   }
 
   std::optional<AggregatableReport> assembled_report =
-      report_provider_->CreateFromRequestAndPublicKeys(
-          pending_request.report_request, std::move(public_keys));
+      report_provider_->CreateFromRequestAndPublicKey(
+          pending_request.report_request, *std::move(key));
   AssemblyStatus assembly_status =
       assembled_report ? AssemblyStatus::kOk : AssemblyStatus::kAssemblyFailed;
   RecordAssemblyStatus(assembly_status);
diff --git a/content/browser/aggregation_service/aggregatable_report_assembler.h b/content/browser/aggregation_service/aggregatable_report_assembler.h
index b80d294..5d91cf3 100644
--- a/content/browser/aggregation_service/aggregatable_report_assembler.h
+++ b/content/browser/aggregation_service/aggregatable_report_assembler.h
@@ -10,7 +10,6 @@
 
 #include <memory>
 #include <optional>
-#include <vector>
 
 #include "base/containers/flat_map.h"
 #include "base/functional/callback.h"
@@ -98,8 +97,7 @@
   // Represents a request to assemble a report that has not completed.
   struct PendingRequest {
     PendingRequest(AggregatableReportRequest report_request,
-                   AssemblyCallback callback,
-                   size_t num_processing_urls);
+                   AssemblyCallback callback);
     // Move-only.
     PendingRequest(PendingRequest&& other);
     PendingRequest& operator=(PendingRequest&& other);
@@ -107,15 +105,6 @@
 
     AggregatableReportRequest report_request;
     AssemblyCallback callback;
-
-    // How many key fetches for this request have returned, including errors.
-    size_t num_returned_key_fetches = 0;
-
-    // The PublicKey returned for each key fetch request. Indices correspond to
-    // the ordering of `report_request.processing_urls`. Each element is
-    // `std::nullopt` if that key fetch either has not yet returned or has
-    // returned an error.
-    std::vector<std::optional<PublicKey>> processing_url_keys;
   };
 
   AggregatableReportAssembler(
@@ -123,22 +112,12 @@
       std::unique_ptr<AggregatableReport::Provider> report_provider);
 
   // Called when a result is returned from the key fetcher. Handles throwing
-  // errors on a failed fetch, waiting for both results to return and calling
-  // into `OnAllPublicKeysFetched()` when appropriate. `processing_url_index` is
-  // an index into the corresponding AggregatableReportRequest's
-  // `processing_urls` vector, indicating which URL this fetch is for.
+  // errors on a failed fetch.
   void OnPublicKeyFetched(
       int64_t report_id,
-      size_t processing_url_index,
       std::optional<PublicKey> key,
       AggregationServiceKeyFetcher::PublicKeyFetchStatus status);
 
-  // Call when all results have been returned from the key fetcher. Handles
-  // calling into `AssembleReportUsingKeys()` when appropriate and returning
-  // any assembled report or throwing an error if assembly fails.
-  void OnAllPublicKeysFetched(int64_t report_id,
-                              PendingRequest& pending_request);
-
   // Keyed by a token for easier lookup.
   base::flat_map<int64_t, PendingRequest> pending_requests_;
 
diff --git a/content/browser/aggregation_service/aggregatable_report_assembler_unittest.cc b/content/browser/aggregation_service/aggregatable_report_assembler_unittest.cc
index c56a4db..a63b9169 100644
--- a/content/browser/aggregation_service/aggregatable_report_assembler_unittest.cc
+++ b/content/browser/aggregation_service/aggregatable_report_assembler_unittest.cc
@@ -24,7 +24,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom.h"
-#include "third_party/distributed_point_functions/shim/buildflags.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -51,7 +50,7 @@
                                  AggregatableReport report) {
   return [out, report = std::move(report)](
              const AggregatableReportRequest& report_request,
-             std::vector<PublicKey> public_keys) {
+             PublicKey public_key) {
     *out = aggregation_service::CloneReportRequest(report_request);
     return std::move(report);
   };
@@ -72,8 +71,8 @@
 class MockAggregatableReportProvider : public AggregatableReport::Provider {
  public:
   MOCK_METHOD(std::optional<AggregatableReport>,
-              CreateFromRequestAndPublicKeys,
-              (const AggregatableReportRequest&, std::vector<PublicKey>),
+              CreateFromRequestAndPublicKey,
+              (const AggregatableReportRequest&, PublicKey),
               (const, override));
 };
 
@@ -114,145 +113,18 @@
   base::MockCallback<AssemblyCallback> callback_;
 };
 
-TEST_F(AggregatableReportAssemblerTest, BothKeyFetchesFail_ErrorReturned) {
+TEST_F(AggregatableReportAssemblerTest, KeyFetchSucceeds_ValidReportReturned) {
   base::HistogramTester histograms;
 
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-  std::vector<GURL> processing_urls = request.processing_urls();
-
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[0], _))
-      .WillOnce(base::test::RunOnceCallback<1>(
-          std::nullopt, PublicKeyFetchStatus::kPublicKeyFetchFailed));
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[1], _))
-      .WillOnce(base::test::RunOnceCallback<1>(
-          std::nullopt, PublicKeyFetchStatus::kPublicKeyFetchFailed));
-  EXPECT_CALL(callback(),
-              Run(_, Eq(std::nullopt), AssemblyStatus::kPublicKeyFetchFailed));
-
-  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKeys(_, _))
-      .Times(0);
-
-  assembler()->AssembleReport(std::move(request), callback().Get());
-
-  histograms.ExpectUniqueSample(
-      kReportAssemblerStatusHistogramName,
-      AggregatableReportAssembler::AssemblyStatus::kPublicKeyFetchFailed, 1);
-}
-
-TEST_F(AggregatableReportAssemblerTest, FirstKeyFetchFails_ErrorReturned) {
-  base::HistogramTester histograms;
-
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-  std::vector<GURL> processing_urls = request.processing_urls();
-
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[0], _))
-      .WillOnce(base::test::RunOnceCallback<1>(
-          std::nullopt, PublicKeyFetchStatus::kPublicKeyFetchFailed));
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[1], _))
-      .WillOnce(base::test::RunOnceCallback<1>(
-          aggregation_service::TestHpkeKey().GetPublicKey(),
-          PublicKeyFetchStatus::kOk));
-  EXPECT_CALL(callback(),
-              Run(_, Eq(std::nullopt), AssemblyStatus::kPublicKeyFetchFailed));
-
-  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKeys(_, _))
-      .Times(0);
-
-  assembler()->AssembleReport(std::move(request), callback().Get());
-
-  histograms.ExpectUniqueSample(
-      kReportAssemblerStatusHistogramName,
-      AggregatableReportAssembler::AssemblyStatus::kPublicKeyFetchFailed, 1);
-}
-
-TEST_F(AggregatableReportAssemblerTest, SecondKeyFetchFails_ErrorReturned) {
-  base::HistogramTester histograms;
-
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-  std::vector<GURL> processing_urls = request.processing_urls();
-
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[0], _))
-      .WillOnce(base::test::RunOnceCallback<1>(
-          aggregation_service::TestHpkeKey().GetPublicKey(),
-          PublicKeyFetchStatus::kOk));
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[1], _))
-      .WillOnce(base::test::RunOnceCallback<1>(
-          std::nullopt, PublicKeyFetchStatus::kPublicKeyFetchFailed));
-  EXPECT_CALL(callback(),
-              Run(_, Eq(std::nullopt), AssemblyStatus::kPublicKeyFetchFailed));
-
-  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKeys(_, _))
-      .Times(0);
-
-  assembler()->AssembleReport(std::move(request), callback().Get());
-
-  histograms.ExpectUniqueSample(
-      kReportAssemblerStatusHistogramName,
-      AggregatableReportAssembler::AssemblyStatus::kPublicKeyFetchFailed, 1);
-}
-
-TEST_F(AggregatableReportAssemblerTest,
-       BothKeyFetchesSucceed_ValidReportReturned) {
-  base::HistogramTester histograms;
-
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-
-  std::vector<GURL> processing_urls = request.processing_urls();
-  std::vector<PublicKey> public_keys = {
-      aggregation_service::TestHpkeKey("id123").GetPublicKey(),
-      aggregation_service::TestHpkeKey("456abc").GetPublicKey()};
-
-  std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request, public_keys);
-#if !BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-  ASSERT_FALSE(report.has_value());
-#else
-  ASSERT_TRUE(report.has_value());
-
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[0], _))
-      .WillOnce(base::test::RunOnceCallback<1>(public_keys[0],
-                                               PublicKeyFetchStatus::kOk));
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[1], _))
-      .WillOnce(base::test::RunOnceCallback<1>(public_keys[1],
-                                               PublicKeyFetchStatus::kOk));
-  EXPECT_CALL(callback(), Run(_, report, AssemblyStatus::kOk));
-
-  std::optional<AggregatableReportRequest> actual_request;
-  EXPECT_CALL(*report_provider(),
-              CreateFromRequestAndPublicKeys(_, public_keys))
-      .WillOnce(CloneRequestAndReturnReport(&actual_request,
-                                            std::move(report.value())));
-
-  assembler()->AssembleReport(aggregation_service::CloneReportRequest(request),
-                              callback().Get());
-  ASSERT_TRUE(actual_request.has_value());
-  EXPECT_TRUE(aggregation_service::ReportRequestsEqual(actual_request.value(),
-                                                       request));
-
-  histograms.ExpectUniqueSample(
-      kReportAssemblerStatusHistogramName,
-      AggregatableReportAssembler::AssemblyStatus::kOk, 1);
-#endif  // !BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-}
-
-TEST_F(AggregatableReportAssemblerTest,
-       OnlyKeyFetchSucceeds_ValidReportReturned) {
-  base::HistogramTester histograms;
-
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kTeeBased);
+  AggregatableReportRequest request =
+      aggregation_service::CreateExampleRequest();
 
   PublicKey public_key =
       aggregation_service::TestHpkeKey("id123").GetPublicKey();
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request, {public_key});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(request,
+                                                                   public_key);
   ASSERT_TRUE(report.has_value());
 
   EXPECT_CALL(*fetcher(), GetPublicKey)
@@ -261,8 +133,7 @@
   EXPECT_CALL(callback(), Run(_, report, AssemblyStatus::kOk));
 
   std::optional<AggregatableReportRequest> actual_request;
-  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKeys(
-                                      _, std::vector<PublicKey>{public_key}))
+  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKey(_, public_key))
       .WillOnce(CloneRequestAndReturnReport(&actual_request,
                                             std::move(report.value())));
 
@@ -277,11 +148,11 @@
       AggregatableReportAssembler::AssemblyStatus::kOk, 1);
 }
 
-TEST_F(AggregatableReportAssemblerTest, OnlyKeyFetchFails_ErrorReturned) {
+TEST_F(AggregatableReportAssemblerTest, KeyFetchFails_ErrorReturned) {
   base::HistogramTester histograms;
 
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kTeeBased);
+  AggregatableReportRequest request =
+      aggregation_service::CreateExampleRequest();
 
   EXPECT_CALL(*fetcher(), GetPublicKey)
       .WillOnce(base::test::RunOnceCallback<1>(
@@ -289,8 +160,7 @@
   EXPECT_CALL(callback(),
               Run(_, Eq(std::nullopt), AssemblyStatus::kPublicKeyFetchFailed));
 
-  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKeys(_, _))
-      .Times(0);
+  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKey(_, _)).Times(0);
 
   assembler()->AssembleReport(std::move(request), callback().Get());
 
@@ -300,60 +170,11 @@
 }
 
 TEST_F(AggregatableReportAssemblerTest,
-       TwoKeyFetchesReturnInSwappedOrder_ValidReportReturned) {
-  base::HistogramTester histograms;
-
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-
-  std::vector<GURL> processing_urls = request.processing_urls();
-  std::vector<PublicKey> public_keys = {
-      aggregation_service::TestHpkeKey("id123").GetPublicKey(),
-      aggregation_service::TestHpkeKey("456abc").GetPublicKey()};
-
-  std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request, public_keys);
-#if !BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-  ASSERT_FALSE(report.has_value());
-#else
-  ASSERT_TRUE(report.has_value());
-
-  std::vector<FetchCallback> pending_callbacks(2);
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[0], _))
-      .WillOnce(MoveArg<1>(&pending_callbacks.front()));
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[1], _))
-      .WillOnce(MoveArg<1>(&pending_callbacks.back()));
-  EXPECT_CALL(callback(), Run(_, report, AssemblyStatus::kOk));
-
-  std::optional<AggregatableReportRequest> actual_request;
-  EXPECT_CALL(*report_provider(),
-              CreateFromRequestAndPublicKeys(_, public_keys))
-      .WillOnce(CloneRequestAndReturnReport(&actual_request,
-                                            std::move(report.value())));
-
-  assembler()->AssembleReport(aggregation_service::CloneReportRequest(request),
-                              callback().Get());
-
-  // Swap order of responses
-  std::move(pending_callbacks.back())
-      .Run(public_keys[1], PublicKeyFetchStatus::kOk);
-  std::move(pending_callbacks.front())
-      .Run(public_keys[0], PublicKeyFetchStatus::kOk);
-
-  histograms.ExpectUniqueSample(
-      kReportAssemblerStatusHistogramName,
-      AggregatableReportAssembler::AssemblyStatus::kOk, 1);
-#endif  // !BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-}
-
-TEST_F(AggregatableReportAssemblerTest,
        AssemblerDeleted_PendingRequestsNotRun) {
   base::HistogramTester histograms;
 
   AggregatableReportRequest request =
       aggregation_service::CreateExampleRequest();
-  std::vector<GURL> processing_urls = request.processing_urls();
 
   EXPECT_CALL(callback(), Run).Times(0);
   EXPECT_CALL(*fetcher(), GetPublicKey);
@@ -371,17 +192,16 @@
   AggregatableReportRequest request =
       aggregation_service::CreateExampleRequest();
 
-  std::vector<GURL> processing_urls = request.processing_urls();
   PublicKey public_key =
       aggregation_service::TestHpkeKey("id123").GetPublicKey();
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request, {public_key});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(request,
+                                                                   public_key);
   ASSERT_TRUE(report.has_value());
 
   std::vector<FetchCallback> pending_callbacks(2);
-  EXPECT_CALL(*fetcher(), GetPublicKey(processing_urls[0], _))
+  EXPECT_CALL(*fetcher(), GetPublicKey(request.processing_url(), _))
       .WillOnce(MoveArg<1>(&pending_callbacks.front()))
       .WillOnce(MoveArg<1>(&pending_callbacks.back()));
 
@@ -389,8 +209,7 @@
 
   std::optional<AggregatableReportRequest> first_request;
   std::optional<AggregatableReportRequest> second_request;
-  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKeys(
-                                      _, std::vector<PublicKey>{public_key}))
+  EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKey(_, public_key))
       .WillOnce(CloneRequestAndReturnReport(&first_request, report.value()))
       .WillOnce(CloneRequestAndReturnReport(&second_request,
                                             std::move(report.value())));
@@ -424,8 +243,8 @@
   PublicKey public_key =
       aggregation_service::TestHpkeKey("id123").GetPublicKey();
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          aggregation_service::CreateExampleRequest(), {std::move(public_key)});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          aggregation_service::CreateExampleRequest(), std::move(public_key));
   ASSERT_TRUE(report.has_value());
 
   std::vector<FetchCallback> pending_callbacks;
@@ -456,7 +275,7 @@
     for (size_t i = 0;
          i < AggregatableReportAssembler::kMaxSimultaneousRequests; i++) {
       EXPECT_CALL(checkpoint, Call(current_check++));
-      EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKeys)
+      EXPECT_CALL(*report_provider(), CreateFromRequestAndPublicKey)
           .WillOnce(Return(report));
       EXPECT_CALL(callback(), Run(_, report, AssemblyStatus::kOk));
     }
diff --git a/content/browser/aggregation_service/aggregatable_report_unittest.cc b/content/browser/aggregation_service/aggregatable_report_unittest.cc
index 4699ae41..b3717f9 100644
--- a/content/browser/aggregation_service/aggregatable_report_unittest.cc
+++ b/content/browser/aggregation_service/aggregatable_report_unittest.cc
@@ -37,7 +37,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/numeric/int128.h"
 #include "third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom.h"
-#include "third_party/distributed_point_functions/shim/buildflags.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -85,11 +84,11 @@
     const std::optional<AggregatableReport>& report,
     const AggregationServicePayloadContents& expected_payload_contents,
     const AggregatableReportSharedInfo& expected_shared_info,
-    size_t expected_num_processing_urls,
     const std::optional<uint64_t>& expected_debug_key,
     const base::flat_map<std::string, std::string>& expected_additional_fields,
-    const std::vector<aggregation_service::TestHpkeKey>& encryption_keys) {
+    const aggregation_service::TestHpkeKey& encryption_key) {
   ASSERT_TRUE(report.has_value());
+  ASSERT_TRUE(report->payload().has_value());
 
   std::string expected_serialized_shared_info =
       expected_shared_info.SerializeAsJson();
@@ -98,116 +97,92 @@
   EXPECT_EQ(report->debug_key(), expected_debug_key);
   EXPECT_EQ(report->additional_fields(), expected_additional_fields);
 
-  const std::vector<AggregatableReport::AggregationServicePayload>& payloads =
-      report->payloads();
-  ASSERT_EQ(payloads.size(), expected_num_processing_urls);
-  ASSERT_EQ(encryption_keys.size(), expected_num_processing_urls);
+  const AggregatableReport::AggregationServicePayload& payload =
+      *report->payload();
 
   std::vector<blink::mojom::AggregatableReportHistogramContribution>
       expected_contributions =
           PadContributions(expected_payload_contents.contributions,
                            expected_payload_contents.max_contributions_allowed);
 
-  for (size_t i = 0; i < expected_num_processing_urls; ++i) {
-    EXPECT_EQ(payloads[i].key_id, encryption_keys[i].key_id());
+  EXPECT_EQ(payload.key_id, encryption_key.key_id());
 
-    std::vector<uint8_t> decrypted_payload =
-        aggregation_service::DecryptPayloadWithHpke(
-            payloads[i].payload, encryption_keys[i].full_hpke_key(),
-            expected_serialized_shared_info);
-    ASSERT_FALSE(decrypted_payload.empty());
+  std::vector<uint8_t> decrypted_payload =
+      aggregation_service::DecryptPayloadWithHpke(
+          payload.payload, encryption_key.full_hpke_key(),
+          expected_serialized_shared_info);
+  ASSERT_FALSE(decrypted_payload.empty());
 
-    if (expected_shared_info.debug_mode ==
-        AggregatableReportSharedInfo::DebugMode::kEnabled) {
-      ASSERT_TRUE(payloads[i].debug_cleartext_payload.has_value());
-      EXPECT_EQ(payloads[i].debug_cleartext_payload.value(), decrypted_payload);
-    } else {
-      EXPECT_FALSE(payloads[i].debug_cleartext_payload.has_value());
-    }
+  if (expected_shared_info.debug_mode ==
+      AggregatableReportSharedInfo::DebugMode::kEnabled) {
+    ASSERT_TRUE(payload.debug_cleartext_payload.has_value());
+    EXPECT_EQ(payload.debug_cleartext_payload.value(), decrypted_payload);
+  } else {
+    EXPECT_FALSE(payload.debug_cleartext_payload.has_value());
+  }
 
-    std::optional<cbor::Value> deserialized_payload =
-        cbor::Reader::Read(decrypted_payload);
-    ASSERT_TRUE(deserialized_payload.has_value());
-    ASSERT_TRUE(deserialized_payload->is_map());
-    const cbor::Value::MapValue& payload_map = deserialized_payload->GetMap();
+  std::optional<cbor::Value> deserialized_payload =
+      cbor::Reader::Read(decrypted_payload);
+  ASSERT_TRUE(deserialized_payload.has_value());
+  ASSERT_TRUE(deserialized_payload->is_map());
+  const cbor::Value::MapValue& payload_map = deserialized_payload->GetMap();
 
-    EXPECT_EQ(payload_map.size(), 2UL);
+  EXPECT_EQ(payload_map.size(), 2UL);
 
-    ASSERT_TRUE(CborMapContainsKeyAndType(payload_map, "operation",
-                                          cbor::Value::Type::STRING));
-    EXPECT_EQ(payload_map.at(cbor::Value("operation")).GetString(),
-              "histogram");
+  ASSERT_TRUE(CborMapContainsKeyAndType(payload_map, "operation",
+                                        cbor::Value::Type::STRING));
+  EXPECT_EQ(payload_map.at(cbor::Value("operation")).GetString(), "histogram");
 
-    switch (expected_payload_contents.aggregation_mode) {
-      case blink::mojom::AggregationServiceMode::kTeeBased: {
-        ASSERT_TRUE(CborMapContainsKeyAndType(payload_map, "data",
-                                              cbor::Value::Type::ARRAY));
-        const cbor::Value::ArrayValue& data_array =
-            payload_map.at(cbor::Value("data")).GetArray();
+  ASSERT_TRUE(
+      CborMapContainsKeyAndType(payload_map, "data", cbor::Value::Type::ARRAY));
+  const cbor::Value::ArrayValue& data_array =
+      payload_map.at(cbor::Value("data")).GetArray();
 
-        ASSERT_EQ(data_array.size(), expected_contributions.size());
-        for (size_t j = 0; j < data_array.size(); ++j) {
-          ASSERT_TRUE(data_array[j].is_map());
-          const cbor::Value::MapValue& data_map = data_array[j].GetMap();
+  ASSERT_EQ(data_array.size(), expected_contributions.size());
+  for (size_t j = 0; j < data_array.size(); ++j) {
+    ASSERT_TRUE(data_array[j].is_map());
+    const cbor::Value::MapValue& data_map = data_array[j].GetMap();
 
-          ASSERT_TRUE(CborMapContainsKeyAndType(
-              data_map, "bucket", cbor::Value::Type::BYTE_STRING));
-          const cbor::Value::BinaryValue& bucket_byte_string =
-              data_map.at(cbor::Value("bucket")).GetBytestring();
-          EXPECT_EQ(bucket_byte_string.size(), 16u);  // 16 bytes = 128 bits
+    ASSERT_TRUE(CborMapContainsKeyAndType(data_map, "bucket",
+                                          cbor::Value::Type::BYTE_STRING));
+    const cbor::Value::BinaryValue& bucket_byte_string =
+        data_map.at(cbor::Value("bucket")).GetBytestring();
+    EXPECT_EQ(bucket_byte_string.size(), 16u);  // 16 bytes = 128 bits
 
-          // TODO(crbug.com/40215445): Replace with
-          // `base::U128FromBigEndian()` when available.
-          absl::uint128 bucket;
-          base::HexStringToUInt128(base::HexEncode(bucket_byte_string),
-                                   &bucket);
-          EXPECT_EQ(bucket, expected_contributions[j].bucket);
+    // TODO(crbug.com/40215445): Replace with
+    // `base::U128FromBigEndian()` when available.
+    absl::uint128 bucket;
+    base::HexStringToUInt128(base::HexEncode(bucket_byte_string), &bucket);
+    EXPECT_EQ(bucket, expected_contributions[j].bucket);
 
-          ASSERT_TRUE(CborMapContainsKeyAndType(
-              data_map, "value", cbor::Value::Type::BYTE_STRING));
-          const cbor::Value::BinaryValue& value_byte_string =
-              data_map.at(cbor::Value("value")).GetBytestring();
-          EXPECT_EQ(value_byte_string.size(), 4u);  // 4 bytes = 32 bits
+    ASSERT_TRUE(CborMapContainsKeyAndType(data_map, "value",
+                                          cbor::Value::Type::BYTE_STRING));
+    const cbor::Value::BinaryValue& value_byte_string =
+        data_map.at(cbor::Value("value")).GetBytestring();
+    EXPECT_EQ(value_byte_string.size(), 4u);  // 4 bytes = 32 bits
 
-          uint32_t value = base::U32FromBigEndian(
-              base::as_byte_span(value_byte_string).first<4u>());
-          EXPECT_EQ(int64_t{value}, expected_contributions[j].value);
+    uint32_t value = base::U32FromBigEndian(
+        base::as_byte_span(value_byte_string).first<4u>());
+    EXPECT_EQ(int64_t{value}, expected_contributions[j].value);
 
-          ASSERT_TRUE(CborMapContainsKeyAndType(
-              data_map, "id", cbor::Value::Type::BYTE_STRING));
-          const cbor::Value::BinaryValue& filtering_id_byte_string =
-              data_map.at(cbor::Value("id")).GetBytestring();
-          ASSERT_EQ(filtering_id_byte_string.size(),
-                    expected_payload_contents.filtering_id_max_bytes);
+    ASSERT_TRUE(CborMapContainsKeyAndType(data_map, "id",
+                                          cbor::Value::Type::BYTE_STRING));
+    const cbor::Value::BinaryValue& filtering_id_byte_string =
+        data_map.at(cbor::Value("id")).GetBytestring();
+    ASSERT_EQ(filtering_id_byte_string.size(),
+              expected_payload_contents.filtering_id_max_bytes);
 
-          std::array<uint8_t, 8u> padded_filtering_id_bytestring;
-          padded_filtering_id_bytestring.fill(0);
-          base::as_writable_byte_span(padded_filtering_id_bytestring)
-              .last(expected_payload_contents.filtering_id_max_bytes)
-              .copy_from(filtering_id_byte_string);
+    std::array<uint8_t, 8u> padded_filtering_id_bytestring;
+    padded_filtering_id_bytestring.fill(0);
+    base::as_writable_byte_span(padded_filtering_id_bytestring)
+        .last(expected_payload_contents.filtering_id_max_bytes)
+        .copy_from(filtering_id_byte_string);
 
-          CHECK_LE(expected_payload_contents.filtering_id_max_bytes, 8u);
-          uint64_t filtering_id = base::U64FromBigEndian(
-              base::span(padded_filtering_id_bytestring));
+    CHECK_LE(expected_payload_contents.filtering_id_max_bytes, 8u);
+    uint64_t filtering_id =
+        base::U64FromBigEndian(base::span(padded_filtering_id_bytestring));
 
-          EXPECT_EQ(filtering_id,
-                    expected_contributions[j].filtering_id.value_or(0));
-        }
-
-        EXPECT_FALSE(payload_map.contains(cbor::Value("dpf_key")));
-        break;
-      }
-      case blink::mojom::AggregationServiceMode::kExperimentalPoplar: {
-        EXPECT_TRUE(CborMapContainsKeyAndType(payload_map, "dpf_key",
-                                              cbor::Value::Type::BYTE_STRING));
-
-        // TODO(crbug.com/40193482): Test the payload details (e.g. dpf key) in
-        // more depth against a minimal helper server implementation.
-
-        EXPECT_FALSE(payload_map.contains(cbor::Value("data")));
-        break;
-      }
-    }
+    EXPECT_EQ(filtering_id, expected_contributions[j].filtering_id.value_or(0));
   }
 }
 
@@ -220,68 +195,31 @@
            url::Origin::Create(GURL("https://b.test"))}};
 };
 
-TEST_F(AggregatableReportTest,
-       ValidExperimentalPoplarRequest_ValidReportReturned) {
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar);
+TEST_F(AggregatableReportTest, ValidRequest_ValidReportReturned) {
+  AggregatableReportRequest request =
+      aggregation_service::CreateExampleRequest();
 
   AggregationServicePayloadContents expected_payload_contents =
       request.payload_contents();
   AggregatableReportSharedInfo expected_shared_info =
       request.shared_info().Clone();
 
-  [[maybe_unused]] size_t expected_num_processing_urls =
-      request.processing_urls().size();
-
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
-  hpke_keys.emplace_back("456abc");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(request),
-          {hpke_keys[0].GetPublicKey(), hpke_keys[1].GetPublicKey()});
-
-#if BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS)
-  ASSERT_NO_FATAL_FAILURE(
-      VerifyReport(report, expected_payload_contents, expected_shared_info,
-                   expected_num_processing_urls,
-                   /*expected_debug_key=*/std::nullopt,
-                   /*expected_additional_fields=*/{}, std::move(hpke_keys)));
-#else
-  EXPECT_FALSE(report.has_value());
-#endif
-}
-
-TEST_F(AggregatableReportTest, ValidTeeBasedRequest_ValidReportReturned) {
-  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kTeeBased);
-
-  AggregationServicePayloadContents expected_payload_contents =
-      request.payload_contents();
-  AggregatableReportSharedInfo expected_shared_info =
-      request.shared_info().Clone();
-  size_t expected_num_processing_urls = request.processing_urls().size();
-
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
-
-  std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(request), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(request), hpke_key.GetPublicKey());
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyReport(report, expected_payload_contents, expected_shared_info,
-                   expected_num_processing_urls,
                    /*expected_debug_key=*/std::nullopt,
-                   /*expected_additional_fields=*/{}, std::move(hpke_keys)));
+                   /*expected_additional_fields=*/{}, hpke_key));
 }
 
 TEST_F(AggregatableReportTest,
        ValidMultipleContributionsRequest_ValidReportReturned) {
   AggregatableReportRequest example_request =
-      aggregation_service::CreateExampleRequest(
-          blink::mojom::AggregationServiceMode::kTeeBased);
+      aggregation_service::CreateExampleRequest();
 
   AggregationServicePayloadContents expected_payload_contents =
       example_request.payload_contents();
@@ -300,27 +238,23 @@
 
   AggregatableReportSharedInfo expected_shared_info =
       request->shared_info().Clone();
-  size_t expected_num_processing_urls = request->processing_urls().size();
 
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(*request), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(*request), hpke_key.GetPublicKey());
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyReport(report, expected_payload_contents, expected_shared_info,
-                   expected_num_processing_urls,
                    /*expected_debug_key=*/std::nullopt,
-                   /*expected_additional_fields=*/{}, std::move(hpke_keys)));
+                   /*expected_additional_fields=*/{}, hpke_key));
 }
 
 TEST_F(AggregatableReportTest,
        ValidNoContributionsRequest_ValidReportReturned) {
   AggregatableReportRequest example_request =
-      aggregation_service::CreateExampleRequest(
-          blink::mojom::AggregationServiceMode::kTeeBased);
+      aggregation_service::CreateExampleRequest();
 
   AggregationServicePayloadContents payload_contents =
       example_request.payload_contents();
@@ -333,20 +267,18 @@
 
   AggregatableReportSharedInfo expected_shared_info =
       request->shared_info().Clone();
-  size_t expected_num_processing_urls = request->processing_urls().size();
 
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(*request), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(*request), hpke_key.GetPublicKey());
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyReport(report, /*expected_payload_contents=*/payload_contents,
-                   expected_shared_info, expected_num_processing_urls,
+                   expected_shared_info,
                    /*expected_debug_key=*/std::nullopt,
-                   /*expected_additional_fields=*/{}, std::move(hpke_keys)));
+                   /*expected_additional_fields=*/{}, hpke_key));
 }
 
 TEST_F(AggregatableReportTest,
@@ -364,20 +296,17 @@
 
   AggregationServicePayloadContents expected_payload_contents =
       request->payload_contents();
-  size_t expected_num_processing_urls = request->processing_urls().size();
 
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(request.value()), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(request.value()), hpke_key.GetPublicKey());
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyReport(report, expected_payload_contents, expected_shared_info,
-                   expected_num_processing_urls,
                    /*expected_debug_key=*/std::nullopt,
-                   /*expected_additional_fields=*/{}, std::move(hpke_keys)));
+                   /*expected_additional_fields=*/{}, hpke_key));
 }
 
 TEST_F(AggregatableReportTest,
@@ -400,19 +329,17 @@
 
   AggregationServicePayloadContents expected_payload_contents =
       request->payload_contents();
-  size_t expected_num_processing_urls = request->processing_urls().size();
 
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(request.value()), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(request.value()), hpke_key.GetPublicKey());
 
-  ASSERT_NO_FATAL_FAILURE(
-      VerifyReport(report, expected_payload_contents, expected_shared_info,
-                   expected_num_processing_urls, expected_debug_key,
-                   /*expected_additional_fields=*/{}, std::move(hpke_keys)));
+  ASSERT_NO_FATAL_FAILURE(VerifyReport(report, expected_payload_contents,
+                                       expected_shared_info, expected_debug_key,
+                                       /*expected_additional_fields=*/{},
+                                       hpke_key));
 }
 
 TEST_F(AggregatableReportTest, AdditionalFieldsPresent_ValidReportReturned) {
@@ -432,19 +359,17 @@
 
   AggregationServicePayloadContents expected_payload_contents =
       request->payload_contents();
-  size_t expected_num_processing_urls = request->processing_urls().size();
 
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(request.value()), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(request.value()), hpke_key.GetPublicKey());
 
-  ASSERT_NO_FATAL_FAILURE(VerifyReport(
-      report, expected_payload_contents, example_request.shared_info(),
-      expected_num_processing_urls, /*expected_debug_key=*/std::nullopt,
-      expected_additional_fields, std::move(hpke_keys)));
+  ASSERT_NO_FATAL_FAILURE(VerifyReport(report, expected_payload_contents,
+                                       example_request.shared_info(),
+                                       /*expected_debug_key=*/std::nullopt,
+                                       expected_additional_fields, hpke_key));
 }
 
 TEST_F(AggregatableReportTest,
@@ -461,19 +386,16 @@
                                         example_request.shared_info().Clone());
   ASSERT_TRUE(request.has_value());
 
-  size_t expected_num_processing_urls = request->processing_urls().size();
-
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(request.value()), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(request.value()), hpke_key.GetPublicKey());
 
-  ASSERT_NO_FATAL_FAILURE(VerifyReport(
-      report, payload_contents, example_request.shared_info(),
-      expected_num_processing_urls, /*expected_debug_key=*/std::nullopt,
-      /*expected_additional_fields=*/{}, std::move(hpke_keys)));
+  ASSERT_NO_FATAL_FAILURE(
+      VerifyReport(report, payload_contents, example_request.shared_info(),
+                   /*expected_debug_key=*/std::nullopt,
+                   /*expected_additional_fields=*/{}, hpke_key));
 }
 
 TEST_F(AggregatableReportTest, FilteringIdsSpecified_ValidReportReturned) {
@@ -497,19 +419,16 @@
                                         example_request.shared_info().Clone());
   ASSERT_TRUE(request.has_value());
 
-  size_t expected_num_processing_urls = request->processing_urls().size();
-
-  std::vector<aggregation_service::TestHpkeKey> hpke_keys;
-  hpke_keys.emplace_back("id123");
+  aggregation_service::TestHpkeKey hpke_key("id123");
 
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          std::move(request.value()), {hpke_keys[0].GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          std::move(request.value()), hpke_key.GetPublicKey());
 
-  ASSERT_NO_FATAL_FAILURE(VerifyReport(
-      report, payload_contents, example_request.shared_info(),
-      expected_num_processing_urls, /*expected_debug_key=*/std::nullopt,
-      /*expected_additional_fields=*/{}, std::move(hpke_keys)));
+  ASSERT_NO_FATAL_FAILURE(
+      VerifyReport(report, payload_contents, example_request.shared_info(),
+                   /*expected_debug_key=*/std::nullopt,
+                   /*expected_additional_fields=*/{}, hpke_key));
 }
 
 TEST_F(AggregatableReportTest,
@@ -552,10 +471,9 @@
   EXPECT_FALSE(request.has_value());
 }
 
-TEST_F(AggregatableReportTest, TeeBasedRequestCreatedWithZeroContributions) {
+TEST_F(AggregatableReportTest, RequestCreatedWithZeroContributions) {
   AggregatableReportRequest example_request =
-      aggregation_service::CreateExampleRequest(
-          blink::mojom::AggregationServiceMode::kTeeBased);
+      aggregation_service::CreateExampleRequest();
 
   AggregationServicePayloadContents payload_contents =
       example_request.payload_contents();
@@ -568,43 +486,6 @@
 }
 
 TEST_F(AggregatableReportTest,
-       ExperimentalPoplarRequestNotCreatedWithZeroContributions) {
-  AggregatableReportRequest example_request =
-      aggregation_service::CreateExampleRequest(
-          blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-
-  AggregationServicePayloadContents payload_contents =
-      example_request.payload_contents();
-
-  payload_contents.contributions.clear();
-  std::optional<AggregatableReportRequest> request =
-      AggregatableReportRequest::Create(payload_contents,
-                                        example_request.shared_info().Clone());
-  EXPECT_FALSE(request.has_value());
-}
-
-TEST_F(AggregatableReportTest, RequestCreatedWithTooManyContributions) {
-  AggregatableReportRequest example_request =
-      aggregation_service::CreateExampleRequest(
-          blink::mojom::AggregationServiceMode::kExperimentalPoplar);
-
-  AggregationServicePayloadContents payload_contents =
-      example_request.payload_contents();
-  payload_contents.contributions = {
-      blink::mojom::AggregatableReportHistogramContribution(
-          /*bucket=*/123,
-          /*value=*/456, /*filtering_id=*/std::nullopt),
-      blink::mojom::AggregatableReportHistogramContribution(
-          /*bucket=*/7890,
-          /*value=*/1234, /*filtering_id=*/std::nullopt)};
-
-  std::optional<AggregatableReportRequest> request =
-      AggregatableReportRequest::Create(payload_contents,
-                                        example_request.shared_info().Clone());
-  ASSERT_FALSE(request.has_value());
-}
-
-TEST_F(AggregatableReportTest,
        RequestCreatedWithDebugKeyButDebugModeDisabled_Failed) {
   AggregatableReportRequest example_request =
       aggregation_service::CreateExampleRequest();
@@ -621,12 +502,11 @@
 }
 
 TEST_F(AggregatableReportTest, GetAsJsonOnePayload_ValidJsonReturned) {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/std::nullopt);
-
-  AggregatableReport report(std::move(payloads), "example_shared_info",
+  AggregatableReport report(AggregatableReport::AggregationServicePayload(
+                                /*payload=*/kABCD1234AsBytes,
+                                /*key_id=*/"key_1",
+                                /*debug_cleartext_payload=*/std::nullopt),
+                            "example_shared_info",
                             /*debug_key=*/std::nullopt,
                             /*additional_fields=*/{},
                             /*aggregation_coordinator_origin=*/std::nullopt);
@@ -645,43 +525,13 @@
   EXPECT_EQ(report_json_string, kExpectedJsonString);
 }
 
-TEST_F(AggregatableReportTest, GetAsJsonTwoPayloads_ValidJsonReturned) {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/std::nullopt);
-  payloads.emplace_back(/*payload=*/kEFGH5678AsBytes,
-                        /*key_id=*/"key_2",
-                        /*debug_cleartext_payload=*/std::nullopt);
-
-  AggregatableReport report(std::move(payloads), "example_shared_info",
-                            /*debug_key=*/std::nullopt,
-                            /*additional_fields=*/{},
-                            /*aggregation_coordinator_origin=*/std::nullopt);
-
-  std::string report_json_string;
-  base::JSONWriter::Write(base::Value(report.GetAsJson()), &report_json_string);
-
-  const char kExpectedJsonString[] =
-      R"({)"
-      R"("aggregation_coordinator_origin":"https://a.test",)"
-      R"("aggregation_service_payloads":[)"
-      R"({"key_id":"key_1","payload":"ABCD1234"},)"
-      R"({"key_id":"key_2","payload":"EFGH5678"})"
-      R"(],)"
-      R"("shared_info":"example_shared_info")"
-      R"(})";
-  EXPECT_EQ(report_json_string, kExpectedJsonString);
-}
-
 TEST_F(AggregatableReportTest,
        GetAsJsonDebugCleartextPayload_ValidJsonReturned) {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/kEFGH5678AsBytes);
-
-  AggregatableReport report(std::move(payloads), "example_shared_info",
+  AggregatableReport report(AggregatableReport::AggregationServicePayload(
+                                /*payload=*/kABCD1234AsBytes,
+                                /*key_id=*/"key_1",
+                                /*debug_cleartext_payload=*/kEFGH5678AsBytes),
+                            "example_shared_info",
                             /*debug_key=*/std::nullopt,
                             /*additional_fields=*/{},
                             /*aggregation_coordinator_origin=*/std::nullopt);
@@ -703,12 +553,11 @@
 }
 
 TEST_F(AggregatableReportTest, GetAsJsonDebugKey_ValidJsonReturned) {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/kEFGH5678AsBytes);
-
-  AggregatableReport report(std::move(payloads), "example_shared_info",
+  AggregatableReport report(AggregatableReport::AggregationServicePayload(
+                                /*payload=*/kABCD1234AsBytes,
+                                /*key_id=*/"key_1",
+                                /*debug_cleartext_payload=*/kEFGH5678AsBytes),
+                            "example_shared_info",
                             /*debug_key=*/1234, /*additional_fields=*/{},
                             /*aggregation_coordinator_origin=*/std::nullopt);
 
@@ -730,13 +579,12 @@
 }
 
 TEST_F(AggregatableReportTest, GetAsJsonAdditionalFields_ValidJsonReturned) {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/std::nullopt);
-
   AggregatableReport report(
-      std::move(payloads), "example_shared_info",
+      AggregatableReport::AggregationServicePayload(
+          /*payload=*/kABCD1234AsBytes,
+          /*key_id=*/"key_1",
+          /*debug_cleartext_payload=*/std::nullopt),
+      "example_shared_info",
       /*debug_key=*/std::nullopt, /*additional_fields=*/
       {{"additional_key", "example_value"}, {"second", "field"}, {"", ""}},
       /*aggregation_coordinator_origin=*/std::nullopt);
@@ -839,8 +687,7 @@
 
 TEST_F(AggregatableReportTest, ReportingPathSet_SetInRequest) {
   AggregatableReportRequest example_request =
-      aggregation_service::CreateExampleRequest(
-          blink::mojom::AggregationServiceMode::kExperimentalPoplar);
+      aggregation_service::CreateExampleRequest();
 
   std::string reporting_path = "/example-path";
 
@@ -910,7 +757,6 @@
 
   AggregatableReportRequest example_request_with_failed_attempts =
       aggregation_service::CreateExampleRequest(
-          /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
           /*failed_send_attempts=*/2,
           /*aggregation_coordinator_origin=*/std::nullopt,
           /*delay_type=*/
@@ -933,7 +779,6 @@
 TEST_F(AggregatableReportTest, DelayTypeSerializeNulloptCrashes) {
   AggregatableReportRequest example_request =
       aggregation_service::CreateExampleRequest(
-          /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
           /*failed_send_attempts=*/0,
           /*aggregation_coordinator_origin=*/std::nullopt,
           /*delay_type=*/std::nullopt);
@@ -948,7 +793,6 @@
 TEST_F(AggregatableReportTest, DelayTypeSerializeUnscheduledCrashes) {
   AggregatableReportRequest example_request =
       aggregation_service::CreateExampleRequest(
-          /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
           /*failed_send_attempts=*/0,
           /*aggregation_coordinator_origin=*/std::nullopt,
           /*delay_type=*/AggregatableReportRequest::DelayType::Unscheduled);
@@ -969,7 +813,6 @@
   for (const auto delay_type : kDelayTypeValues) {
     AggregatableReportRequest example_request =
         aggregation_service::CreateExampleRequest(
-            /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
             /*failed_send_attempts=*/0,
             /*aggregation_coordinator_origin=*/std::nullopt, delay_type);
 
@@ -1094,8 +937,7 @@
 
 TEST_F(AggregatableReportTest, ReportingPathEmpty_NotSetInRequest) {
   AggregatableReportRequest example_request =
-      aggregation_service::CreateExampleRequest(
-          blink::mojom::AggregationServiceMode::kExperimentalPoplar);
+      aggregation_service::CreateExampleRequest();
 
   std::optional<AggregatableReportRequest> request =
       AggregatableReportRequest::Create(example_request.payload_contents(),
@@ -1256,7 +1098,6 @@
               {blink::mojom::AggregatableReportHistogramContribution(
                   /*bucket=*/123, /*value=*/456,
                   /*filtering_id=*/std::nullopt)},
-              blink::mojom::AggregationServiceMode::kDefault,
               /*aggregation_coordinator_origin=*/std::nullopt,
               /*max_contributions_allowed=*/1u,
               /*filtering_id_max_bytes=*/1u),  // Default max bytes used.
@@ -1304,7 +1145,6 @@
               {blink::mojom::AggregatableReportHistogramContribution(
                   /*bucket=*/123, /*value=*/456,
                   /*filtering_id=*/std::nullopt)},
-              blink::mojom::AggregationServiceMode::kDefault,
               /*aggregation_coordinator_origin=*/std::nullopt,
               /*max_contributions_allowed=*/1u,
               /*filtering_id_max_bytes=*/1u),  // Default max bytes used.
@@ -1353,7 +1193,6 @@
               {blink::mojom::AggregatableReportHistogramContribution(
                   /*bucket=*/123, /*value=*/456,
                   /*filtering_id=*/std::nullopt)},
-              blink::mojom::AggregationServiceMode::kDefault,
               /*aggregation_coordinator_origin=*/std::nullopt,
               /*max_contributions_allowed=*/1u,
               /*filtering_id_max_bytes=*/1u),  // Default max bytes used.
@@ -1380,35 +1219,35 @@
 TEST_F(AggregatableReportTest, ProcessingUrlSet) {
   AggregatableReportRequest request =
       aggregation_service::CreateExampleRequest();
-  EXPECT_THAT(
-      request.processing_urls(),
-      ::testing::ElementsAre(GetAggregationServiceProcessingUrl(
-          ::aggregation_service::GetDefaultAggregationCoordinatorOrigin())));
+  EXPECT_EQ(
+      request.processing_url(),
+      GetAggregationServiceProcessingUrl(
+          ::aggregation_service::GetDefaultAggregationCoordinatorOrigin()));
 }
 
 TEST_F(AggregatableReportTest, AggregationCoordinator_ProcessingUrlSet) {
   const struct {
     std::optional<url::Origin> aggregation_coordinator_origin;
-    std::vector<GURL> expected_urls;
+    std::optional<GURL> expected_url;
   } kTestCases[] = {
       {
           std::nullopt,
-          {GURL("https://a.test/.well-known/aggregation-service/v1/"
-                "public-keys")},
+          GURL("https://a.test/.well-known/aggregation-service/v1/"
+               "public-keys"),
       },
       {
           url::Origin::Create(GURL("https://a.test")),
-          {GURL("https://a.test/.well-known/aggregation-service/v1/"
-                "public-keys")},
+          GURL("https://a.test/.well-known/aggregation-service/v1/"
+               "public-keys"),
       },
       {
           url::Origin::Create(GURL("https://b.test")),
-          {GURL("https://b.test/.well-known/aggregation-service/v1/"
-                "public-keys")},
+          GURL("https://b.test/.well-known/aggregation-service/v1/"
+               "public-keys"),
       },
       {
           url::Origin::Create(GURL("https://c.test")),
-          {},
+          std::nullopt,
       },
   };
 
@@ -1421,7 +1260,6 @@
                     /*bucket=*/123,
                     /*value=*/456,
                     /*filtering_id=*/std::nullopt)},
-                blink::mojom::AggregationServiceMode::kDefault,
                 test_case.aggregation_coordinator_origin,
                 /*max_contributions_allowed=*/20u,
                 /*filtering_id_max_bytes=*/1u),  // Default max bytes used.
@@ -1439,21 +1277,20 @@
             /*debug_key=*/std::nullopt, /*additional_fields=*/{},
             /*failed_send_attempts=*/0);
 
-    if (test_case.expected_urls.empty()) {
-      EXPECT_FALSE(request.has_value());
-    } else {
-      EXPECT_EQ(request->processing_urls(), test_case.expected_urls);
+    ASSERT_EQ(request.has_value(), test_case.expected_url.has_value());
+
+    if (test_case.expected_url.has_value()) {
+      EXPECT_EQ(request->processing_url(), *test_case.expected_url);
     }
   }
 }
 
 TEST_F(AggregatableReportTest, AggregationCoordinator_SetInReport) {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/std::nullopt);
-
-  AggregatableReport report(std::move(payloads), "example_shared_info",
+  AggregatableReport report(AggregatableReport::AggregationServicePayload(
+                                /*payload=*/kABCD1234AsBytes,
+                                /*key_id=*/"key_1",
+                                /*debug_cleartext_payload=*/std::nullopt),
+                            "example_shared_info",
                             /*debug_key=*/std::nullopt,
                             /*additional_fields=*/{},
                             /*aggregation_coordinator_origin=*/std::nullopt);
@@ -1475,27 +1312,26 @@
 TEST(AggregatableReportPayloadLengthTest, With20Contributions) {
   // NOTE: These expectations are inscrutable when they fail due to
   // `StrictNumeric`, unless we include base/numerics/ostream_operators.h.
-  EXPECT_EQ(AggregatableReport::ComputeTeeBasedPayloadLengthInBytesForTesting(
+  EXPECT_EQ(AggregatableReport::ComputePayloadLengthInBytesForTesting(
                 /*num_contributions=*/20u, /*filtering_id_max_bytes=*/1u),
             847);
 }
 
 TEST(AggregatableReportPayloadLengthTest, With100Contributions) {
-  EXPECT_EQ(AggregatableReport::ComputeTeeBasedPayloadLengthInBytesForTesting(
+  EXPECT_EQ(AggregatableReport::ComputePayloadLengthInBytesForTesting(
                 /*num_contributions=*/100u, /*filtering_id_max_bytes=*/1u),
             4128);
 }
 
 TEST(AggregatableReportPayloadLengthTest, OutOfRange) {
-  EXPECT_FALSE(
-      AggregatableReport::ComputeTeeBasedPayloadLengthInBytesForTesting(
-          /*num_contributions=*/std::numeric_limits<size_t>::max(),
-          /*filtering_id_max_bytes=*/1u)
-          .has_value());
+  EXPECT_FALSE(AggregatableReport::ComputePayloadLengthInBytesForTesting(
+                   /*num_contributions=*/std::numeric_limits<size_t>::max(),
+                   /*filtering_id_max_bytes=*/1u)
+                   .has_value());
   if constexpr (std::numeric_limits<size_t>::max() >
                 std::numeric_limits<uint32_t>::max()) {
     EXPECT_FALSE(
-        AggregatableReport::ComputeTeeBasedPayloadLengthInBytesForTesting(
+        AggregatableReport::ComputePayloadLengthInBytesForTesting(
             // It's critical to convert the max `uint32_t` value to size_t
             // before adding one to avoid an unwanted integer overflow.
             /*num_contributions=*/size_t{std::numeric_limits<uint32_t>::max()} +
@@ -1522,7 +1358,7 @@
                    << ", filtering_id_max_bytes: " << filtering_id_max_bytes);
 
       const std::optional<size_t> predicted_length =
-          AggregatableReport::ComputeTeeBasedPayloadLengthInBytesForTesting(
+          AggregatableReport::ComputePayloadLengthInBytesForTesting(
               num_contributions, filtering_id_max_bytes);
       ASSERT_TRUE(predicted_length.has_value());
 
@@ -1532,14 +1368,13 @@
           contributions(/*count=*/num_contributions, /*value=*/contribution);
       AggregationServicePayloadContents payload_contents(
           AggregationServicePayloadContents::Operation::kHistogram,
-          contributions, blink::mojom::AggregationServiceMode::kTeeBased,
+          contributions,
           /*aggregation_coordinator_origin=*/std::nullopt,
           /*max_contributions_allowed=*/num_contributions,
           filtering_id_max_bytes);
 
       const std::optional<std::vector<uint8_t>> serialized =
-          AggregatableReport::SerializeTeeBasedPayloadForTesting(
-              payload_contents);
+          AggregatableReport::SerializePayloadForTesting(payload_contents);
       ASSERT_TRUE(serialized.has_value());
       EXPECT_EQ(serialized->size(), *predicted_length);
     }
diff --git a/content/browser/aggregation_service/aggregation_service_impl_unittest.cc b/content/browser/aggregation_service/aggregation_service_impl_unittest.cc
index ec1fdb3..d4cc3b34 100644
--- a/content/browser/aggregation_service/aggregation_service_impl_unittest.cc
+++ b/content/browser/aggregation_service/aggregation_service_impl_unittest.cc
@@ -59,11 +59,11 @@
 }
 
 AggregatableReport CreateExampleAggregatableReport() {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/std::nullopt);
-  return AggregatableReport(std::move(payloads), "example_shared_info",
+  return AggregatableReport(AggregatableReport::AggregationServicePayload(
+                                /*payload=*/kABCD1234AsBytes,
+                                /*key_id=*/"key_1",
+                                /*debug_cleartext_payload=*/std::nullopt),
+                            "example_shared_info",
                             /*debug_key=*/std::nullopt,
                             /*additional_fields=*/{},
                             /*aggregation_coordinator_origin=*/std::nullopt);
@@ -72,7 +72,6 @@
 AggregatableReportRequest CreateExampleRequestWithDelayType(
     AggregatableReportRequest::DelayType delay_type) {
   return aggregation_service::CreateExampleRequest(
-      /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
       /*failed_send_attempts=*/0,
       /*aggregation_coordinator_origin=*/std::nullopt, delay_type);
 }
@@ -474,7 +473,6 @@
       });
 
   AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
       /*failed_send_attempts=*/AggregatableReportScheduler::kMaxRetries);
 
   service_impl_->ScheduleReport(std::move(request));
@@ -527,7 +525,6 @@
       });
 
   AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
-      /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
       /*failed_send_attempts=*/AggregatableReportScheduler::kMaxRetries,
       /*aggregation_coordinator_origin=*/std::nullopt, /*delay_type=*/
       AggregatableReportRequest::DelayType::ScheduledWithReducedDelay);
@@ -642,7 +639,6 @@
       aggregation_service::CreateExampleRequest();
   AggregatableReportRequest request_2 =
       aggregation_service::CreateExampleRequest(
-          /*aggregation_mode=*/blink::mojom::AggregationServiceMode::kDefault,
           /*failed_send_attempts=*/2);
 
   service_impl_->ScheduleReport(std::move(request_1));
diff --git a/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc b/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc
index 8bf0bff..1e74b40 100644
--- a/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc
+++ b/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc
@@ -69,7 +69,6 @@
 
 AggregatableReportRequest CreateExampleRequestWithDelayType() {
   return aggregation_service::CreateExampleRequest(
-      blink::mojom::AggregationServiceMode::kDefault,
       /*failed_send_attempts=*/0,
       /*aggregation_coordinator_origin=*/std::nullopt,
       AggregatableReportRequest::DelayType::ScheduledWithFullDelay);
diff --git a/content/browser/aggregation_service/aggregation_service_test_utils.cc b/content/browser/aggregation_service/aggregation_service_test_utils.cc
index da1d236..254b8cc 100644
--- a/content/browser/aggregation_service/aggregation_service_test_utils.cc
+++ b/content/browser/aggregation_service/aggregation_service_test_utils.cc
@@ -77,26 +77,24 @@
 testing::AssertionResult AggregatableReportsEqual(
     const AggregatableReport& expected,
     const AggregatableReport& actual) {
-  if (expected.payloads().size() != actual.payloads().size()) {
-    return testing::AssertionFailure()
-           << "Expected payloads size " << expected.payloads().size()
-           << ", actual: " << actual.payloads().size();
+  const std::optional<AggregationServicePayload>& expected_payload =
+      expected.payload();
+  const std::optional<AggregationServicePayload>& actual_payload =
+      actual.payload();
+
+  if (expected_payload.has_value() != actual_payload.has_value()) {
+    return testing::AssertionFailure() << "Expected payload nullness to match";
   }
 
-  for (size_t i = 0; i < expected.payloads().size(); ++i) {
-    const AggregationServicePayload& expected_payload = expected.payloads()[i];
-    const AggregationServicePayload& actual_payload = actual.payloads()[i];
-
-    if (expected_payload.payload != actual_payload.payload) {
-      return testing::AssertionFailure()
-             << "Expected payloads at payload index " << i << " to match";
+  if (expected_payload.has_value()) {
+    if (expected_payload->payload != actual_payload->payload) {
+      return testing::AssertionFailure() << "Expected payload to match";
     }
 
-    if (expected_payload.key_id != actual_payload.key_id) {
+    if (expected_payload->key_id != actual_payload->key_id) {
       return testing::AssertionFailure()
-             << "Expected key_id " << expected_payload.key_id
-             << " at payload index " << i
-             << ", actual: " << actual_payload.key_id;
+             << "Expected key_id " << expected_payload->key_id
+             << ", actual: " << actual_payload->key_id;
     }
   }
 
@@ -116,19 +114,10 @@
 testing::AssertionResult ReportRequestsEqual(
     const AggregatableReportRequest& expected,
     const AggregatableReportRequest& actual) {
-  if (expected.processing_urls().size() != actual.processing_urls().size()) {
+  if (expected.processing_url() != actual.processing_url()) {
     return testing::AssertionFailure()
-           << "Expected processing_urls size "
-           << expected.processing_urls().size()
-           << ", actual: " << actual.processing_urls().size();
-  }
-  for (size_t i = 0; i < expected.processing_urls().size(); ++i) {
-    if (expected.processing_urls()[i] != actual.processing_urls()[i]) {
-      return testing::AssertionFailure()
-             << "Expected processing_urls()[" << i << "] to be "
-             << expected.processing_urls()[i]
-             << ", actual: " << actual.processing_urls()[i];
-    }
+           << "Expected processing_url to be " << expected.processing_url()
+           << ", actual: " << actual.processing_url();
   }
 
   testing::AssertionResult payload_contents_equal = PayloadContentsEqual(
@@ -198,11 +187,6 @@
              << ", actual: " << actual.contributions[i].value;
     }
   }
-  if (expected.aggregation_mode != actual.aggregation_mode) {
-    return testing::AssertionFailure()
-           << "Expected aggregation_mode " << expected.aggregation_mode
-           << ", actual: " << actual.aggregation_mode;
-  }
 
   if (expected.aggregation_coordinator_origin !=
       actual.aggregation_coordinator_origin) {
@@ -304,18 +288,16 @@
 }
 
 AggregatableReportRequest CreateExampleRequest(
-    blink::mojom::AggregationServiceMode aggregation_mode,
     int failed_send_attempts,
     std::optional<url::Origin> aggregation_coordinator_origin,
     std::optional<AggregatableReportRequest::DelayType> delay_type) {
   return CreateExampleRequestWithReportTime(
-      /*report_time=*/base::Time::Now(), aggregation_mode, failed_send_attempts,
+      /*report_time=*/base::Time::Now(), failed_send_attempts,
       std::move(aggregation_coordinator_origin), std::move(delay_type));
 }
 
 AggregatableReportRequest CreateExampleRequestWithReportTime(
     base::Time report_time,
-    blink::mojom::AggregationServiceMode aggregation_mode,
     int failed_send_attempts,
     std::optional<url::Origin> aggregation_coordinator_origin,
     std::optional<AggregatableReportRequest::DelayType> delay_type) {
@@ -325,7 +307,7 @@
                  {blink::mojom::AggregatableReportHistogramContribution(
                      /*bucket=*/123, /*value=*/456,
                      /*filtering_id=*/std::nullopt)},
-                 aggregation_mode, std::move(aggregation_coordinator_origin),
+                 std::move(aggregation_coordinator_origin),
                  /*max_contributions_allowed=*/20u,
                  /*filtering_id_max_bytes=*/1u),
              AggregatableReportSharedInfo(
@@ -347,7 +329,7 @@
 AggregatableReportRequest CloneReportRequest(
     const AggregatableReportRequest& request) {
   return AggregatableReportRequest::CreateForTesting(
-             request.processing_urls(), request.payload_contents(),
+             request.processing_url(), request.payload_contents(),
              request.shared_info().Clone(), request.delay_type(),
              std::string(request.reporting_path()), request.debug_key(),
              request.additional_fields(), request.failed_send_attempts())
@@ -355,14 +337,7 @@
 }
 
 AggregatableReport CloneAggregatableReport(const AggregatableReport& report) {
-  std::vector<AggregationServicePayload> payloads;
-  for (const AggregationServicePayload& payload : report.payloads()) {
-    payloads.emplace_back(payload.payload, payload.key_id,
-                          payload.debug_cleartext_payload);
-  }
-
-  return AggregatableReport(std::move(payloads),
-                            std::string(report.shared_info()),
+  return AggregatableReport(report.payload(), std::string(report.shared_info()),
                             report.debug_key(), report.additional_fields(),
                             report.aggregation_coordinator_origin());
 }
@@ -542,17 +517,6 @@
   }
 }
 
-std::ostream& operator<<(
-    std::ostream& out,
-    blink::mojom::AggregationServiceMode aggregation_mode) {
-  switch (aggregation_mode) {
-    case blink::mojom::AggregationServiceMode::kTeeBased:
-      return out << "kTeeBased";
-    case blink::mojom::AggregationServiceMode::kExperimentalPoplar:
-      return out << "kExperimentalPoplar";
-  }
-}
-
 std::ostream& operator<<(std::ostream& out,
                          AggregatableReportSharedInfo::DebugMode debug_mode) {
   switch (debug_mode) {
diff --git a/content/browser/aggregation_service/aggregation_service_test_utils.h b/content/browser/aggregation_service/aggregation_service_test_utils.h
index 9db1e2d3..b6d301e 100644
--- a/content/browser/aggregation_service/aggregation_service_test_utils.h
+++ b/content/browser/aggregation_service/aggregation_service_test_utils.h
@@ -27,7 +27,6 @@
 #include "content/browser/aggregation_service/public_key.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom.h"
 #include "third_party/boringssl/src/include/openssl/base.h"
 #include "third_party/boringssl/src/include/openssl/hpke.h"
 
@@ -94,8 +93,6 @@
 
 // Returns an example report request, using the given parameters.
 AggregatableReportRequest CreateExampleRequest(
-    blink::mojom::AggregationServiceMode aggregation_mode =
-        blink::mojom::AggregationServiceMode::kDefault,
     int failed_send_attempts = 0,
     std::optional<url::Origin> aggregation_coordinator_origin = std::nullopt,
     std::optional<AggregatableReportRequest::DelayType> =
@@ -103,8 +100,6 @@
 
 AggregatableReportRequest CreateExampleRequestWithReportTime(
     base::Time report_time,
-    blink::mojom::AggregationServiceMode aggregation_mode =
-        blink::mojom::AggregationServiceMode::kDefault,
     int failed_send_attempts = 0,
     std::optional<url::Origin> aggregation_coordinator_origin = std::nullopt,
     std::optional<AggregatableReportRequest::DelayType> = std::nullopt);
@@ -255,8 +250,6 @@
     std::ostream& out,
     AggregationServicePayloadContents::Operation operation);
 std::ostream& operator<<(std::ostream& out,
-                         blink::mojom::AggregationServiceMode aggregation_mode);
-std::ostream& operator<<(std::ostream& out,
                          AggregatableReportSharedInfo::DebugMode debug_mode);
 
 bool operator==(const PublicKey& a, const PublicKey& b);
diff --git a/content/browser/aggregation_service/proto/aggregatable_report.proto b/content/browser/aggregation_service/proto/aggregatable_report.proto
index c127ac4..e5da21d 100644
--- a/content/browser/aggregation_service/proto/aggregatable_report.proto
+++ b/content/browser/aggregation_service/proto/aggregatable_report.proto
@@ -10,12 +10,6 @@
 
 option optimize_for = LITE_RUNTIME;
 
-// Proto equivalent of `blink::mojom::AggregationServiceMode`
-enum AggregationServiceMode {
-  TEE_BASED = 0;
-  EXPERIMENTAL_POPLAR = 1;
-}
-
 // Proto equivalent of `blink::mojom::AggregatableReportHistogramContribution`
 message AggregatableReportHistogramContribution {
   uint64 bucket_high = 1;
@@ -32,11 +26,12 @@
 
   Operation operation = 1;
   repeated AggregatableReportHistogramContribution contributions = 2;
-  AggregationServiceMode aggregation_mode = 3;
   int32 max_contributions_allowed = 5;
   optional string aggregation_coordinator_origin = 6;
   optional uint32 filtering_id_max_bytes = 7;
 
+  reserved 3;
+  reserved "aggregation_mode";
   reserved 4;
   reserved "aggregation_coordinator";
 }
diff --git a/content/browser/android/overscroll_controller_android.cc b/content/browser/android/overscroll_controller_android.cc
index 29a9d3ec..8b092c9 100644
--- a/content/browser/android/overscroll_controller_android.cc
+++ b/content/browser/android/overscroll_controller_android.cc
@@ -188,9 +188,10 @@
   if (refresh_effect_) {
     refresh_effect_->OnOverscrolled(params.overscroll_behavior,
                                     params.accumulated_overscroll);
-    is_handling_sequence_ = refresh_effect_->IsActive();
+    bool refresh_effect_active = refresh_effect_->IsActive();
+    is_handling_sequence_ |= refresh_effect_active;
 
-    if (is_handling_sequence_ || refresh_effect_->IsAwaitingScrollUpdateAck()) {
+    if (refresh_effect_active || refresh_effect_->IsAwaitingScrollUpdateAck()) {
       // An active (or potentially active) refresh effect should always pre-empt
       // the passive glow effect.
       return;
@@ -304,26 +305,24 @@
 
 bool OverscrollControllerAndroid::OnTouchEvent(
     const ui::MotionEventAndroid& event) {
+  const auto action = event.GetAction();
+  // This will consume touch events until the next Action::DOWN. Ideally we
+  // should consume until the final Action::UP/Action::CANCEL. But, apparently,
+  // we can't reliably determine the final Action::CANCEL in a multi-touch
+  // scenario. See https://crbug.com/653212.
+  if (action == ui::MotionEventAndroid::Action::DOWN) {
+    is_handling_sequence_ = false;
+  }
+
   const bool handles_current_event = IsHandlingInputSequence();
 
-  const auto action = event.GetAction();
-  const bool is_sequence_terminating_action =
-      (action == ui::MotionEventAndroid::Action::UP ||
-       action == ui::MotionEventAndroid::Action::CANCEL);
-
-  // Clean up state after processing a terminating action.
-  absl::Cleanup update_state = [this, &is_sequence_terminating_action] {
-    if (is_sequence_terminating_action) {
-      last_pos_ = gfx::Vector2dF();  // Reset last position.
-      is_handling_sequence_ = false;
-    }
-  };
-
+  // |refresh_effect_| might have been consuming input events earlier, return if
+  // the OverscrollController is consuming the whole input sequence.
   if (!ShouldHandleInputEvents()) {
     return handles_current_event;
   }
 
-  switch (event.GetAction()) {
+  switch (action) {
     case ui::MotionEventAndroid::Action::DOWN:
       last_pos_ = gfx::Vector2dF(event.GetXPix(0), event.GetYPix(0));
       break;
diff --git a/content/browser/android/overscroll_controller_android.h b/content/browser/android/overscroll_controller_android.h
index 8ea11958..6fa3e9a 100644
--- a/content/browser/android/overscroll_controller_android.h
+++ b/content/browser/android/overscroll_controller_android.h
@@ -80,6 +80,9 @@
   void Enable();
   void Disable();
 
+  // Returns true if the controller is actively handling the current input
+  // sequence. This state persists until reset by
+  // MotionEventAndroid::Action::DOWN from the next input sequence.
   bool IsHandlingInputSequence();
 
   // Returns true if |event| is consumed by an overscroll effect, in which
diff --git a/content/browser/attribution_reporting/aggregatable_attribution_utils.cc b/content/browser/attribution_reporting/aggregatable_attribution_utils.cc
index 5d2c2f4..5d93c0f5 100644
--- a/content/browser/attribution_reporting/aggregatable_attribution_utils.cc
+++ b/content/browser/attribution_reporting/aggregatable_attribution_utils.cc
@@ -193,7 +193,6 @@
       AggregationServicePayloadContents(
           AggregationServicePayloadContents::Operation::kHistogram,
           aggregatable_data->contributions(),
-          blink::mojom::AggregationServiceMode::kDefault,
           aggregatable_data->aggregation_coordinator_origin()
               ? std::make_optional(
                     **aggregatable_data->aggregation_coordinator_origin())
diff --git a/content/browser/attribution_reporting/aggregatable_debug_report.cc b/content/browser/attribution_reporting/aggregatable_debug_report.cc
index d06ea28..5ea563b 100644
--- a/content/browser/attribution_reporting/aggregatable_debug_report.cc
+++ b/content/browser/attribution_reporting/aggregatable_debug_report.cc
@@ -346,7 +346,7 @@
   return AggregatableReportRequest::Create(
       AggregationServicePayloadContents(
           AggregationServicePayloadContents::Operation::kHistogram,
-          contributions_, blink::mojom::AggregationServiceMode::kDefault,
+          contributions_,
           aggregation_coordinator_origin_
               ? std::make_optional(**aggregation_coordinator_origin_)
               : std::nullopt,
diff --git a/content/browser/attribution_reporting/aggregatable_debug_report_unittest.cc b/content/browser/attribution_reporting/aggregatable_debug_report_unittest.cc
index 7c15898..709d421 100644
--- a/content/browser/attribution_reporting/aggregatable_debug_report_unittest.cc
+++ b/content/browser/attribution_reporting/aggregatable_debug_report_unittest.cc
@@ -999,7 +999,6 @@
           {AggregatableReportHistogramContribution(
               /*bucket=*/123,
               /*value=*/456, /*filtering_id=*/std::nullopt)},
-          blink::mojom::AggregationServiceMode::kDefault,
           /*aggregation_coordinator_origin=*/
           url::Origin::Create(GURL("https://a.test")),
           /*max_contributions_allowed=*/2u, /*filtering_id_max_bytes=*/1u),
diff --git a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
index 2d05257..a53df30 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
@@ -167,14 +167,6 @@
 }
 
 AggregatableReport CreateExampleAggregatableReport() {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/std::nullopt);
-  payloads.emplace_back(/*payload=*/kEFGH5678AsBytes,
-                        /*key_id=*/"key_2",
-                        /*debug_cleartext_payload=*/std::nullopt);
-
   base::Value::Dict additional_fields;
   additional_fields.Set("source_registration_time", "1234569600");
   additional_fields.Set(
@@ -190,21 +182,17 @@
       /*api_version=*/"",
       /*api_identifier=*/"attribution-reporting");
 
-  return AggregatableReport(std::move(payloads), shared_info.SerializeAsJson(),
+  return AggregatableReport(AggregatableReport::AggregationServicePayload(
+                                /*payload=*/kABCD1234AsBytes,
+                                /*key_id=*/"key_1",
+                                /*debug_cleartext_payload=*/std::nullopt),
+                            shared_info.SerializeAsJson(),
                             /*debug_key=*/std::nullopt,
                             /*additional_fields=*/{},
                             /*aggregation_coordinator_origin=*/std::nullopt);
 }
 
 AggregatableReport CreateExampleAggregatableDebugReport() {
-  std::vector<AggregatableReport::AggregationServicePayload> payloads;
-  payloads.emplace_back(/*payload=*/kABCD1234AsBytes,
-                        /*key_id=*/"key_1",
-                        /*debug_cleartext_payload=*/std::nullopt);
-  payloads.emplace_back(/*payload=*/kEFGH5678AsBytes,
-                        /*key_id=*/"key_2",
-                        /*debug_cleartext_payload=*/std::nullopt);
-
   base::Value::Dict additional_fields;
   additional_fields.Set(
       "attribution_destination",
@@ -219,7 +207,11 @@
       /*api_version=*/"0.1",
       /*api_identifier=*/"attribution-reporting-debug");
 
-  return AggregatableReport(std::move(payloads), shared_info.SerializeAsJson(),
+  return AggregatableReport(AggregatableReport::AggregationServicePayload(
+                                /*payload=*/kABCD1234AsBytes,
+                                /*key_id=*/"key_1",
+                                /*debug_cleartext_payload=*/std::nullopt),
+                            shared_info.SerializeAsJson(),
                             /*debug_key=*/std::nullopt,
                             /*additional_fields=*/{},
                             /*aggregation_coordinator_origin=*/std::nullopt);
diff --git a/content/browser/blob_storage/blob_url_browsertest.cc b/content/browser/blob_storage/blob_url_browsertest.cc
index c7a1882..904cf3e 100644
--- a/content/browser/blob_storage/blob_url_browsertest.cc
+++ b/content/browser/blob_storage/blob_url_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/pattern.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/values_test_util.h"
 #include "base/test/with_feature_override.h"
 #include "build/build_config.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
@@ -283,35 +284,29 @@
   void WaitForIssueAndCheckUrl(const std::string& url,
                                TestDevToolsProtocolClient* client,
                                const std::string& expected_info_enum) {
-    auto is_blob_url_issue = [](const base::Value::Dict& params) {
-      const std::string* issue_code =
-          params.FindStringByDottedPath("issue.code");
-      return issue_code && *issue_code == "PartitioningBlobURLIssue";
-    };
-
     // Wait for notification of a Partitioning Blob URL Issue.
     base::Value::Dict params = client->WaitForMatchingNotification(
-        "Audits.issueAdded", base::BindRepeating(is_blob_url_issue));
+        "Audits.issueAdded",
+        base::BindRepeating([](const base::Value::Dict& params) {
+          const std::string* issue_code =
+              params.FindStringByDottedPath("issue.code");
+          return issue_code && *issue_code == "PartitioningBlobURLIssue";
+        }));
 
-    EXPECT_EQ(*params.FindStringByDottedPath("issue.code"),
-              "PartitioningBlobURLIssue");
-
-    base::Value::Dict* partitioning_blob_url_issue_details =
-        params.FindDictByDottedPath(
-            "issue.details.partitioningBlobURLIssueDetails");
-    ASSERT_TRUE(partitioning_blob_url_issue_details);
-
-    // Verify the reported blob_url match the expected url.
-    std::string* blob_url_ptr =
-        partitioning_blob_url_issue_details->FindString("url");
-    EXPECT_EQ(*blob_url_ptr, url);
-
-    // Verify the reported partitioningBlobURLInfo matches the expected enum.
-    std::string* info_enum_ptr =
-        partitioning_blob_url_issue_details->FindString(
-            "partitioningBlobURLInfo");
-    ASSERT_TRUE(info_enum_ptr);
-    EXPECT_EQ(*info_enum_ptr, expected_info_enum);
+    EXPECT_THAT(params, base::test::IsSupersetOfValue(
+                            base::test::ParseJson(content::JsReplace(
+                                R"({
+                  "issue": {
+                    "code": "PartitioningBlobURLIssue",
+                    "details": {
+                      "partitioningBlobURLIssueDetails": {
+                        "url": $1,
+                        "partitioningBlobURLInfo": $2,
+                      }
+                    }
+                  }
+                })",
+                                url, expected_info_enum))));
 
     // Clear existing notifications so subsequent calls don't fail by checking
     // `url` against old notifications.
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 4419b68..4fb8684 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -2251,6 +2251,8 @@
       return protocol::Network::BlockedReasonEnum::Origin;
     case blink::ResourceRequestBlockedReason::kInspector:
       return protocol::Network::BlockedReasonEnum::Inspector;
+    case blink::ResourceRequestBlockedReason::kIntegrity:
+      return protocol::Network::BlockedReasonEnum::Integrity;
     case blink::ResourceRequestBlockedReason::kSubresourceFilter:
       return protocol::Network::BlockedReasonEnum::SubresourceFilter;
     case blink::ResourceRequestBlockedReason::kContentType:
diff --git a/content/browser/devtools/protocol/storage_handler.cc b/content/browser/devtools/protocol/storage_handler.cc
index 288bc21..7c0fc74 100644
--- a/content/browser/devtools/protocol/storage_handler.cc
+++ b/content/browser/devtools/protocol/storage_handler.cc
@@ -1455,7 +1455,7 @@
           std::move(callback)));
 }
 
-GlobalRenderFrameHostId StorageHandler::AssociatedMainFrameId() const {
+GlobalRenderFrameHostId StorageHandler::AssociatedFrameHostId() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return frame_host_ ? frame_host_->GetGlobalId() : GlobalRenderFrameHostId();
 }
diff --git a/content/browser/devtools/protocol/storage_handler.h b/content/browser/devtools/protocol/storage_handler.h
index 0b17d01f..5241f91 100644
--- a/content/browser/devtools/protocol/storage_handler.h
+++ b/content/browser/devtools/protocol/storage_handler.h
@@ -223,7 +223,7 @@
                     const SendResult&) override;
 
   // SharedStorageObserverInterface
-  GlobalRenderFrameHostId AssociatedMainFrameId() const override;
+  GlobalRenderFrameHostId AssociatedFrameHostId() const override;
   bool ShouldReceiveAllReports() const override;
   void OnSharedStorageAccessed(
       base::Time access_time,
diff --git a/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc b/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc
index 3288373..34b7925 100644
--- a/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc
+++ b/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc
@@ -56,7 +56,6 @@
                 /*bucket=*/1,
                 /*value=*/2,
                 /*filtering_id=*/std::nullopt),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(),
             /*error_event=*/std::nullopt);
 
@@ -67,7 +66,6 @@
                 /*bucket=*/3,
                 /*value=*/4,
                 /*filtering_id=*/1),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(),
             /*error_event=*/std::nullopt);
 
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.cc b/content/browser/first_party_sets/first_party_sets_handler_impl_instance.cc
index 782a74f64..978e2db 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl_instance.cc
@@ -124,7 +124,7 @@
 }
 
 void FirstPartySetsHandlerImplInstance::GetContextConfigForPolicy(
-    const base::Value::Dict* policy,
+    base::optional_ref<const base::Value::Dict> policy,
     base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!policy) {
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h b/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h
index 794e409..ed82fe9 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h
@@ -75,7 +75,7 @@
       const net::SchemefulSite& site,
       const net::FirstPartySetsContextConfig& config) const override;
   void GetContextConfigForPolicy(
-      const base::Value::Dict* policy,
+      base::optional_ref<const base::Value::Dict> policy,
       base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback)
       override;
   void ClearSiteDataOnChangedSetsForContext(
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc b/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc
index 74db0af5..dab5f83 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc
@@ -177,7 +177,7 @@
   }
 
   net::FirstPartySetsContextConfig GetContextConfigForPolicy(
-      const base::Value::Dict* policy) {
+      base::optional_ref<const base::Value::Dict> policy) {
     base::test::TestFuture<net::FirstPartySetsContextConfig> future;
     handler().GetContextConfigForPolicy(policy, future.GetCallback());
     return future.Take();
@@ -269,10 +269,10 @@
   // Should already be able to answer queries, even before Init is called.
   EXPECT_THAT(handler().GetSets(base::NullCallback()), Optional(_));
 
-  EXPECT_EQ(GetContextConfigForPolicy(nullptr),
+  EXPECT_EQ(GetContextConfigForPolicy(std::nullopt),
             net::FirstPartySetsContextConfig());
 
-  base::Value::Dict policy = base::test::ParseJsonDict(R"(
+  EXPECT_EQ(GetContextConfigForPolicy(base::test::ParseJsonDict(R"(
                 {
                 "replacements": [
                   {
@@ -281,8 +281,7 @@
                   }
                 ]
               }
-            )");
-  EXPECT_EQ(GetContextConfigForPolicy(&policy),
+            )")),
             net::FirstPartySetsContextConfig());
 
   // The local set declaration should be ignored, since the handler is disabled.
@@ -798,9 +797,9 @@
 
 TEST_F(FirstPartySetsHandlerGetContextConfigForPolicyTest,
        DefaultOverridesPolicy_DefaultContextConfigs) {
-  base::Value::Dict policy;
   base::test::TestFuture<net::FirstPartySetsContextConfig> future;
-  handler().GetContextConfigForPolicy(&policy, future.GetCallback());
+  handler().GetContextConfigForPolicy(base::Value::Dict(),
+                                      future.GetCallback());
 
   InitPublicFirstPartySets();
   EXPECT_EQ(future.Take(), net::FirstPartySetsContextConfig());
@@ -808,12 +807,12 @@
 
 TEST_F(FirstPartySetsHandlerGetContextConfigForPolicyTest,
        MalformedOverridesPolicy_DefaultContextConfigs) {
-  base::Value::Dict policy = base::test::ParseJsonDict(R"({
+  base::test::TestFuture<net::FirstPartySetsContextConfig> future;
+  handler().GetContextConfigForPolicy(base::test::ParseJsonDict(R"({
     "replacements": 123,
     "additions": true
-  })");
-  base::test::TestFuture<net::FirstPartySetsContextConfig> future;
-  handler().GetContextConfigForPolicy(&policy, future.GetCallback());
+  })"),
+                                      future.GetCallback());
 
   InitPublicFirstPartySets();
   EXPECT_EQ(future.Take(), net::FirstPartySetsContextConfig());
@@ -821,7 +820,8 @@
 
 TEST_F(FirstPartySetsHandlerGetContextConfigForPolicyTest,
        NonDefaultOverridesPolicy_NonDefaultContextConfigs) {
-  base::Value::Dict policy = base::test::ParseJsonDict(R"(
+  base::test::TestFuture<net::FirstPartySetsContextConfig> future;
+  handler().GetContextConfigForPolicy(base::test::ParseJsonDict(R"(
                 {
                 "replacements": [
                   {
@@ -836,15 +836,14 @@
                   }
                 ]
               }
-            )");
-  base::test::TestFuture<net::FirstPartySetsContextConfig> future;
-  handler().GetContextConfigForPolicy(&policy, future.GetCallback());
+            )"),
+                                      future.GetCallback());
 
   InitPublicFirstPartySets();
   // We don't care what the customizations are, here; we only care that they're
   // not a no-op.
   EXPECT_FALSE(future.Take().empty());
-  EXPECT_EQ(GetContextConfigForPolicy(nullptr),
+  EXPECT_EQ(GetContextConfigForPolicy(std::nullopt),
             net::FirstPartySetsContextConfig());
 }
 
diff --git a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc
index b9ac04c..6c75045 100644
--- a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc
+++ b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc
@@ -63,7 +63,7 @@
 }
 
 void ScopedMockFirstPartySetsHandler::GetContextConfigForPolicy(
-    const base::Value::Dict* policy,
+    base::optional_ref<const base::Value::Dict> policy,
     base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
   if (should_deadlock_) {
     return;
diff --git a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h
index 65fc9a0..26e5ae2 100644
--- a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h
+++ b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h
@@ -46,7 +46,7 @@
       const net::SchemefulSite& site,
       const net::FirstPartySetsContextConfig& config) const override;
   void GetContextConfigForPolicy(
-      const base::Value::Dict* policy,
+      base::optional_ref<const base::Value::Dict> policy,
       base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback)
       override;
   void ClearSiteDataOnChangedSetsForContext(
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index 5e4d8b2e..d40f87a 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -409,7 +409,6 @@
                         /*bucket=*/1,
                         /*value=*/2,
                         /*filtering_id=*/std::nullopt)),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New());
 
 const auction_worklet::mojom::PrivateAggregationRequestPtr
@@ -423,7 +422,6 @@
                                 kBelowKAnonThreshold),
                         /*value=*/0,
                         /*filtering_id=*/std::nullopt)),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New());
 
 const auction_worklet::mojom::PrivateAggregationRequestPtr
@@ -435,7 +433,6 @@
                         /*bucket=*/3,
                         /*value=*/4,
                         /*filtering_id=*/std::nullopt)),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New());
 
 const auction_worklet::mojom::PrivateAggregationRequestPtr
@@ -447,7 +444,6 @@
                         /*bucket=*/5,
                         /*value=*/6,
                         /*filtering_id=*/std::nullopt)),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New());
 
 const auction_worklet::mojom::PrivateAggregationRequestPtr
@@ -459,7 +455,6 @@
                         /*bucket=*/7,
                         /*value=*/8,
                         /*filtering_id=*/std::nullopt)),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New());
 
 // gTest helper to allow both finalized and non-finalized requests to be
@@ -485,7 +480,6 @@
 
   return request->contribution->get_histogram_contribution() ==
              finalized->contribution &&
-         request->aggregation_mode == finalized->aggregation_mode &&
          request->debug_mode_details == finalized->debug_mode_details;
 }
 bool RequestsEqual(
@@ -1598,7 +1592,6 @@
           NewHistogramContribution(
               blink::mojom::AggregatableReportHistogramContribution::New(
                   bucket, value, filtering_id)),
-      blink::mojom::AggregationServiceMode::kDefault,
       std::move(debug_mode_details));
 }
 
@@ -1636,7 +1629,6 @@
   return auction_worklet::mojom::PrivateAggregationRequest::New(
       auction_worklet::mojom::AggregatableReportContribution::
           NewForEventContribution(contribution.Clone()),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 }
 
@@ -1649,7 +1641,6 @@
   return auction_worklet::mojom::FinalizedPrivateAggregationRequest::New(
       blink::mojom::AggregatableReportHistogramContribution::New(bucket, value,
                                                                  filtering_id),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New(), error_event);
 }
 
@@ -1670,7 +1661,6 @@
   return auction_worklet::mojom::PrivateAggregationRequest::New(
       auction_worklet::mojom::AggregatableReportContribution::
           NewForEventContribution(contribution.Clone()),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 }
 
diff --git a/content/browser/interest_group/bidding_and_auction_response.cc b/content/browser/interest_group/bidding_and_auction_response.cc
index 4985c6a5..771736de 100644
--- a/content/browser/interest_group/bidding_and_auction_response.cc
+++ b/content/browser/interest_group/bidding_and_auction_response.cc
@@ -515,7 +515,6 @@
                               /*bucket=*/U128FromBigEndian(*bucket),
                               /*value=*/*value,
                               /*filtering_id=*/std::nullopt)),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New()));
     }
   }
@@ -816,8 +815,6 @@
                               auction_worklet::mojom::ForEventSignalValue::
                                   NewIntValue(*value),
                               filtering_id, event_type->Clone())),
-              // TODO(qingxinwu): consider allowing this to be set
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New());
       output.component_win_pagg_requests[agg_phase_key].emplace_back(
           std::move(request));
@@ -836,8 +833,6 @@
                   /*bucket=*/U128FromBigEndian(*bucket),
                   /*value=*/*value,
                   /*filtering_id=*/filtering_id),
-              // TODO(qingxinwu): consider allowing this to be set
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(), error_event);
 
       if (event_type->is_non_reserved()) {
diff --git a/content/browser/interest_group/bidding_and_auction_response_unittest.cc b/content/browser/interest_group/bidding_and_auction_response_unittest.cc
index eee738e3..a34e962 100644
--- a/content/browser/interest_group/bidding_and_auction_response_unittest.cc
+++ b/content/browser/interest_group/bidding_and_auction_response_unittest.cc
@@ -344,8 +344,6 @@
                       auction_worklet::mojom::ForEventSignalValue::NewIntValue(
                           value),
                       filtering_id, std::move(event))),
-      // TODO(qingxinwu): consider allowing this to be set
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 }
 
@@ -358,8 +356,6 @@
           /*bucket=*/bucket,
           /*value=*/value,
           /*filtering_id=*/filtering_id),
-      // TODO(qingxinwu): consider allowing this to be set
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New(),
       /*error_event=*/std::nullopt);
 }
@@ -1799,7 +1795,6 @@
                                      /*bucket=*/1025,
                                      /*value=*/2,
                                      /*filtering_id=*/std::nullopt)),
-                     blink::mojom::AggregationServiceMode::kDefault,
                      blink::mojom::DebugModeDetails::New()));
          return response;
        }()},
@@ -1835,7 +1830,6 @@
                                      /*bucket=*/1025,
                                      /*value=*/2,
                                      /*filtering_id=*/std::nullopt)),
-                     blink::mojom::AggregationServiceMode::kDefault,
                      blink::mojom::DebugModeDetails::New()));
          response.k_anon_ghost_winner->non_kanon_private_aggregation_requests
              .emplace_back(
@@ -1847,7 +1841,6 @@
                                      /*bucket=*/1538,
                                      /*value=*/4,
                                      /*filtering_id=*/std::nullopt)),
-                     blink::mojom::AggregationServiceMode::kDefault,
                      blink::mojom::DebugModeDetails::New()));
          return response;
        }()},
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc
index 843ff076..b96ca48c 100644
--- a/content/browser/interest_group/interest_group_auction.cc
+++ b/content/browser/interest_group/interest_group_auction.cc
@@ -4199,8 +4199,6 @@
               base::saturated_cast<int32_t>(
                   std::max(0.0, value * report_buyers_config->scale)),
               /*filtering_id=*/std::nullopt),
-          // TODO(caraitto): Consider allowing this to be set.
-          blink::mojom::AggregationServiceMode::kDefault,
           std::move(debug_mode_details),
           /*error_event=*/std::nullopt));
   return true;
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 f939de4..1c7db03 100644
--- a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
@@ -89,7 +89,7 @@
   return auction_worklet::mojom::PrivateAggregationRequest::New(
       auction_worklet::mojom::AggregatableReportContribution::
           NewHistogramContribution(std::move(finalized->contribution)),
-      finalized->aggregation_mode, std::move(finalized->debug_mode_details));
+      std::move(finalized->debug_mode_details));
 }
 
 template <typename T>
@@ -583,7 +583,6 @@
                   /*bucket=*/1,
                   /*value=*/2,
                   /*filtering_id=*/std::nullopt),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(),
               /*error_event=*/std::nullopt);
   const auction_worklet::mojom::FinalizedPrivateAggregationRequestPtr
@@ -593,7 +592,6 @@
                   /*bucket=*/3,
                   /*value=*/4,
                   /*filtering_id=*/0),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(),
               /*error_event=*/std::nullopt);
   const auction_worklet::mojom::FinalizedPrivateAggregationRequestPtr
@@ -603,7 +601,6 @@
                   /*bucket=*/5,
                   /*value=*/6,
                   /*filtering_id=*/1),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(),
               /*error_event=*/std::nullopt);
   const auction_worklet::mojom::FinalizedPrivateAggregationRequestPtr
@@ -613,7 +610,6 @@
                   /*bucket=*/7,
                   /*value=*/8,
                   /*filtering_id=*/255),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(),
               /*error_event=*/std::nullopt);
   const auction_worklet::mojom::FinalizedPrivateAggregationRequestPtr
@@ -623,7 +619,6 @@
                   /*bucket=*/9,
                   /*value=*/10,
                   /*filtering_id=*/std::nullopt),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(),
               /*error_event=*/std::nullopt);
   const auction_worklet::mojom::FinalizedPrivateAggregationRequestPtr
@@ -633,7 +628,6 @@
                   /*bucket=*/42,
                   /*value=*/24,
                   /*filtering_id=*/std::nullopt),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(),
               /*error_event=*/std::nullopt);
   const auction_worklet::mojom::PrivateAggregationRequestPtr
@@ -650,7 +644,6 @@
                               /*filtering_id=*/std::nullopt,
                               auction_worklet::mojom::EventType::NewNonReserved(
                                   "event_type"))),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New());
   const auction_worklet::mojom::PrivateAggregationRequestPtr
       kReservedOncePrivateAggregationRequest =
@@ -669,7 +662,6 @@
                                       auction_worklet::mojom::
                                           ReservedNonErrorEventType::
                                               kReservedOnce))),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New());
   const auction_worklet::mojom::PrivateAggregationRequestPtr
       kBonusNonReservedPrivateAggregationRequest =
@@ -685,7 +677,6 @@
                               /*filtering_id=*/std::nullopt,
                               auction_worklet::mojom::EventType::NewNonReserved(
                                   "event_type2"))),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New());
   const auction_worklet::mojom::PrivateAggregationRequestPtr
       kReportWinNonReservedPrivateAggregationRequest =
@@ -701,7 +692,6 @@
                               /*filtering_id=*/0,
                               auction_worklet::mojom::EventType::NewNonReserved(
                                   "event_type"))),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New());
 
   const auction_worklet::mojom::PrivateAggregationRequestPtr
@@ -720,7 +710,6 @@
                                   NewReservedError(auction_worklet::mojom::
                                                        ReservedErrorEventType::
                                                            kReportSuccess))),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New());
   const auction_worklet::mojom::FinalizedPrivateAggregationRequestPtr
       kErrorEventFinalizedPrivateAggregationRequest =
@@ -729,7 +718,6 @@
                   /*bucket=*/3,
                   /*value=*/4,
                   /*filtering_id=*/0),
-              blink::mojom::AggregationServiceMode::kDefault,
               blink::mojom::DebugModeDetails::New(),
               blink::mojom::PrivateAggregationErrorEvent::kReportSuccess);
 
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 bab55d1b..41ac1b9 100644
--- a/content/browser/interest_group/interest_group_pa_report_util.cc
+++ b/content/browser/interest_group/interest_group_pa_report_util.cc
@@ -364,7 +364,6 @@
             auction_worklet::mojom::FinalizedPrivateAggregationRequest::New(
                 /*contribution=*/std::move(
                     request->contribution->get_histogram_contribution()),
-                request->aggregation_mode,
                 std::move(request->debug_mode_details),
                 /*error_event=*/std::nullopt);
 
@@ -427,7 +426,7 @@
 
   PrivateAggregationRequestWithEventType request_with_event_type(
       auction_worklet::mojom::FinalizedPrivateAggregationRequest::New(
-          std::move(calculated_contribution), request->aggregation_mode,
+          std::move(calculated_contribution),
           std::move(request->debug_mode_details),
           ConvertErrorEventToPAggType(reserved_error_event_type)),
       non_reserved_event_type);
@@ -484,10 +483,6 @@
        requests) {
     CHECK(request->debug_mode_details);
 
-    // TODO(alexmt): Split by this too when it can be non-default.
-    CHECK_EQ(request->aggregation_mode,
-             blink::mojom::AggregationServiceMode::kDefault);
-
     blink::mojom::DebugModeDetailsPtr debug_mode_details =
         std::move(request->debug_mode_details);
 
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 b64cfec..38487f3 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
@@ -30,7 +30,6 @@
                 /*bucket=*/123,
                 /*value=*/45,
                 /*filtering_id=*/std::nullopt),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(),
             /*error_event=*/std::nullopt),
         /*event_type=*/std::nullopt);
@@ -66,7 +65,6 @@
           NewHistogramContribution(
               blink::mojom::AggregatableReportHistogramContribution::New(
                   bucket, value, filtering_id)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 }
 
@@ -82,7 +80,6 @@
   return auction_worklet::mojom::FinalizedPrivateAggregationRequest::New(
       blink::mojom::AggregatableReportHistogramContribution::New(bucket, value,
                                                                  filtering_id),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New(), error_event);
 }
 
@@ -122,7 +119,6 @@
   return auction_worklet::mojom::PrivateAggregationRequest::New(
       auction_worklet::mojom::AggregatableReportContribution::
           NewForEventContribution(std::move(contribution)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 }
 
@@ -144,7 +140,6 @@
   return auction_worklet::mojom::PrivateAggregationRequest::New(
       auction_worklet::mojom::AggregatableReportContribution::
           NewForEventContribution(std::move(contribution)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 }
 
@@ -166,7 +161,6 @@
   return auction_worklet::mojom::PrivateAggregationRequest::New(
       auction_worklet::mojom::AggregatableReportContribution::
           NewForEventContribution(std::move(contribution)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 }
 
@@ -196,7 +190,6 @@
           NewHistogramContribution(
               blink::mojom::AggregatableReportHistogramContribution::New(
                   /*bucket=*/123, /*value=*/45, /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 
   EXPECT_EQ(kExpectedRequestWithReservedEventType,
@@ -219,14 +212,13 @@
 }
 
 // FillInPrivateAggregationRequest() sets returned request's
-// aggregation_mode and debug_mode_details correctly.
-TEST_F(InterestGroupPaReportUtilTest, AggregationModeAndDebugMode) {
+// debug_mode_details correctly.
+TEST_F(InterestGroupPaReportUtilTest, DebugMode) {
   auction_worklet::mojom::PrivateAggregationRequest request(
       auction_worklet::mojom::AggregatableReportContribution::
           NewHistogramContribution(
               blink::mojom::AggregatableReportHistogramContribution::New(
                   /*bucket=*/123, /*value=*/45, /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar,
       blink::mojom::DebugModeDetails::New(
           /*is_enabled=*/true,
           /*debug_key=*/blink::mojom::DebugKey::New(1234u)));
@@ -234,7 +226,6 @@
   auction_worklet::mojom::FinalizedPrivateAggregationRequest expected_request(
       blink::mojom::AggregatableReportHistogramContribution::New(
           /*bucket=*/123, /*value=*/45, /*filtering_id=*/std::nullopt),
-      blink::mojom::AggregationServiceMode::kExperimentalPoplar,
       blink::mojom::DebugModeDetails::New(
           /*is_enabled=*/true,
           /*debug_key=*/blink::mojom::DebugKey::New(1234u)),
@@ -499,7 +490,6 @@
           blink::mojom::AggregatableReportHistogramContribution::New(
               /*bucket=*/6, /*value=*/45,
               /*filtering_id=*/std::nullopt),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New(),
           /*error_event=*/std::nullopt),
       /*event_type=*/std::nullopt);
diff --git a/content/browser/interest_group/test_interest_group_private_aggregation_manager.cc b/content/browser/interest_group/test_interest_group_private_aggregation_manager.cc
index 3d4b7ddb..858bff0 100644
--- a/content/browser/interest_group/test_interest_group_private_aggregation_manager.cc
+++ b/content/browser/interest_group/test_interest_group_private_aggregation_manager.cc
@@ -96,7 +96,6 @@
     private_aggregation_requests_[receiver_id].push_back(
         auction_worklet::mojom::FinalizedPrivateAggregationRequest::New(
             std::move(contribution),
-            blink::mojom::AggregationServiceMode::kDefault,
             /*debug_mode_details=*/nullptr,  // Will be filled in later.
             /*error_event=*/std::nullopt));
   }
@@ -114,7 +113,6 @@
     private_aggregation_requests_[receiver_id].push_back(
         auction_worklet::mojom::FinalizedPrivateAggregationRequest::New(
             std::move(contribution),
-            blink::mojom::AggregationServiceMode::kDefault,
             /*debug_mode_details=*/nullptr,  // Will be filled in later.
             error_event));
   }
diff --git a/content/browser/network/reporting_service_proxy.cc b/content/browser/network/reporting_service_proxy.cc
index db51e423..e994f0ae 100644
--- a/content/browser/network/reporting_service_proxy.cc
+++ b/content/browser/network/reporting_service_proxy.cc
@@ -122,6 +122,20 @@
     QueueReport(url, group, "csp-violation", std::move(body));
   }
 
+  void QueueIntegrityViolationReport(const GURL& url,
+                                     const std::string& endpoint,
+                                     const std::string& document_url,
+                                     const std::string& blocked_url,
+                                     const std::string& destination,
+                                     bool report_only) override {
+    base::Value::Dict body;
+    body.Set("documentURL", document_url);
+    body.Set("blockedURL", blocked_url);
+    body.Set("destination", destination);
+    body.Set("reportOnly", report_only);
+    QueueReport(url, endpoint, "integrity-violation", std::move(body));
+  }
+
   void QueuePermissionsPolicyViolationReport(
       const GURL& url,
       const std::string& endpoint,
diff --git a/content/browser/private_aggregation/private_aggregation_host.cc b/content/browser/private_aggregation/private_aggregation_host.cc
index be4c538..576952ca 100644
--- a/content/browser/private_aggregation/private_aggregation_host.cc
+++ b/content/browser/private_aggregation/private_aggregation_host.cc
@@ -550,8 +550,6 @@
   AggregationServicePayloadContents payload_contents(
       AggregationServicePayloadContents::Operation::kHistogram,
       std::move(contributions),
-      // TODO(alexmt): Consider allowing this to be set.
-      blink::mojom::AggregationServiceMode::kDefault,
       std::move(aggregation_coordinator_origin),
       /*max_contributions_allowed=*/max_contributions, filtering_id_max_bytes);
 
diff --git a/content/browser/private_aggregation/private_aggregation_host_unittest.cc b/content/browser/private_aggregation/private_aggregation_host_unittest.cc
index 0215ecf6..99d3bf0d 100644
--- a/content/browser/private_aggregation/private_aggregation_host_unittest.cc
+++ b/content/browser/private_aggregation/private_aggregation_host_unittest.cc
@@ -321,7 +321,6 @@
               {blink::mojom::AggregatableReportHistogramContribution(
                   /*bucket=*/123, /*value=*/456,
                   /*filtering_id=*/std::nullopt)},
-              blink::mojom::AggregationServiceMode::kDefault,
               /*aggregation_coordinator_origin=*/std::nullopt,
               /*max_contributions_allowed=*/20u,
               PrivateAggregationHost::kDefaultFilteringIdMaxBytes),
@@ -3080,7 +3079,6 @@
               {blink::mojom::AggregatableReportHistogramContribution(
                   /*bucket=*/123, /*value=*/456,
                   /*filtering_id=*/std::nullopt)},
-              blink::mojom::AggregationServiceMode::kDefault,
               /*aggregation_coordinator_origin=*/std::nullopt,
               /*max_contributions_allowed=*/20u,
               PrivateAggregationHost::kDefaultFilteringIdMaxBytes),
@@ -3270,7 +3268,6 @@
                       /*bucket=*/6, /*value=*/7,
                       /*filtering_id=*/8),
               },
-              blink::mojom::AggregationServiceMode::kDefault,
               /*aggregation_coordinator_origin=*/std::nullopt,
               /*max_contributions_allowed=*/20u,
               PrivateAggregationHost::kDefaultFilteringIdMaxBytes),
diff --git a/content/browser/private_aggregation/private_aggregation_internals_browsertest.cc b/content/browser/private_aggregation/private_aggregation_internals_browsertest.cc
index 24a49a2..cac83f6e 100644
--- a/content/browser/private_aggregation/private_aggregation_internals_browsertest.cc
+++ b/content/browser/private_aggregation/private_aggregation_internals_browsertest.cc
@@ -156,8 +156,8 @@
   AggregatableReportRequest request_1 =
       aggregation_service::CreateExampleRequest();
   std::optional<AggregatableReport> report_1 =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request_1, {hpke_key.GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          request_1, hpke_key.GetPublicKey());
 
   aggregation_service().NotifyReportHandled(
       std::move(request_1), AggregationServiceStorage::RequestId(1),
@@ -175,8 +175,8 @@
   AggregatableReportRequest request_3 =
       aggregation_service::CreateExampleRequest();
   std::optional<AggregatableReport> report_3 =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request_3, {hpke_key.GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          request_3, hpke_key.GetPublicKey());
 
   aggregation_service().NotifyReportHandled(
       std::move(request_3), AggregationServiceStorage::RequestId(3),
@@ -351,8 +351,8 @@
   AggregatableReportRequest request =
       aggregation_service::CreateExampleRequest();
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request, {hpke_key.GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          request, hpke_key.GetPublicKey());
 
   aggregation_service().NotifyReportHandled(
       std::move(request), AggregationServiceStorage::RequestId(10),
diff --git a/content/browser/private_aggregation/private_aggregation_internals_handler_impl_unittest.cc b/content/browser/private_aggregation/private_aggregation_internals_handler_impl_unittest.cc
index edd1419..17b06d8 100644
--- a/content/browser/private_aggregation/private_aggregation_internals_handler_impl_unittest.cc
+++ b/content/browser/private_aggregation/private_aggregation_internals_handler_impl_unittest.cc
@@ -241,8 +241,8 @@
 
   aggregation_service::TestHpkeKey hpke_key{/*key_id=*/"id123"};
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request, {hpke_key.GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          request, hpke_key.GetPublicKey());
 
   base::Time now = base::Time::Now();
 
@@ -268,8 +268,8 @@
 
   aggregation_service::TestHpkeKey hpke_key{/*key_id=*/"id123"};
   std::optional<AggregatableReport> report =
-      AggregatableReport::Provider().CreateFromRequestAndPublicKeys(
-          request, {hpke_key.GetPublicKey()});
+      AggregatableReport::Provider().CreateFromRequestAndPublicKey(
+          request, hpke_key.GetPublicKey());
 
   base::Time now = base::Time::Now();
 
diff --git a/content/browser/renderer_host/navigation_policy_container_builder.cc b/content/browser/renderer_host/navigation_policy_container_builder.cc
index 10fc9c53..a7212c5 100644
--- a/content/browser/renderer_host/navigation_policy_container_builder.cc
+++ b/content/browser/renderer_host/navigation_policy_container_builder.cc
@@ -154,6 +154,20 @@
   delivered_policies_.document_isolation_policy = dip;
 }
 
+void NavigationPolicyContainerBuilder::SetIntegrityPolicy(
+    network::IntegrityPolicy ip) {
+  DCHECK(!HasComputedPolicies());
+
+  delivered_policies_.integrity_policy = std::move(ip);
+}
+
+void NavigationPolicyContainerBuilder::SetIntegrityPolicyReportOnly(
+    network::IntegrityPolicy ip) {
+  DCHECK(!HasComputedPolicies());
+
+  delivered_policies_.integrity_policy_report_only = std::move(ip);
+}
+
 const PolicyContainerPolicies&
 NavigationPolicyContainerBuilder::DeliveredPoliciesForTesting() const {
   DCHECK(!HasComputedPolicies());
diff --git a/content/browser/renderer_host/navigation_policy_container_builder.h b/content/browser/renderer_host/navigation_policy_container_builder.h
index 3d0976a..3da4e8b 100644
--- a/content/browser/renderer_host/navigation_policy_container_builder.h
+++ b/content/browser/renderer_host/navigation_policy_container_builder.h
@@ -105,6 +105,9 @@
   // This must be called before `ComputePolicies()`.
   void SetDocumentIsolationPolicy(const network::DocumentIsolationPolicy& dip);
 
+  void SetIntegrityPolicy(network::IntegrityPolicy ip);
+  void SetIntegrityPolicyReportOnly(network::IntegrityPolicy ip);
+
   // Sets the IP address space of the delivered policies of the new document.
   //
   // This must be called before `ComputePolicies()`.
diff --git a/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc b/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc
index f2442b3..d2872ff 100644
--- a/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc
+++ b/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc
@@ -49,8 +49,8 @@
       network::mojom::IPAddressSpace::kPublic,
       /*is_web_secure_context=*/true, std::move(csp_list),
       network::CrossOriginOpenerPolicy(), network::CrossOriginEmbedderPolicy(),
-      network::DocumentIsolationPolicy(),
-      network::mojom::WebSandboxFlags::kNone,
+      network::DocumentIsolationPolicy(), network::IntegrityPolicy(),
+      network::IntegrityPolicy(), network::mojom::WebSandboxFlags::kNone,
       /*is_credentialless=*/false,
       /*can_navigate_top_without_user_gesture=*/true,
       /*cross_origin_isolation_enabled_by_dip=*/false);
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 555236d7..d5273fc 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -162,6 +162,7 @@
 #include "services/network/public/cpp/cross_origin_resource_policy.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/header_util.h"
+#include "services/network/public/cpp/integrity_policy.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/permissions_policy/fenced_frame_permissions_policies.h"
 #include "services/network/public/cpp/permissions_policy/permissions_policy_declaration.h"
@@ -9524,6 +9525,28 @@
   return network::CrossOriginEmbedderPolicy();
 }
 
+NavigationRequest::IntegrityPolicies
+NavigationRequest::ComputeIntegrityPolicies() {
+  IntegrityPolicies policies;
+  if (!base::FeatureList::IsEnabled(
+          network::features::kIntegrityPolicyScript)) {
+    return policies;
+  }
+  const GURL& url = common_params_->url;
+  const GURL& top_level_creation_url = GetParentFrameOrOuterDocument()
+                                           ? GetParentFrameOrOuterDocument()
+                                                 ->GetOutermostMainFrame()
+                                                 ->GetLastCommittedURL()
+                                           : url;
+  if (network::IsUrlPotentiallyTrustworthy(top_level_creation_url) &&
+      response_head_ && response_head_->parsed_headers) {
+    policies.enforced = response_head_->parsed_headers->integrity_policy;
+    policies.report_only =
+        response_head_->parsed_headers->integrity_policy_report_only;
+  }
+  return policies;
+}
+
 // [spec]:
 // https://html.spec.whatwg.org/C/#check-a-navigation-response's-adherence-to-its-embedder-policy
 //
@@ -10056,6 +10079,12 @@
   policy_container_builder_->SetCrossOriginEmbedderPolicy(
       ComputeCrossOriginEmbedderPolicy());
 
+  IntegrityPolicies integrity_policies = ComputeIntegrityPolicies();
+  policy_container_builder_->SetIntegrityPolicy(
+      std::move(integrity_policies.enforced));
+  policy_container_builder_->SetIntegrityPolicyReportOnly(
+      std::move(integrity_policies.report_only));
+
   // If the navigation is the result of a network response, set DIP to the
   // one in the network response. Otherwise, DIP should follow normal rules of
   // policy inheritance, which should be handled by the policy container.
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index b215ec3..0f9dc9f 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -82,6 +82,7 @@
 #endif
 
 namespace network {
+struct IntegrityPolicy;
 struct URLLoaderCompletionStatus;
 }  // namespace network
 
@@ -2110,6 +2111,15 @@
   // or retrieved from response headers.
   network::CrossOriginEmbedderPolicy ComputeCrossOriginEmbedderPolicy();
 
+  struct IntegrityPolicies {
+    network::IntegrityPolicy enforced;
+    network::IntegrityPolicy report_only;
+  };
+
+  // Calculates the integrity policies for a document, based on the
+  // `Integrity-Policy` and `Integrity-Policy-Report-Only` headers.
+  IntegrityPolicies ComputeIntegrityPolicies();
+
   // [spec]:
   // https://html.spec.whatwg.org/C/#check-a-navigation-response's-adherence-to-its-embedder-policy
   //
diff --git a/content/browser/renderer_host/policy_container_host.cc b/content/browser/renderer_host/policy_container_host.cc
index 5b05cc9d..e044d0d0 100644
--- a/content/browser/renderer_host/policy_container_host.cc
+++ b/content/browser/renderer_host/policy_container_host.cc
@@ -16,6 +16,22 @@
 #include "services/network/public/cpp/document_isolation_policy.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
+#include "services/network/public/mojom/integrity_policy.mojom.h"
+
+namespace {
+template <typename T>
+std::string ConvertToString(const std::vector<T>& array) {
+  std::ostringstream oss;
+  size_t array_size = array.size();
+  for (size_t i = 0; i < array_size; ++i) {
+    oss << array[i];
+    if (i == array_size - 1) {
+      oss << ", ";
+    }
+  }
+  return oss.str();
+}
+}  // namespace
 
 namespace content {
 
@@ -29,6 +45,8 @@
          lhs.cross_origin_opener_policy == rhs.cross_origin_opener_policy &&
          lhs.cross_origin_embedder_policy == rhs.cross_origin_embedder_policy &&
          lhs.document_isolation_policy == rhs.document_isolation_policy &&
+         lhs.integrity_policy == rhs.integrity_policy &&
+         lhs.integrity_policy_report_only == rhs.integrity_policy_report_only &&
          lhs.sandbox_flags == rhs.sandbox_flags &&
          lhs.is_credentialless == rhs.is_credentialless &&
          lhs.can_navigate_top_without_user_gesture ==
@@ -96,6 +114,16 @@
              .value_or("<null>")
       << " }";
 
+  out << ", integrity_policy: " << "{ blocked-destinations: "
+      << ConvertToString<::network::mojom::IntegrityPolicy_Destination>(
+             policies.integrity_policy.blocked_destinations)
+      << ", sources: "
+      << ConvertToString<::network::mojom::IntegrityPolicy_Source>(
+             policies.integrity_policy.sources)
+      << ", endpoints: "
+      << ConvertToString<std::string>(policies.integrity_policy.endpoints)
+      << " }";
+
   out << ", sandbox_flags: " << policies.sandbox_flags;
   out << ", is_credentialless: " << policies.is_credentialless;
   out << ", can_navigate_top_without_user_gesture: "
@@ -117,6 +145,8 @@
     const network::CrossOriginOpenerPolicy& cross_origin_opener_policy,
     const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy,
     const network::DocumentIsolationPolicy& document_isolation_policy,
+    network::IntegrityPolicy integrity_policy,
+    network::IntegrityPolicy integrity_policy_report_only,
     network::mojom::WebSandboxFlags sandbox_flags,
     bool is_credentialless,
     bool can_navigate_top_without_user_gesture,
@@ -128,6 +158,8 @@
       cross_origin_opener_policy(cross_origin_opener_policy),
       cross_origin_embedder_policy(cross_origin_embedder_policy),
       document_isolation_policy(document_isolation_policy),
+      integrity_policy(std::move(integrity_policy)),
+      integrity_policy_report_only(std::move(integrity_policy_report_only)),
       sandbox_flags(sandbox_flags),
       is_credentialless(is_credentialless),
       can_navigate_top_without_user_gesture(
@@ -145,6 +177,8 @@
                               network::CrossOriginOpenerPolicy(),
                               policies.cross_origin_embedder_policy,
                               network::DocumentIsolationPolicy(),
+                              std::move(policies.integrity_policy),
+                              std::move(policies.integrity_policy_report_only),
                               policies.sandbox_flags,
                               policies.is_credentialless,
                               policies.can_navigate_top_without_user_gesture,
@@ -162,6 +196,8 @@
           response_head->parsed_headers->cross_origin_opener_policy,
           response_head->parsed_headers->cross_origin_embedder_policy,
           response_head->parsed_headers->document_isolation_policy,
+          response_head->parsed_headers->integrity_policy,
+          response_head->parsed_headers->integrity_policy_report_only,
           network::mojom::WebSandboxFlags::kNone,
           /*is_credentialless=*/false,
           /*can_navigate_top_without_user_gesture=*/true,
@@ -185,7 +221,8 @@
       referrer_policy, ip_address_space, is_web_secure_context,
       mojo::Clone(content_security_policies), cross_origin_opener_policy,
       cross_origin_embedder_policy, mojo::Clone(document_isolation_policy),
-      sandbox_flags, is_credentialless, can_navigate_top_without_user_gesture,
+      integrity_policy, integrity_policy_report_only, sandbox_flags,
+      is_credentialless, can_navigate_top_without_user_gesture,
       cross_origin_isolation_enabled_by_dip);
 }
 
@@ -204,7 +241,8 @@
 blink::mojom::PolicyContainerPoliciesPtr
 PolicyContainerPolicies::ToMojoPolicyContainerPolicies() const {
   return blink::mojom::PolicyContainerPolicies::New(
-      cross_origin_embedder_policy, referrer_policy,
+      cross_origin_embedder_policy, integrity_policy,
+      integrity_policy_report_only, referrer_policy,
       mojo::Clone(content_security_policies), is_credentialless, sandbox_flags,
       ip_address_space, can_navigate_top_without_user_gesture,
       cross_origin_isolation_enabled_by_dip);
diff --git a/content/browser/renderer_host/policy_container_host.h b/content/browser/renderer_host/policy_container_host.h
index 90be772..9ab9c211 100644
--- a/content/browser/renderer_host/policy_container_host.h
+++ b/content/browser/renderer_host/policy_container_host.h
@@ -17,6 +17,7 @@
 #include "services/network/public/cpp/cross_origin_embedder_policy.h"
 #include "services/network/public/cpp/cross_origin_opener_policy.h"
 #include "services/network/public/cpp/document_isolation_policy.h"
+#include "services/network/public/cpp/integrity_policy.h"
 #include "services/network/public/cpp/web_sandbox_flags.h"
 #include "services/network/public/mojom/content_security_policy.mojom-forward.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
@@ -43,6 +44,8 @@
       const network::CrossOriginOpenerPolicy& cross_origin_opener_policy,
       const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy,
       const network::DocumentIsolationPolicy& document_isolation_policy,
+      network::IntegrityPolicy integrity_policy,
+      network::IntegrityPolicy integrity_policy_report_only,
       network::mojom::WebSandboxFlags sandbox_flags,
       bool is_credentialless,
       bool can_navigate_top_without_user_gesture,
@@ -120,6 +123,9 @@
   // https://github.com/explainers-by-googlers/document-isolation-policy
   network::DocumentIsolationPolicy document_isolation_policy;
 
+  network::IntegrityPolicy integrity_policy;
+  network::IntegrityPolicy integrity_policy_report_only;
+
   // Tracks the sandbox flags which are in effect on this document. This
   // includes any flags which have been set by a Content-Security-Policy header,
   // in addition to those which are set by the embedding frame.
@@ -220,6 +226,13 @@
     return policies_.document_isolation_policy;
   }
 
+  const network::IntegrityPolicy& integrity_policy() const {
+    return policies_.integrity_policy;
+  }
+  const network::IntegrityPolicy& integrity_policy_report_only() const {
+    return policies_.integrity_policy_report_only;
+  }
+
   network::mojom::WebSandboxFlags sandbox_flags() const {
     return policies_.sandbox_flags;
   }
diff --git a/content/browser/renderer_host/policy_container_host_unittest.cc b/content/browser/renderer_host/policy_container_host_unittest.cc
index c9ac380..1e0b5c74 100644
--- a/content/browser/renderer_host/policy_container_host_unittest.cc
+++ b/content/browser/renderer_host/policy_container_host_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/run_loop.h"
 #include "content/public/test/browser_task_environment.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
+#include "services/network/public/mojom/integrity_policy.mojom.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
 #include "services/network/public/mojom/web_sandbox_flags.mojom.h"
@@ -30,6 +31,8 @@
   network::CrossOriginOpenerPolicy cross_origin_opener_policy;
   network::CrossOriginEmbedderPolicy cross_origin_embedder_policy;
   network::DocumentIsolationPolicy document_isolation_policy;
+  network::IntegrityPolicy integrity_policy;
+  network::IntegrityPolicy integrity_policy_report_only;
   network::mojom::WebSandboxFlags sandbox_flags;
   bool is_credentialless;
   bool can_navigate_top_without_user_gesture;
@@ -82,11 +85,17 @@
   dip.reporting_endpoint = "endpoint 1";
   dip.report_only_reporting_endpoint = "endpoint 2";
 
+  network::IntegrityPolicy ip;
+  ip.sources.push_back(network::mojom::IntegrityPolicy::Source::kInline);
+  ip.blocked_destinations.push_back(
+      network::mojom::IntegrityPolicy::Destination::kScript);
+  ip.endpoints.push_back("integrity endpoint");
+
   PolicyContainerPolicies policies(
       network::mojom::ReferrerPolicy::kAlways,
       network::mojom::IPAddressSpace::kUnknown,
       /*is_web_secure_context=*/true, std::move(csps), coop, coep,
-      std::move(dip), sandbox_flags,
+      std::move(dip), ip, network::IntegrityPolicy(), sandbox_flags,
       /*is_credentialless=*/true,
       /*can_navigate_top_without_user_gesture=*/true,
       /*cross_origin_isolation_enabled_by_dip=*/false);
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index d1ed337f..07cea50 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4032,6 +4032,8 @@
             parent_policies.cross_origin_opener_policy,
             parent_policies.cross_origin_embedder_policy,
             parent_policies.document_isolation_policy,
+            parent_policies.integrity_policy,
+            parent_policies.integrity_policy_report_only,
             network::mojom::WebSandboxFlags::kNone,
             /*is_credentialless=*/false,
             /*can_navigate_top_without_user_gesture=*/true,
diff --git a/content/browser/resources/traces_internals/BUILD.gn b/content/browser/resources/traces_internals/BUILD.gn
index 2703af4e..ab401788 100644
--- a/content/browser/resources/traces_internals/BUILD.gn
+++ b/content/browser/resources/traces_internals/BUILD.gn
@@ -4,6 +4,39 @@
 
 import("//third_party/protobuf/proto_library.gni")
 import("//ui/webui/resources/tools/build_webui.gni")
+import("//ui/webui/resources/tools/bundle_js.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+import("//ui/webui/resources/tools/minify_js.gni")
+
+bundle_js("bufbuild_bundle") {
+  visibility = [ ":bufbuild_min_js" ]
+  host = "_ignored_"
+  input =
+      rebase_path("//third_party/node/node_modules/@bufbuild/protobuf/dist/esm",
+                  root_build_dir)
+  js_module_in_files = [ "wire/index.js" ]
+  out_folder = "$target_gen_dir/bufbuild/bundled"
+}
+
+minify_js("bufbuild_min_js") {
+  visibility = [ ":bufbuild_grdp" ]
+  deps = [ ":bufbuild_bundle" ]
+  in_folder = "$target_gen_dir/bufbuild/bundled"
+  in_files = [ "wire/index.rollup.js" ]
+  out_folder = "$target_gen_dir/bufbuild/minified"
+}
+
+generate_grd("bufbuild_grdp") {
+  deps = [ ":bufbuild_min_js" ]
+  grd_prefix = "bufbuild"
+  out_grd = "$root_gen_dir/bufbuild.grdp"
+  input_files = [ "wire/index.rollup.js" ]
+
+  input_files_base_dir =
+      rebase_path("$target_gen_dir/bufbuild/minified", root_build_dir)
+  resource_path_rewrites =
+      [ "wire/index.rollup.js|@bufbuild/protobuf/wire/index.js" ]
+}
 
 proto_library("config_proto") {
   generator_visibility = [ ":copy_mojo" ]
@@ -64,7 +97,7 @@
     "$proto_ts_root/third_party/perfetto/protos/perfetto/config/perfetto_config.ts",
   ]
 
-  extra_grdp_deps = [ "//third_party/protobuf:bufbuild_grdp" ]
+  extra_grdp_deps = [ ":bufbuild_grdp" ]
   extra_grdp_files = [ "$root_gen_dir/bufbuild.grdp" ]
 
   ts_path_mappings = [ "/@bufbuild/protobuf/wire/index.js|" + rebase_path(
diff --git a/content/browser/sandbox_mac_unittest.mm b/content/browser/sandbox_mac_unittest.mm
index fff31d2..9979cfcc 100644
--- a/content/browser/sandbox_mac_unittest.mm
+++ b/content/browser/sandbox_mac_unittest.mm
@@ -218,7 +218,7 @@
 MULTIPROCESS_TEST_MAIN(NetworkProcessPrefs) {
   CheckCreateSeatbeltServer();
 
-  const std::string kBundleId = base::apple::BaseBundleID();
+  const std::string kBundleId(base::apple::BaseBundleID());
   const std::string kUserName = base::SysNSStringToUTF8(NSUserName());
   const std::vector<std::string> kPaths = {
       "/Library/Managed Preferences/.GlobalPreferences.plist",
diff --git a/content/browser/sandbox_parameters_mac.mm b/content/browser/sandbox_parameters_mac.mm
index 403b6ce..f732687f 100644
--- a/content/browser/sandbox_parameters_mac.mm
+++ b/content/browser/sandbox_parameters_mac.mm
@@ -108,7 +108,7 @@
   CHECK(
       serializer->SetParameter(sandbox::policy::kParamBundlePath, bundle_path));
 
-  std::string bundle_id = base::apple::BaseBundleID();
+  std::string bundle_id(base::apple::BaseBundleID());
   DCHECK(!bundle_id.empty()) << "base::apple::OuterBundle is unset";
   CHECK(serializer->SetParameter(sandbox::policy::kParamBundleId, bundle_id));
 
diff --git a/content/browser/shared_storage/shared_storage_runtime_manager.cc b/content/browser/shared_storage/shared_storage_runtime_manager.cc
index 48c4702..a55dd7c 100644
--- a/content/browser/shared_storage/shared_storage_runtime_manager.cc
+++ b/content/browser/shared_storage/shared_storage_runtime_manager.cc
@@ -17,13 +17,14 @@
     const SharedStorageRuntimeManager::SharedStorageObserverInterface& observer,
     GlobalRenderFrameHostId main_frame_id) {
   // We should send a report if and only if (1) the observer is subscribed to
-  // receiving all reports, or (2) the observer has a valid associated main
-  // frame ID (i.e. is an observer attached to a main render frame host), and
-  // that main frame ID matches the main frame ID passed as a parameter of the
-  // report.
+  // receiving all reports, or (2) the observer has a valid associated render
+  // frame host ID (i.e. the observer is attached to a render frame host), and
+  // that global render frame host ID matches the main frame ID passed as a
+  // parameter of the report (and hence the observer is attached to the relevant
+  // main render frame host).
   return observer.ShouldReceiveAllReports() ||
-         (observer.AssociatedMainFrameId() &&
-          observer.AssociatedMainFrameId() == main_frame_id);
+         (observer.AssociatedFrameHostId() &&
+          observer.AssociatedFrameHostId() == main_frame_id);
 }
 
 }  // namespace
diff --git a/content/browser/shared_storage/shared_storage_runtime_manager.h b/content/browser/shared_storage/shared_storage_runtime_manager.h
index 9d79fed..e01171f4 100644
--- a/content/browser/shared_storage/shared_storage_runtime_manager.h
+++ b/content/browser/shared_storage/shared_storage_runtime_manager.h
@@ -60,7 +60,7 @@
       kRemainingBudget,
     };
 
-    virtual GlobalRenderFrameHostId AssociatedMainFrameId() const = 0;
+    virtual GlobalRenderFrameHostId AssociatedFrameHostId() const = 0;
 
     virtual bool ShouldReceiveAllReports() const = 0;
 
diff --git a/content/browser/shared_storage/test_shared_storage_observer.cc b/content/browser/shared_storage/test_shared_storage_observer.cc
index 3d4c4c1..8477b22 100644
--- a/content/browser/shared_storage/test_shared_storage_observer.cc
+++ b/content/browser/shared_storage/test_shared_storage_observer.cc
@@ -94,7 +94,7 @@
 TestSharedStorageObserver::TestSharedStorageObserver() = default;
 TestSharedStorageObserver::~TestSharedStorageObserver() = default;
 
-GlobalRenderFrameHostId TestSharedStorageObserver::AssociatedMainFrameId()
+GlobalRenderFrameHostId TestSharedStorageObserver::AssociatedFrameHostId()
     const {
   return GlobalRenderFrameHostId();
 }
diff --git a/content/browser/shared_storage/test_shared_storage_observer.h b/content/browser/shared_storage/test_shared_storage_observer.h
index 1343e5e..931a44c 100644
--- a/content/browser/shared_storage/test_shared_storage_observer.h
+++ b/content/browser/shared_storage/test_shared_storage_observer.h
@@ -46,7 +46,7 @@
   TestSharedStorageObserver();
   ~TestSharedStorageObserver() override;
 
-  GlobalRenderFrameHostId AssociatedMainFrameId() const override;
+  GlobalRenderFrameHostId AssociatedFrameHostId() const override;
 
   bool ShouldReceiveAllReports() const override;
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 2b63e244..b64480c 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -2199,57 +2199,92 @@
   const URLLoaderNetworkContext& context =
       url_loader_network_observers_.current_context();
 
+  // Three different cases are handled here depending on the request context:
+  //   1. Document context (ContextType::kRenderFrameHostContext) covers fetch()
+  //      and subresource requests. These should check for existing permission
+  //      state, and if the state is ASK trigger the permission prompt. These
+  //      should also handle being delegated into subframe documents.
+  //   2. Navigation context (ContextType::kNavigationRequestContext) covers
+  //      subframe navigations. These should check for existing permission
+  //      state, and if the state is ASK trigger the permission prompt. Nested
+  //      subframes should be allowed iff permission policy delegated the
+  //      permission into the embedding frame.
+  //   3. Worker context (ContextType::kServiceWorkerContext) covers requests
+  //      from workers. These may not have an existing document around. These
+  //      should check for the permission state, but NOT trigger the permission
+  //      prompt.
+
   // Currently requesting the Local Network Access permission is restricted to
-  // document contexts (subresource requests).
-  // TODO(crbug.com/404887282): Add support for allowing requests from workers
-  // if the user has previously granted the permission.
-  // TODO(crbug.com/404887285): Add support for having subframe navigation
-  // requests query and trigger the permission prompt.
-  if (context.type() != ContextType::kRenderFrameHostContext ||
-      !context.navigation_or_document()) {
-    std::move(callback).Run(false);
-    return;
-  }
-  RenderFrameHost* rfh = context.navigation_or_document()->GetDocument();
-  if (!rfh) {
-    std::move(callback).Run(false);
-    return;
-  }
+  // subresource requests and subframe navigation requests.
+  // TODO(crbug.com/404887285): Denying permission for a subframe navigation
+  // results in an error page with text that isn't quite true anymore: "The
+  // connection is blocked because it was initiated by a public page to connect
+  // to devices or servers on your private network. Reload this page to allow
+  // the connection." The last sentence should be removed.
 
-  PermissionController* permission_controller =
-      browser_context_->GetPermissionController();
-  DCHECK(permission_controller);
+  // Handle document (Case 1) and navigation (Case 2) contexts.
+  if (context.navigation_or_document()) {
+    RenderFrameHost* rfh = nullptr;
+    if (context.navigation_or_document()->GetDocument()) {
+      // Get the document that is making the request.
+      rfh = context.navigation_or_document()->GetDocument();
+    } else if (context.navigation_or_document()->GetNavigationRequest()) {
+      // Get the document that is embedding the frame being navigated.
+      rfh = context.navigation_or_document()
+                ->GetNavigationRequest()
+                ->GetParentFrameOrOuterDocument();
+    }
+    if (!rfh) {
+      std::move(callback).Run(false);
+      return;
+    }
 
-  auto status = permission_controller->GetPermissionStatusForCurrentDocument(
-      content::PermissionDescriptorUtil::
-          CreatePermissionDescriptorForPermissionType(
-              blink::PermissionType::LOCAL_NETWORK_ACCESS),
-      rfh);
-  if (status == blink::mojom::PermissionStatus::GRANTED) {
+    PermissionController* permission_controller =
+        browser_context_->GetPermissionController();
+    DCHECK(permission_controller);
+    auto status = permission_controller->GetPermissionStatusForCurrentDocument(
+        content::PermissionDescriptorUtil::
+            CreatePermissionDescriptorForPermissionType(
+                blink::PermissionType::LOCAL_NETWORK_ACCESS),
+        rfh);
+    if (status == blink::mojom::PermissionStatus::GRANTED) {
+      std::move(callback).Run(true);
+      return;
+    } else if (status == blink::mojom::PermissionStatus::DENIED) {
+      std::move(callback).Run(false);
+      return;
+    } else {
+      // PermissionStatus is ASK, so request the permission. Converts the result
+      // into a boolean to pass back to `callback`, capturing whether the
+      // permission is granted or not.
+      permission_controller->RequestPermissionFromCurrentDocument(
+          rfh,
+          PermissionRequestDescription(
+              content::PermissionDescriptorUtil::
+                  CreatePermissionDescriptorForPermissionType(
+                      blink::PermissionType::LOCAL_NETWORK_ACCESS)),
+          base::BindOnce(
+              [](OnLocalNetworkAccessPermissionRequiredCallback cb,
+                 PermissionStatus status) {
+                std::move(cb).Run(status ==
+                                  blink::mojom::PermissionStatus::GRANTED);
+              },
+              std::move(callback)));
+      return;
+    }
+  } else if (context.type() == ContextType::kServiceWorkerContext) {
+    // TODO(crbug.com/404887282): Add support for gating requests from workers
+    // on whether the user previously granted the permission. This will require
+    // plumbing through the `window_id` for the fetch to identify the worker
+    // context and then using that to get the worker origin to use when calling
+    // PermissionController::GetPermissionStatusForWorker().
     std::move(callback).Run(true);
     return;
-  } else if (status == blink::mojom::PermissionStatus::DENIED) {
-    std::move(callback).Run(false);
-    return;
-  } else {
-    // PermissionStatus is ASK, so request the permission. Converts the result
-    // into a boolean to pass back to `callback`, capturing whether the
-    // permission is granted or not.
-    permission_controller->RequestPermissionFromCurrentDocument(
-        rfh,
-        PermissionRequestDescription(
-            content::PermissionDescriptorUtil::
-                CreatePermissionDescriptorForPermissionType(
-                    blink::PermissionType::LOCAL_NETWORK_ACCESS)),
-        base::BindOnce(
-            [](OnLocalNetworkAccessPermissionRequiredCallback cb,
-               PermissionStatus status) {
-              std::move(cb).Run(status ==
-                                blink::mojom::PermissionStatus::GRANTED);
-            },
-            std::move(callback)));
-    return;
   }
+
+  // Otherwise default to denying local network access.
+  std::move(callback).Run(false);
+  return;
 }
 
 void StoragePartitionImpl::OnCertificateRequested(
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index f3445ac..a4975330 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -67,6 +67,7 @@
 #include "content/browser/interest_group/interest_group_permissions_checker.h"
 #include "content/browser/private_aggregation/private_aggregation_manager.h"
 #include "content/browser/private_aggregation/private_aggregation_test_utils.h"
+#include "content/browser/renderer_host/navigation_request.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/browsing_data_filter_builder.h"
@@ -77,7 +78,10 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_task_environment.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
 #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
 #include "net/base/network_isolation_key.h"
@@ -2594,10 +2598,65 @@
   EXPECT_FALSE(grant_permission.Get());
 }
 
-TEST_F(StoragePartitionImplTest, LocalNetworkAccessPermission) {
+// Local network access tests require there to be a (minimal) frame setup.
+using StoragePartitionImplLocalNetworkAccessTest = RenderViewHostTestHarness;
+
+// Tests triggering the Local Network Access permission check for a subresource
+// request.
+TEST_F(StoragePartitionImplLocalNetworkAccessTest,
+       LocalNetworkAccessPermission_SubresourceContext) {
   base::test::ScopedFeatureList features(
       network::features::kLocalNetworkAccessChecks);
+  StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
+      browser_context()->GetDefaultStoragePartition());
 
+  mojo::Remote<network::mojom::URLLoaderNetworkServiceObserver> observer(
+      partition->CreateURLLoaderNetworkObserverForFrame(
+          process()->GetDeprecatedID(), main_rfh()->GetRoutingID()));
+
+  base::test::TestFuture<bool> grant_permission;
+  observer->OnLocalNetworkAccessPermissionRequired(
+      base::BindOnce(grant_permission.GetCallback()));
+  EXPECT_FALSE(grant_permission.Get());
+}
+
+// Tests triggering the Local Network Access permission check for a subframe
+// navigation context.
+TEST_F(StoragePartitionImplLocalNetworkAccessTest,
+       LocalNetworkAccessPermission_SubframeNavigationContext) {
+  base::test::ScopedFeatureList features(
+      network::features::kLocalNetworkAccessChecks);
+  StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
+      browser_context()->GetDefaultStoragePartition());
+
+  // Set up a frame tree with a subframe, start a navigation in the subframe,
+  // and get the NavigationRequest for that navigation.
+  NavigateAndCommit(GURL("https://foo.com"));
+  content::RenderFrameHost* sub_frame =
+      content::RenderFrameHostTester::For(main_rfh())
+          ->AppendChild(std::string("child"));
+  std::unique_ptr<content::NavigationSimulator> simulator =
+      content::NavigationSimulator::CreateRendererInitiated(
+          GURL("http://test.local"), sub_frame);
+  simulator->Start();
+  NavigationRequest* request =
+      NavigationRequest::From(simulator->GetNavigationHandle());
+
+  mojo::Remote<network::mojom::URLLoaderNetworkServiceObserver> observer(
+      partition->CreateURLLoaderNetworkObserverForNavigationRequest(*request));
+
+  base::test::TestFuture<bool> grant_permission;
+  observer->OnLocalNetworkAccessPermissionRequired(
+      base::BindOnce(grant_permission.GetCallback()));
+  EXPECT_FALSE(grant_permission.Get());
+}
+
+// Tests triggering the Local Network Access permission check for a worker
+// request.
+TEST_F(StoragePartitionImplLocalNetworkAccessTest,
+       LocalNetworkAccessPermission_WorkerContext) {
+  base::test::ScopedFeatureList features(
+      network::features::kLocalNetworkAccessChecks);
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       browser_context()->GetDefaultStoragePartition());
 
@@ -2608,7 +2667,9 @@
   base::test::TestFuture<bool> grant_permission;
   observer->OnLocalNetworkAccessPermissionRequired(
       base::BindOnce(grant_permission.GetCallback()));
-  EXPECT_FALSE(grant_permission.Get());
+  // TODO(crbug.com/404887282): Once support for checking permission in service
+  // workers is added, this should be changed to EXPECT_FALSE().
+  EXPECT_TRUE(grant_permission.Get());
 }
 
 TEST_F(StoragePartitionImplTest, ClearDataStorageKeyDeletesPartitionedCookies) {
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 70575de..b3b0709 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -964,6 +964,14 @@
   web_contents_->SetSupportsForwardTransitionAnimation(supports);
 }
 
+jint WebContentsAndroid::GetOriginalWindowOpenDisposition(JNIEnv* env) {
+  return static_cast<jint>(web_contents_->GetOriginalWindowOpenDisposition());
+}
+
+jboolean WebContentsAndroid::HasOpener(JNIEnv* env) {
+  return static_cast<jboolean>(web_contents_->HasOpener());
+}
+
 void WebContentsAndroid::UpdateOffsetTagDefinitions(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jtag_definitions) {
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index 0cc233a..020899f 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -253,6 +253,10 @@
 
   void SetSupportsForwardTransitionAnimation(JNIEnv* env, jboolean enabled);
 
+  jboolean HasOpener(JNIEnv* env);
+
+  jint GetOriginalWindowOpenDisposition(JNIEnv* env);
+
   // Adds a crash report, like DumpWithoutCrashing(), including the Java stack
   // trace from which `web_contents` was created. This is meant to help debug
   // cases where BrowserContext is destroyed before its WebContents.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index cb039c0..45b84cb 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -948,6 +948,11 @@
   return partitioned_popin_opener_properties_->top_frame_origin.GetURL();
 }
 
+WindowOpenDisposition WebContentsImpl::GetOriginalWindowOpenDisposition()
+    const {
+  return original_window_open_disposition_;
+}
+
 void WebContents::SetScreenOrientationDelegate(
     ScreenOrientationDelegate* delegate) {
   ScreenOrientationProvider::SetDelegate(delegate);
@@ -5019,10 +5024,11 @@
   }
 
   // TODO(crbug.com/40202416): Support a way for MPArch guests to support this.
-  if (delegate_ && delegate_->IsWebContentsCreationOverridden(
-                       source_site_instance, params.window_container_type,
-                       opener->GetLastCommittedURL(), params.frame_name,
-                       params.target_url)) {
+  if (delegate_ &&
+      delegate_->IsWebContentsCreationOverridden(
+          opener, source_site_instance, params.window_container_type,
+          opener->GetLastCommittedURL(), params.frame_name,
+          params.target_url)) {
     auto* web_contents_impl =
         static_cast<WebContentsImpl*>(delegate_->CreateCustomWebContents(
             opener, source_site_instance, is_new_browsing_instance,
@@ -5139,6 +5145,9 @@
   SetPartitionedPopinOpenerOnNewWindowIfNeeded(new_contents_impl, params,
                                                opener);
 
+  // Sets the newly created WebContents WindowOpenDisposition.
+  new_contents_impl->original_window_open_disposition_ = params.disposition;
+
   // If the new frame has a name, make sure any SiteInstances that can find
   // this named frame have proxies for it.  Must be called after
   // SetSessionStorageNamespace, since this calls CreateRenderView, which uses
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 54e9de12..eabf30ff 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -95,6 +95,7 @@
 #include "ui/base/ime/mojom/virtual_keyboard_types.mojom.h"
 #include "ui/base/mojom/window_show_state.mojom-forward.h"
 #include "ui/base/ui_base_types.h"
+#include "ui/base/window_open_disposition.h"
 #include "ui/color/color_provider_key.h"
 #include "ui/color/color_provider_source_observer.h"
 #include "ui/gfx/geometry/size.h"
@@ -651,6 +652,7 @@
   bool IsInPreviewMode() const override;
   void WillActivatePreviewPage() override;
   void ActivatePreviewPage() override;
+  WindowOpenDisposition GetOriginalWindowOpenDisposition() const override;
 
   // Implementation of PageNavigator.
   WebContents* OpenURL(const OpenURLParams& params,
@@ -2743,6 +2745,11 @@
   // Whether this contents represents a window initially opened as a new popup.
   bool is_popup_{false};
 
+  // The window open disposition that was originally requested
+  // when this WebContents was created.
+  WindowOpenDisposition original_window_open_disposition_ =
+      WindowOpenDisposition::UNKNOWN;
+
   // If this window was opened as a new partitioned popin this will contain the
   // properties needed to setup partitioning which aligns with the opener.
   // See https://explainers-by-googlers.github.io/partitioned-popins/
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc
index b11e699..25dce5d 100644
--- a/content/browser/webid/federated_auth_request_impl_unittest.cc
+++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -401,13 +401,16 @@
       }
     }
 
+    IdpNetworkRequestManager::ClientMetadata client_metadata;
+    client_metadata.privacy_policy_url =
+        GURL(info.client_metadata.privacy_policy_url);
+    client_metadata.terms_of_service_url =
+        GURL(info.client_metadata.terms_of_service_url);
+    client_metadata.brand_icon_url = GURL(info.client_metadata.brand_icon_url);
     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), info.client_metadata.fetch_status,
-                       IdpNetworkRequestManager::ClientMetadata{
-                           GURL(info.client_metadata.privacy_policy_url),
-                           GURL(info.client_metadata.terms_of_service_url),
-                           GURL(info.client_metadata.brand_icon_url)}));
+                       client_metadata));
   }
 
   void SendAccountsRequest(const url::Origin& idp_origin,
diff --git a/content/browser/webid/flags.cc b/content/browser/webid/flags.cc
index 2b42715c..c40b8e51 100644
--- a/content/browser/webid/flags.cc
+++ b/content/browser/webid/flags.cc
@@ -81,4 +81,9 @@
   return base::FeatureList::IsEnabled(features::kFedCmAutofill) ||
          IsFedCmDelegationEnabled();
 }
+
+bool IsFedCmIframeOriginEnabled() {
+  return base::FeatureList::IsEnabled(features::kFedCmIframeOrigin);
+}
+
 }  // namespace content
diff --git a/content/browser/webid/flags.h b/content/browser/webid/flags.h
index 9a70fbd..6a1cf6f3 100644
--- a/content/browser/webid/flags.h
+++ b/content/browser/webid/flags.h
@@ -56,6 +56,10 @@
 
 // Whether autofill enhancement with FedCM is enabled.
 bool IsFedCmAutofillEnabled();
+
+// Whether showing the iframe origin is enabled.
+bool IsFedCmIframeOriginEnabled();
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_WEBID_FLAGS_H_
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc
index 46c05e1..30d9cb6 100644
--- a/content/browser/webid/idp_network_request_manager.cc
+++ b/content/browser/webid/idp_network_request_manager.cc
@@ -105,6 +105,8 @@
 // Client metadata keys.
 constexpr char kPrivacyPolicyKey[] = "privacy_policy_url";
 constexpr char kTermsOfServiceKey[] = "terms_of_service_url";
+constexpr char kClientMatchesTopFrameOriginKey[] =
+    "client_matches_top_frame_origin";
 
 // Accounts endpoint response keys.
 constexpr char kAccountsKey[] = "accounts";
@@ -706,6 +708,7 @@
 }
 
 void OnClientMetadataParsed(
+    bool is_cross_site_iframe,
     int rp_brand_icon_ideal_size,
     int rp_brand_icon_minimum_size,
     IdpNetworkRequestManager::FetchClientMetadataCallback callback,
@@ -720,6 +723,10 @@
   const base::Value::Dict& response = result->GetDict();
   data.privacy_policy_url = ExtractUrl(response, kPrivacyPolicyKey);
   data.terms_of_service_url = ExtractUrl(response, kTermsOfServiceKey);
+  if (is_cross_site_iframe) {
+    data.client_matches_top_frame_origin =
+        response.FindBool(kClientMatchesTopFrameOriginKey);
+  }
 
   const base::Value::List* icons_value = response.FindList(kBrandingIconsKey);
   if (icons_value) {
@@ -1022,6 +1029,11 @@
 IdpNetworkRequestManager::WellKnown::WellKnown(const WellKnown& other) =
     default;
 
+IdpNetworkRequestManager::ClientMetadata::ClientMetadata() = default;
+IdpNetworkRequestManager::ClientMetadata::~ClientMetadata() = default;
+IdpNetworkRequestManager::ClientMetadata::ClientMetadata(
+    const ClientMetadata& other) = default;
+
 IdpNetworkRequestManager::TokenResult::TokenResult() = default;
 IdpNetworkRequestManager::TokenResult::~TokenResult() = default;
 IdpNetworkRequestManager::TokenResult::TokenResult(const TokenResult& other) =
@@ -1037,6 +1049,7 @@
   // when the user selects an account to sign in.
   return std::make_unique<IdpNetworkRequestManager>(
       host->GetLastCommittedOrigin(),
+      host->GetMainFrame()->GetLastCommittedOrigin(),
       host->GetStoragePartition()->GetURLLoaderFactoryForBrowserProcess(),
       host->GetBrowserContext()->GetFederatedIdentityPermissionContext(),
       host->BuildClientSecurityState());
@@ -1044,10 +1057,12 @@
 
 IdpNetworkRequestManager::IdpNetworkRequestManager(
     const url::Origin& relying_party_origin,
+    const url::Origin& rp_embedding_origin,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
     FederatedIdentityPermissionContextDelegate* permission_delegate,
     network::mojom::ClientSecurityStatePtr client_security_state)
     : relying_party_origin_(relying_party_origin),
+      rp_embedding_origin_(rp_embedding_origin),
       loader_factory_(loader_factory),
       permission_delegate_(permission_delegate),
       client_security_state_(std::move(client_security_state)) {
@@ -1289,6 +1304,12 @@
       maxResponseSizeInKiB * 1024);
 }
 
+bool IdpNetworkRequestManager::IsCrossSiteIframe() const {
+  return IsFedCmIframeOriginEnabled() && !rp_embedding_origin_.opaque() &&
+         !net::SchemefulSite::IsSameSite(relying_party_origin_,
+                                         rp_embedding_origin_);
+}
+
 void IdpNetworkRequestManager::DownloadAndDecodeImage(const GURL& url,
                                                       ImageCallback callback) {
   std::unique_ptr<network::ResourceRequest> resource_request =
@@ -1386,8 +1407,12 @@
     int rp_brand_icon_ideal_size,
     int rp_brand_icon_minimum_size,
     FetchClientMetadataCallback callback) {
-  GURL target_url = endpoint.Resolve(
-      "?client_id=" + base::EscapeQueryParamValue(client_id, true));
+  std::string parameters =
+      "?client_id=" + base::EscapeQueryParamValue(client_id, true);
+  if (IsCrossSiteIframe()) {
+    parameters += "&top_frame_origin=" + rp_embedding_origin_.Serialize();
+  }
+  GURL target_url = endpoint.Resolve(parameters);
 
   std::unique_ptr<network::ResourceRequest> resource_request =
       CreateUncredentialedResourceRequest(target_url,
@@ -1396,8 +1421,9 @@
   DownloadJsonAndParse(
       std::move(resource_request),
       /*url_encoded_post_data=*/std::nullopt,
-      base::BindOnce(&OnClientMetadataParsed, rp_brand_icon_ideal_size,
-                     rp_brand_icon_minimum_size, std::move(callback)),
+      base::BindOnce(&OnClientMetadataParsed, IsCrossSiteIframe(),
+                     rp_brand_icon_ideal_size, rp_brand_icon_minimum_size,
+                     std::move(callback)),
       maxResponseSizeInKiB * 1024);
 }
 
diff --git a/content/browser/webid/idp_network_request_manager.h b/content/browser/webid/idp_network_request_manager.h
index 791016c..43e50efae 100644
--- a/content/browser/webid/idp_network_request_manager.h
+++ b/content/browser/webid/idp_network_request_manager.h
@@ -131,10 +131,15 @@
     GURL login_url;
   };
 
-  struct ClientMetadata {
+  struct CONTENT_EXPORT ClientMetadata {
+    ClientMetadata();
+    ~ClientMetadata();
+    ClientMetadata(const ClientMetadata&);
+
     GURL privacy_policy_url;
     GURL terms_of_service_url;
     GURL brand_icon_url;
+    std::optional<bool> client_matches_top_frame_origin;
   };
 
   struct CONTENT_EXPORT TokenResult {
@@ -254,6 +259,7 @@
 
   IdpNetworkRequestManager(
       const url::Origin& relying_party,
+      const url::Origin& rp_embedding_origin,
       scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
       FederatedIdentityPermissionContextDelegate* permission_delegate,
       network::mojom::ClientSecurityStatePtr client_security_state);
@@ -332,6 +338,8 @@
   virtual void DownloadAndDecodeImage(const GURL& url, ImageCallback callback);
 
  private:
+  bool IsCrossSiteIframe() const;
+
   // Starts download request using `url_loader`. Calls `parse_json_callback`
   // when the download result has been parsed.
   void DownloadJsonAndParse(
@@ -378,6 +386,7 @@
       CredentialedResourceRequestType type) const;
 
   url::Origin relying_party_origin_;
+  url::Origin rp_embedding_origin_;
 
   scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
 
diff --git a/content/browser/webid/idp_network_request_manager_unittest.cc b/content/browser/webid/idp_network_request_manager_unittest.cc
index f000be64..bb6f894 100644
--- a/content/browser/webid/idp_network_request_manager_unittest.cc
+++ b/content/browser/webid/idp_network_request_manager_unittest.cc
@@ -124,11 +124,16 @@
 
 class IdpNetworkRequestManagerTest : public ::testing::Test {
  public:
-  std::unique_ptr<IdpNetworkRequestManager> CreateTestManager() {
+  std::unique_ptr<IdpNetworkRequestManager> CreateTestManager(
+      const char* top_level_origin = nullptr) {
     test_permission_delegate_ =
         std::make_unique<NiceMock<MockPermissionDelegate>>();
+    url::Origin top_level_origin_obj;
+    if (top_level_origin) {
+      top_level_origin_obj = url::Origin::Create(GURL(top_level_origin));
+    }
     return std::make_unique<IdpNetworkRequestManager>(
-        url::Origin::Create(GURL(kTestRpUrl)),
+        url::Origin::Create(GURL(kTestRpUrl)), top_level_origin_obj,
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_),
         test_permission_delegate_.get(),
@@ -311,10 +316,15 @@
 
   IdpClientMetadata SendClientMetadataRequestAndWaitForResponse(
       const char* client_id,
-      const std::string& response = R"({})") {
+      const std::string& response = R"({})",
+      const char* top_level_origin = nullptr) {
     GURL client_id_endpoint(kTestClientMetadataEndpoint);
-    AddResponse(GURL(client_id_endpoint.spec() + "?client_id=" + client_id),
-                net::HTTP_OK, "application/json", response);
+    std::string url_string =
+        client_id_endpoint.spec() + "?client_id=" + client_id;
+    if (top_level_origin) {
+      url_string += std::string("&top_frame_origin=") + top_level_origin;
+    }
+    AddResponse(GURL(url_string), net::HTTP_OK, "application/json", response);
 
     IdpClientMetadata data;
     base::RunLoop run_loop;
@@ -324,7 +334,8 @@
           run_loop.Quit();
         });
 
-    std::unique_ptr<IdpNetworkRequestManager> manager = CreateTestManager();
+    std::unique_ptr<IdpNetworkRequestManager> manager =
+        CreateTestManager(top_level_origin);
     manager->FetchClientMetadata(
         client_id_endpoint, client_id, kTestBrandIconIdealSize,
         kTestBrandIconMinimumSize, std::move(callback));
@@ -914,6 +925,7 @@
 
   auto network_manager = std::make_unique<IdpNetworkRequestManager>(
       url::Origin::Create(GURL(kTestRpUrl)),
+      /*rp_embedding_origin=*/url::Origin(),
       base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
           &test_url_loader_factory),
       test_permission_delegate_.get(),
@@ -1766,6 +1778,19 @@
   ASSERT_EQ(GURL(), data.privacy_policy_url);
   ASSERT_EQ(GURL(), data.terms_of_service_url);
   ASSERT_EQ(GURL(), data.brand_icon_url);
+  ASSERT_FALSE(data.client_matches_top_frame_origin.has_value());
+}
+
+// Tests the "matches top frame" boolean.
+TEST_F(IdpNetworkRequestManagerTest, ClientMatchesTopFrameOrigin) {
+  base::test::ScopedFeatureList list;
+  list.InitAndEnableFeature(features::kFedCmIframeOrigin);
+
+  IdpClientMetadata data = SendClientMetadataRequestAndWaitForResponse(
+      "clientid", R"({"client_matches_top_frame_origin": false})",
+      "https://toplevel.example");
+  ASSERT_TRUE(data.client_matches_top_frame_origin.has_value());
+  EXPECT_FALSE(*data.client_matches_top_frame_origin);
 }
 
 // Tests that we correctly records metrics regarding approved_clients.
diff --git a/content/browser/webid/test/mock_idp_network_request_manager.cc b/content/browser/webid/test/mock_idp_network_request_manager.cc
index 545b52d..3375b22 100644
--- a/content/browser/webid/test/mock_idp_network_request_manager.cc
+++ b/content/browser/webid/test/mock_idp_network_request_manager.cc
@@ -10,6 +10,7 @@
 
 MockIdpNetworkRequestManager::MockIdpNetworkRequestManager()
     : IdpNetworkRequestManager(url::Origin(),
+                               url::Origin(),
                                nullptr,
                                nullptr,
                                network::mojom::ClientSecurityState::New()) {}
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 6e18afd..55e7a18f 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -238,6 +238,8 @@
            raw_ref(features::kUserMediaScreenCapturing)},
 #endif
           {wf::EnableInstalledApp, raw_ref(features::kInstalledApp)},
+          {wf::EnableIntegrityPolicyScript,
+           raw_ref(network::features::kIntegrityPolicyScript)},
           {wf::EnableLazyInitializeMediaControls,
            raw_ref(features::kLazyInitializeMediaControls)},
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/content/common/features.cc b/content/common/features.cc
index 9119155..4947a707 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -176,6 +176,13 @@
              "ExperimentalContentSecurityPolicyFeatures",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// For cross-site iframes, sends the top-level origin to the IDP and parses
+// an optional returned boolean indicating whether it is part of the same
+// client to allow for UI decisions based on the boolean.
+BASE_FEATURE(kFedCmIframeOrigin,
+             "FedCmIframeOrigin",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Whether to support the newer syntax for the "Use Other Account"
 // and account labels features.
 BASE_FEATURE(kFedCmUseOtherAccountAndLabelsNewSyntax,
diff --git a/content/common/features.h b/content/common/features.h
index 0764c2fd..eaff791 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -64,6 +64,7 @@
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kEmbeddingRequiresOptIn);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kExperimentalContentSecurityPolicyFeatures);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmIframeOrigin);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmUseOtherAccountAndLabelsNewSyntax);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmSameSiteLax);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFilterInstalledAppsWebAppMatching);
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 6e3de39..7743c3f 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -369,6 +369,7 @@
     "java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java",
     "java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java",
     "java/src/org/chromium/content/browser/webid/DigitalCredentialsCreationDelegate.java",
+    "java/src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegate.java",
     "java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java",
     "java/src/org/chromium/content_public/browser/ActionModeCallback.java",
     "java/src/org/chromium/content_public/browser/ActionModeCallbackHelper.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 921cd2a4..813642b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -1252,6 +1252,16 @@
                 .setSupportsForwardTransitionAnimation(mNativeWebContentsAndroid, supports);
     }
 
+    @Override
+    public boolean hasOpener() {
+        return WebContentsImplJni.get().hasOpener(mNativeWebContentsAndroid);
+    }
+
+    @Override
+    public int getOriginalWindowOpenDisposition() {
+        return WebContentsImplJni.get().getOriginalWindowOpenDisposition(mNativeWebContentsAndroid);
+    }
+
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     @NativeMethods
     public interface Natives {
@@ -1472,5 +1482,9 @@
                 long nativeWebContentsAndroid, Callback<Bitmap> callback);
 
         void setSupportsForwardTransitionAnimation(long nativeWebContentsAndroid, boolean enabled);
+
+        boolean hasOpener(long nativeWebContentsAndroid);
+
+        int getOriginalWindowOpenDisposition(long nativeWebContentsAndroid);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegate.java b/content/public/android/java/src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegate.java
new file mode 100644
index 0000000..5b89755
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/webid/DigitalCredentialsPresentationDelegate.java
@@ -0,0 +1,238 @@
+// Copyright 2025 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.content.browser.webid;
+
+import static androidx.core.app.ActivityCompat.startIntentSenderForResult;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
+import android.credentials.GetCredentialResponse;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ResultReceiver;
+
+import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
+
+import com.google.android.gms.identitycredentials.CredentialOption;
+import com.google.android.gms.identitycredentials.GetCredentialException;
+import com.google.android.gms.identitycredentials.GetCredentialRequest;
+import com.google.android.gms.identitycredentials.IdentityCredentialClient;
+import com.google.android.gms.identitycredentials.IdentityCredentialManager;
+import com.google.android.gms.identitycredentials.IntentHelper;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.chromium.base.IntentUtils;
+import org.chromium.base.Log;
+import org.chromium.base.Promise;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.content.browser.webid.IdentityCredentialsDelegate.DigitalCredential;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+@NullMarked
+public class DigitalCredentialsPresentationDelegate {
+    private static final String TAG = "DCPresentDelegate";
+
+    // Arbitrary request code that is used when invoking the GMSCore API.
+    private static final int REQUEST_CODE_DIGITAL_CREDENTIALS = 777;
+
+    @VisibleForTesting
+    public static final String BUNDLE_KEY_REQUEST_JSON =
+            "androidx.credentials.BUNDLE_KEY_REQUEST_JSON";
+
+    @VisibleForTesting public static final String DC_API_RESPONSE_PROTOCOL_KEY = "protocol";
+    @VisibleForTesting public static final String DC_API_RESPONSE_DATA_KEY = "data";
+    @VisibleForTesting public static final String BUNDLE_KEY_IDENTITY_TOKEN = "identityToken";
+
+    @VisibleForTesting
+    public static final String BUNDLE_KEY_PROVIDER_DATA =
+            "androidx.identitycredentials.BUNDLE_KEY_PROVIDER_DATA";
+
+    @VisibleForTesting
+    public static final String EXTRA_GET_CREDENTIAL_RESPONSE =
+            "android.service.credentials.extra.GET_CREDENTIAL_RESPONSE";
+
+    @VisibleForTesting
+    public static final String EXTRA_CREDENTIAL_DATA =
+            "androidx.credentials.provider.extra.EXTRA_CREDENTIAL_DATA";
+
+    public Promise<DigitalCredential> get(Activity window, String origin, String request) {
+        final IdentityCredentialClient client;
+        try {
+            client = IdentityCredentialManager.Companion.getClient(window);
+        } catch (Exception e) {
+            // Thrown when running in phones without the most current GMS
+            // version.
+            return Promise.rejected();
+        }
+
+        final Promise<DigitalCredential> result = new Promise<DigitalCredential>();
+
+        ResultReceiver resultReceiver =
+                new ResultReceiver(new Handler(Looper.getMainLooper())) {
+                    // android.credentials.GetCredentialException requires API level 34
+                    @SuppressWarnings("NewApi")
+                    @Override
+                    protected void onReceiveResult(int code, Bundle data) {
+                        Log.d(TAG, "Received a response");
+                        try {
+                            result.fulfill(extractDigitalCredentialFromResponseBundle(code, data));
+                        } catch (Exception e) {
+                            Log.e(TAG, e.toString());
+
+                            if (e instanceof GetCredentialException
+                                    && Build.VERSION.SDK_INT
+                                            >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+                                String exceptionType = ((GetCredentialException) e).getType();
+                                result.reject(
+                                        new android.credentials.GetCredentialException(
+                                                exceptionType, e.getMessage()));
+                            } else {
+                                result.reject(e);
+                            }
+                        }
+                    }
+                };
+
+        client.getCredential(
+                        new GetCredentialRequest(
+                                Arrays.asList(
+                                        new CredentialOption(
+                                                "com.credman.IdentityCredential",
+                                                new Bundle(),
+                                                new Bundle(),
+                                                request,
+                                                "",
+                                                "")),
+                                new Bundle(),
+                                origin,
+                                resultReceiver))
+                .addOnSuccessListener(
+                        response -> {
+                            try {
+                                Log.d(TAG, "Sending an intent for sender");
+                                Log.d(TAG, request);
+                                startIntentSenderForResult(
+                                        /* activity= */ window,
+                                        /* intent= */ response.getPendingIntent().getIntentSender(),
+                                        REQUEST_CODE_DIGITAL_CREDENTIALS,
+                                        /* fillInIntent= */ null,
+                                        /* flagsMask= */ 0,
+                                        /* flagsValues= */ 0,
+                                        /* extraFlags= */ 0,
+                                        /* options= */ null);
+                            } catch (SendIntentException e) {
+                                Log.e(TAG, "Sending an intent for sender failed");
+                                result.reject(e);
+                            }
+                        });
+
+        return result;
+    }
+
+    /**
+     * Extracts a DigitalCredential from a response bundle.
+     *
+     * <p>This method attempts to extract a DigitalCredential from the given response bundle. It
+     * first tries to parse the response in the new format. If that fails, it falls back to the
+     * legacy format.
+     *
+     * @param code The result code from the activity.
+     * @param bundle The bundle containing the response data.
+     * @return The extracted DigitalCredential.
+     * @throws JSONException If there is an error parsing the JSON data.
+     * @throws NullPointerException If required data is missing in the legacy format.
+     * @throws GetCredentialException If there is an issue with the credential.
+     */
+    @VisibleForTesting
+    public static DigitalCredential extractDigitalCredentialFromResponseBundle(
+            int code, Bundle bundle)
+            throws JSONException, NullPointerException, GetCredentialException {
+        // Try to read the new format.
+        var digitalCredential = extractDigitalCredentialFromModernResponse(bundle);
+        if (digitalCredential != null) {
+            return digitalCredential;
+        }
+        // TODO(crbug.com/336329411) Handle the case when the intent doesn't contain the modern
+        // response, but contains the modern exception.
+
+        // Fallback to the legacy format.
+        var response = IntentHelper.extractGetCredentialResponse(code, bundle);
+        var token = response.getCredential().getData().getByteArray(BUNDLE_KEY_IDENTITY_TOKEN);
+
+        return new DigitalCredential(null, Objects.requireNonNull(token));
+    }
+
+    /**
+     * Extracts a DigitalCredential from a response bundle in the modern format.
+     *
+     * @param bundle The bundle containing the response data.
+     * @return The extracted DigitalCredential, or null if the response is not in the modern format.
+     * @throws JSONException If there is an error parsing the JSON data.
+     */
+    private static @Nullable DigitalCredential extractDigitalCredentialFromModernResponse(
+            Bundle bundle) throws JSONException {
+        Intent intent = IntentUtils.safeGetParcelable(bundle, BUNDLE_KEY_PROVIDER_DATA);
+        if (intent == null) {
+            return null;
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+            return extractDigitalCredentialIntentAfter34(intent);
+        }
+        return extractDigitalCredentialIntentBefore34(intent);
+    }
+
+    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    private static @Nullable DigitalCredential extractDigitalCredentialIntentAfter34(Intent intent)
+            throws JSONException {
+        GetCredentialResponse response =
+                IntentUtils.safeGetParcelableExtra(intent, EXTRA_GET_CREDENTIAL_RESPONSE);
+        if (response == null) {
+            return null;
+        }
+        return extractDigitalCredentialFromCredentialDataBundle(response.getCredential().getData());
+    }
+
+    private static @Nullable DigitalCredential extractDigitalCredentialIntentBefore34(Intent intent)
+            throws JSONException {
+        Bundle responseBundle =
+                IntentUtils.safeGetBundleExtra(intent, EXTRA_GET_CREDENTIAL_RESPONSE);
+        if (responseBundle == null) {
+            return null;
+        }
+        return extractDigitalCredentialFromCredentialDataBundle(
+                IntentUtils.safeGetBundle(responseBundle, EXTRA_CREDENTIAL_DATA));
+    }
+
+    private static @Nullable DigitalCredential extractDigitalCredentialFromCredentialDataBundle(
+            @Nullable Bundle bundle) throws JSONException {
+        if (bundle == null) {
+            return null;
+        }
+        String credentialJson = bundle.getString(BUNDLE_KEY_REQUEST_JSON);
+        if (credentialJson == null) {
+            return null;
+        }
+        JSONObject credential = new JSONObject(credentialJson);
+        // Unless the json contains the protocol, return null to fallback to the legacy format.
+        if (credential.has(DC_API_RESPONSE_PROTOCOL_KEY)) {
+            String protocol = credential.getString(DC_API_RESPONSE_PROTOCOL_KEY);
+            var data = credential.getJSONObject(DC_API_RESPONSE_DATA_KEY);
+            return new DigitalCredential(protocol, data.toString());
+        }
+        // Otherwise, treat the whole json as the response. This is added for backward compatibility
+        // where GMSCore was setting the modern response with the contents of the legacy response
+        // without a protocol.
+        return new DigitalCredential(null, credentialJson);
+    }
+}
\ No newline at end of file
diff --git a/content/public/android/java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java b/content/public/android/java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java
index 22436a03..22d8b3b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java
@@ -4,68 +4,17 @@
 
 package org.chromium.content.browser.webid;
 
-import static androidx.core.app.ActivityCompat.startIntentSenderForResult;
-
 import android.app.Activity;
-import android.content.Intent;
-import android.content.IntentSender.SendIntentException;
-import android.credentials.GetCredentialResponse;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.ResultReceiver;
 
-import androidx.annotation.RequiresApi;
-import androidx.annotation.VisibleForTesting;
-
-import com.google.android.gms.identitycredentials.CredentialOption;
-import com.google.android.gms.identitycredentials.GetCredentialException;
-import com.google.android.gms.identitycredentials.GetCredentialRequest;
-import com.google.android.gms.identitycredentials.IdentityCredentialClient;
-import com.google.android.gms.identitycredentials.IdentityCredentialManager;
-import com.google.android.gms.identitycredentials.IntentHelper;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.chromium.base.IntentUtils;
-import org.chromium.base.Log;
 import org.chromium.base.Promise;
 import org.chromium.base.ServiceLoaderUtil;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 
-import java.util.Arrays;
-import java.util.Objects;
-
 @NullMarked
 public class IdentityCredentialsDelegate {
     private static final String TAG = "IdentityCredentials";
 
-    // Arbitrary request code that is used when invoking the GMSCore API.
-    private static final int REQUEST_CODE_DIGITAL_CREDENTIALS = 777;
-
-    @VisibleForTesting
-    public static final String BUNDLE_KEY_REQUEST_JSON =
-            "androidx.credentials.BUNDLE_KEY_REQUEST_JSON";
-
-    @VisibleForTesting public static final String DC_API_RESPONSE_PROTOCOL_KEY = "protocol";
-    @VisibleForTesting public static final String DC_API_RESPONSE_DATA_KEY = "data";
-    @VisibleForTesting public static final String BUNDLE_KEY_IDENTITY_TOKEN = "identityToken";
-
-    @VisibleForTesting
-    public static final String BUNDLE_KEY_PROVIDER_DATA =
-            "androidx.identitycredentials.BUNDLE_KEY_PROVIDER_DATA";
-
-    @VisibleForTesting
-    public static final String EXTRA_GET_CREDENTIAL_RESPONSE =
-            "android.service.credentials.extra.GET_CREDENTIAL_RESPONSE";
-
-    @VisibleForTesting
-    public static final String EXTRA_CREDENTIAL_DATA =
-            "androidx.credentials.provider.extra.EXTRA_CREDENTIAL_DATA";
-
     public static class DigitalCredential {
         @Nullable public String mProtocol;
         public String mData;
@@ -87,77 +36,9 @@
     }
 
     public Promise<DigitalCredential> get(Activity window, String origin, String request) {
-        final IdentityCredentialClient client;
-        try {
-            client = IdentityCredentialManager.Companion.getClient(window);
-        } catch (Exception e) {
-            // Thrown when running in phones without the most current GMS
-            // version.
-            return Promise.rejected();
-        }
-
-        final Promise<DigitalCredential> result = new Promise<DigitalCredential>();
-
-        ResultReceiver resultReceiver =
-                new ResultReceiver(new Handler(Looper.getMainLooper())) {
-                    // android.credentials.GetCredentialException requires API level 34
-                    @SuppressWarnings("NewApi")
-                    @Override
-                    protected void onReceiveResult(int code, Bundle data) {
-                        Log.d(TAG, "Received a response");
-                        try {
-                            result.fulfill(extractDigitalCredentialFromResponseBundle(code, data));
-                        } catch (Exception e) {
-                            Log.e(TAG, e.toString());
-
-                            if (e instanceof GetCredentialException
-                                    && Build.VERSION.SDK_INT
-                                            >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
-                                String exceptionType = ((GetCredentialException) e).getType();
-                                result.reject(
-                                        new android.credentials.GetCredentialException(
-                                                exceptionType, e.getMessage()));
-                            } else {
-                                result.reject(e);
-                            }
-                        }
-                    }
-                };
-
-        client.getCredential(
-                        new GetCredentialRequest(
-                                Arrays.asList(
-                                        new CredentialOption(
-                                                "com.credman.IdentityCredential",
-                                                new Bundle(),
-                                                new Bundle(),
-                                                request,
-                                                "",
-                                                "")),
-                                new Bundle(),
-                                origin,
-                                resultReceiver))
-                .addOnSuccessListener(
-                        response -> {
-                            try {
-                                Log.d(TAG, "Sending an intent for sender");
-                                Log.d(TAG, request);
-                                startIntentSenderForResult(
-                                        /* activity= */ window,
-                                        /* intent= */ response.getPendingIntent().getIntentSender(),
-                                        REQUEST_CODE_DIGITAL_CREDENTIALS,
-                                        /* fillInIntent= */ null,
-                                        /* flagsMask= */ 0,
-                                        /* flagsValues= */ 0,
-                                        /* extraFlags= */ 0,
-                                        /* options= */ null);
-                            } catch (SendIntentException e) {
-                                Log.e(TAG, "Sending an intent for sender failed");
-                                result.reject(e);
-                            }
-                        });
-
-        return result;
+        DigitalCredentialsPresentationDelegate presentationDelegate =
+                new DigitalCredentialsPresentationDelegate();
+        return presentationDelegate.get(window, origin, request);
     }
 
     public Promise<String> create(Activity window, String origin, String request) {
@@ -168,100 +49,4 @@
         }
         return Promise.rejected();
     }
-
-    /**
-     * Extracts a DigitalCredential from a response bundle.
-     *
-     * <p>This method attempts to extract a DigitalCredential from the given response bundle. It
-     * first tries to parse the response in the new format. If that fails, it falls back to the
-     * legacy format.
-     *
-     * @param code The result code from the activity.
-     * @param bundle The bundle containing the response data.
-     * @return The extracted DigitalCredential.
-     * @throws JSONException If there is an error parsing the JSON data.
-     * @throws NullPointerException If required data is missing in the legacy format.
-     * @throws GetCredentialException If there is an issue with the credential.
-     */
-    @VisibleForTesting
-    public static DigitalCredential extractDigitalCredentialFromResponseBundle(
-            int code, Bundle bundle)
-            throws JSONException, NullPointerException, GetCredentialException {
-        // Try to read the new format.
-        var digitalCredential = extractDigitalCredentialFromModernResponse(bundle);
-        if (digitalCredential != null) {
-            return digitalCredential;
-        }
-        // TODO(crbug.com/336329411) Handle the case when the intent doesn't contain the modern
-        // response, but contains the modern exception.
-
-        // Fallback to the legacy format.
-        var response = IntentHelper.extractGetCredentialResponse(code, bundle);
-        var token = response.getCredential().getData().getByteArray(BUNDLE_KEY_IDENTITY_TOKEN);
-
-        return new DigitalCredential(null, Objects.requireNonNull(token));
-    }
-
-    /**
-     * Extracts a DigitalCredential from a response bundle in the modern format.
-     *
-     * @param bundle The bundle containing the response data.
-     * @return The extracted DigitalCredential, or null if the response is not in the modern format.
-     * @throws JSONException If there is an error parsing the JSON data.
-     */
-    private static @Nullable DigitalCredential extractDigitalCredentialFromModernResponse(
-            Bundle bundle) throws JSONException {
-        Intent intent = IntentUtils.safeGetParcelable(bundle, BUNDLE_KEY_PROVIDER_DATA);
-        if (intent == null) {
-            return null;
-        }
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
-            return extractDigitalCredentialIntentAfter34(intent);
-        }
-        return extractDigitalCredentialIntentBefore34(intent);
-    }
-
-    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-    private static @Nullable DigitalCredential extractDigitalCredentialIntentAfter34(Intent intent)
-            throws JSONException {
-        GetCredentialResponse response =
-                IntentUtils.safeGetParcelableExtra(intent, EXTRA_GET_CREDENTIAL_RESPONSE);
-        if (response == null) {
-            return null;
-        }
-        return extractDigitalCredentialFromCredentialDataBundle(response.getCredential().getData());
-    }
-
-    private static @Nullable DigitalCredential extractDigitalCredentialIntentBefore34(Intent intent)
-            throws JSONException {
-        Bundle responseBundle =
-                IntentUtils.safeGetBundleExtra(intent, EXTRA_GET_CREDENTIAL_RESPONSE);
-        if (responseBundle == null) {
-            return null;
-        }
-        return extractDigitalCredentialFromCredentialDataBundle(
-                IntentUtils.safeGetBundle(responseBundle, EXTRA_CREDENTIAL_DATA));
-    }
-
-    private static @Nullable DigitalCredential extractDigitalCredentialFromCredentialDataBundle(
-            @Nullable Bundle bundle) throws JSONException {
-        if (bundle == null) {
-            return null;
-        }
-        String credentialJson = bundle.getString(BUNDLE_KEY_REQUEST_JSON);
-        if (credentialJson == null) {
-            return null;
-        }
-        JSONObject credential = new JSONObject(credentialJson);
-        // Unless the json contains the protocol, return null to fallback to the legacy format.
-        if (credential.has(DC_API_RESPONSE_PROTOCOL_KEY)) {
-            String protocol = credential.getString(DC_API_RESPONSE_PROTOCOL_KEY);
-            var data = credential.getJSONObject(DC_API_RESPONSE_DATA_KEY);
-            return new DigitalCredential(protocol, data.toString());
-        }
-        // Otherwise, treat the whole json as the response. This is added for backward compatibility
-        // where GMSCore was setting the modern response with the contents of the legacy response
-        // without a protocol.
-        return new DigitalCredential(null, credentialJson);
-    }
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index e7733eb1..b72ef12 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -638,6 +638,25 @@
     void setSupportsForwardTransitionAnimation(boolean supports);
 
     /**
+     * @return whether this WebContents has an opener (corresponding to window.opener in JavaScript)
+     *     associated with it.
+     */
+    boolean hasOpener();
+
+    /**
+     * Returns the window open disposition that was originally requested when this WebContents was
+     * created or navigated to. This method provides the disposition specified by the opener of this
+     * WebContents, indicating how the content was initially intended to be displayed (e.g., as a
+     * new foreground tab, a background tab, a new window, a popup, etc.). This value is determined
+     * at the point of creation, such as during a navigation that results in a new WebContents
+     * (e.g., from a link click with `target="_blank"`, `window.open()`, or a browser-initiated
+     * action).
+     *
+     * @return an integer constant representing the original window open disposition.
+     */
+    int getOriginalWindowOpenDisposition();
+
+    /**
      * Factory interface passed to {@link #getOrSetUserData()} for instantiation of class as user
      * data.
      *
diff --git a/content/public/browser/ax_inspect_factory_mac.mm b/content/public/browser/ax_inspect_factory_mac.mm
index f26c962..9744ee9 100644
--- a/content/public/browser/ax_inspect_factory_mac.mm
+++ b/content/public/browser/ax_inspect_factory_mac.mm
@@ -53,8 +53,8 @@
 
   switch (type) {
     case ui::AXApiType::kMac:
-      return std::make_unique<ui::AXEventRecorderMac>(manager->GetWeakPtr(),
-                                                      pid, selector);
+      return std::make_unique<ui::AXEventRecorderMac>(
+          manager ? manager->GetWeakPtr() : nullptr, pid, selector);
     default:
       NOTREACHED() << "Unsupported API type " << type;
   }
diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h
index 4711310..0573699d 100644
--- a/content/public/browser/first_party_sets_handler.h
+++ b/content/public/browser/first_party_sets_handler.h
@@ -158,14 +158,14 @@
 
   // Computes a representation of the changes that need to be made to the
   // browser's list of First-Party Sets to respect the `policy` value of the
-  // First-Party Sets Overrides enterprise policy. If `policy` is nullptr,
-  // `callback` is immediately invoked with an empty config.
+  // First-Party Sets Overrides enterprise policy. If `policy` is
+  // `std::nullopt`, `callback` is immediately invoked with an empty config.
   //
   // Otherwise, the context config will be returned via `callback` since the
   // context config must be computed after the list of First-Party Sets is
   // initialized which occurs asynchronously.
   virtual void GetContextConfigForPolicy(
-      const base::Value::Dict* policy,
+      base::optional_ref<const base::Value::Dict> policy,
       base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) = 0;
 
   // Clear site state of sites that have a FPS membership change for the browser
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 9360a2b..ea5856a 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -1694,6 +1694,16 @@
   virtual GURL GetPartitionedPopinEmbedderOrigin(
       base::PassKey<StorageAccessGrantPermissionContext>) const = 0;
 
+  // Returns the window open disposition that was originally requested
+  // when this WebContents was created.
+  // This method provides the disposition specified by the opener of this
+  // WebContents, indicating how the content was initially intended to be
+  // displayed (e.g., as a new foreground tab, a background tab, a new window,
+  // a popup, etc.). This value is determined at the point of
+  // creation, such as during a navigation that results in a new WebContents
+  // (e.g., from a link click with `target="_blank"`, `window.open()`).
+  virtual WindowOpenDisposition GetOriginalWindowOpenDisposition() const = 0;
+
  private:
   // This interface should only be implemented inside content.
   friend class WebContentsImpl;
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index b390356..aabcebe 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -145,6 +145,7 @@
 }
 
 bool WebContentsDelegate::IsWebContentsCreationOverridden(
+    RenderFrameHost* opener,
     SiteInstance* source_site_instance,
     mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index da319cb2..0125c481 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -351,6 +351,7 @@
   // If an delegate returns true, it can optionally also override
   // CreateCustomWebContents() below to provide their own WebContents.
   virtual bool IsWebContentsCreationOverridden(
+      RenderFrameHost* opener,
       SiteInstance* source_site_instance,
       mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index a02b40d..761ea53 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -1189,7 +1189,7 @@
 // If enabled, blink's context snapshot is used rather than the v8 snapshot.
 BASE_FEATURE(kUseContextSnapshot,
              "UseContextSnapshot",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 #endif
 
 // Enables comparing browser and renderer's DidCommitProvisionalLoadParams in
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
index 0eb3fe6..f435592 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
@@ -392,6 +392,16 @@
     public void setSupportsForwardTransitionAnimation(boolean supports) {}
 
     @Override
+    public boolean hasOpener() {
+        return false;
+    }
+
+    @Override
+    public int getOriginalWindowOpenDisposition() {
+        return 0;
+    }
+
+    @Override
     public <T extends UserData> @Nullable T getOrSetUserData(
             Class<T> key, @Nullable UserDataFactory<T> userDataFactory) {
         return null;
diff --git a/content/public/test/test_aggregation_service.cc b/content/public/test/test_aggregation_service.cc
index 9a3fd681..fd8728e 100644
--- a/content/public/test/test_aggregation_service.cc
+++ b/content/public/test/test_aggregation_service.cc
@@ -20,9 +20,8 @@
     Operation operation,
     absl::uint128 bucket,
     int value,
-    AggregationMode aggregation_mode,
     url::Origin reporting_origin,
-    std::vector<GURL> processing_urls,
+    GURL processing_url,
     bool is_debug_mode_enabled,
     base::Value::Dict additional_fields,
     std::string api_version,
@@ -30,9 +29,8 @@
     : operation(operation),
       bucket(bucket),
       value(value),
-      aggregation_mode(aggregation_mode),
       reporting_origin(std::move(reporting_origin)),
-      processing_urls(std::move(processing_urls)),
+      processing_url(std::move(processing_url)),
       is_debug_mode_enabled(is_debug_mode_enabled),
       additional_fields(std::move(additional_fields)),
       api_version(std::move(api_version)),
diff --git a/content/public/test/test_aggregation_service.h b/content/public/test/test_aggregation_service.h
index edb010d8..5d3d007 100644
--- a/content/public/test/test_aggregation_service.h
+++ b/content/public/test/test_aggregation_service.h
@@ -7,15 +7,13 @@
 
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "base/functional/callback_forward.h"
 #include "base/values.h"
 #include "third_party/abseil-cpp/absl/numeric/int128.h"
+#include "url/gurl.h"
 #include "url/origin.h"
 
-class GURL;
-
 template <class T>
 class scoped_refptr;
 
@@ -42,21 +40,13 @@
     kHistogram,
   };
 
-  // This is 1-1 mapping of AggregationServicePayloadContent::AggregationMode.
-  enum class AggregationMode {
-    kTeeBased,
-    kExperimentalPoplar,
-    kDefault = kTeeBased,
-  };
-
   // Represents a request to assemble an aggregatable report.
   struct AssembleRequest {
     AssembleRequest(Operation operation,
                     absl::uint128 bucket,
                     int value,
-                    AggregationMode aggregation_mode,
                     url::Origin reporting_origin,
-                    std::vector<GURL> processing_urls,
+                    GURL processing_url,
                     bool is_debug_mode_enabled,
                     base::Value::Dict additional_fields,
                     std::string api_version,
@@ -71,14 +61,12 @@
     absl::uint128 bucket;
     // Specifies the bucket value of the histogram contribution.
     int value;
-    // Specifies the aggregation mode to use.
-    AggregationMode aggregation_mode;
     // Specifies the endpoint reporting origin.
     url::Origin reporting_origin;
     // Specifies the key for the aggregation servers to do privacy budgeting.
     std::string privacy_budget_key;
-    // Specifies the aggregation server URLs.
-    std::vector<GURL> processing_urls;
+    // Specifies the aggregation server URL.
+    GURL processing_url;
     // Whether debug_mode should be enabled for the report.
     bool is_debug_mode_enabled;
 
diff --git a/content/renderer/policy_container_util.cc b/content/renderer/policy_container_util.cc
index bbf8be6..973e72e 100644
--- a/content/renderer/policy_container_util.cc
+++ b/content/renderer/policy_container_util.cc
@@ -17,6 +17,8 @@
   return std::make_unique<blink::WebPolicyContainer>(
       blink::WebPolicyContainerPolicies{
           in->policies->cross_origin_embedder_policy.value,
+          in->policies->integrity_policy,
+          in->policies->integrity_policy_report_only,
           in->policies->referrer_policy,
           ToWebContentSecurityPolicies(
               std::move(in->policies->content_security_policies)),
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc
index af58d4f..d166cb2 100644
--- a/content/services/auction_worklet/bidder_worklet_unittest.cc
+++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -8238,7 +8238,6 @@
                   /*event_type=*/
                   mojom::EventType::NewReservedNonError(
                       mojom::ReservedNonErrorEventType::kReservedWin))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New()));
   RunReportWinExpectingResultAsync(
       worklet_impl, /*expected_report_url=*/std::nullopt,
@@ -12288,7 +12287,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedRequest2(
       mojom::AggregatableReportContribution::NewHistogramContribution(
@@ -12297,7 +12295,6 @@
                                           /*low=*/0),
               /*value=*/1,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 
   mojom::PrivateAggregationRequest kExpectedForEventRequest1(
@@ -12309,7 +12306,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedNonError(
                   mojom::ReservedNonErrorEventType::kReservedWin))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedForEventRequest2(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -12322,7 +12318,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedNonError(
                   mojom::ReservedNonErrorEventType::kReservedWin))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 
   // Only contributeToHistogram() is called.
@@ -12538,13 +12533,11 @@
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedRequest1.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, blink::mojom::DebugKey::New(1234u))));
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedForEventRequest1.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, blink::mojom::DebugKey::New(1234u))));
 
@@ -12574,13 +12567,11 @@
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedRequest1.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, /*debug_key=*/nullptr)));
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedRequest2.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, /*debug_key=*/nullptr)));
 
@@ -12635,7 +12626,6 @@
                 /*bucket=*/123,
                 /*value=*/45,
                 /*filtering_id=*/0)),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         mojom::AggregatableReportContribution::NewForEventContribution(
@@ -12646,7 +12636,6 @@
                 /*event_type=*/
                 mojom::EventType::NewReservedNonError(
                     mojom::ReservedNonErrorEventType::kReservedWin))),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
 
     RunGenerateBidWithJavascriptExpectingResult(
@@ -12693,7 +12682,6 @@
                     /*event_type=*/
                     mojom::EventType::NewReservedNonError(
                         mojom::ReservedNonErrorEventType::kReservedLoss))),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New()));
 
     RunGenerateBidWithJavascriptExpectingResult(
@@ -12737,7 +12725,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
   expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -12748,7 +12735,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedError(
                   mojom::ReservedErrorEventType::kReportSuccess))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   RunGenerateBidWithJavascriptExpectingResult(
@@ -12780,7 +12766,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   // If the error reporting feature is disabled, the call should be silently
@@ -12814,7 +12799,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   auction_worklet::mojom::PrivateAggregationRequest kExpectedRequest2(
       mojom::AggregatableReportContribution::NewHistogramContribution(
@@ -12822,7 +12806,6 @@
               /*bucket=*/absl::MakeInt128(/*high=*/1, /*low=*/0),
               /*value=*/1,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedForEventRequest1(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -12833,7 +12816,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedNonError(
                   mojom::ReservedNonErrorEventType::kReservedWin))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedForEventRequest2(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -12846,7 +12828,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedNonError(
                   mojom::ReservedNonErrorEventType::kReservedWin))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 
   {
@@ -12957,13 +12938,11 @@
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedRequest1.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, blink::mojom::DebugKey::New(1234u))));
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedForEventRequest1.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, blink::mojom::DebugKey::New(1234u))));
 
@@ -12987,13 +12966,11 @@
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedRequest1.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, /*debug_key=*/nullptr)));
     expected_pa_requests.push_back(
         auction_worklet::mojom::PrivateAggregationRequest::New(
             kExpectedRequest2.contribution->Clone(),
-            blink::mojom::AggregationServiceMode::kDefault,
             blink::mojom::DebugModeDetails::New(
                 /*is_enabled=*/true, /*debug_key=*/nullptr)));
 
@@ -13039,7 +13016,6 @@
                 /*bucket=*/123,
                 /*value=*/45,
                 /*filtering_id=*/0)),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         mojom::AggregatableReportContribution::NewForEventContribution(
@@ -13050,7 +13026,6 @@
                 /*event_type=*/
                 mojom::EventType::NewReservedNonError(
                     mojom::ReservedNonErrorEventType::kReservedWin))),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
 
     RunReportWinWithFunctionBodyExpectingResult(
@@ -13076,7 +13051,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
   expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -13087,7 +13061,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedError(
                   mojom::ReservedErrorEventType::kReportSuccess))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   RunReportWinWithFunctionBodyExpectingResult(
@@ -13113,7 +13086,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   // If the error reporting feature is disabled, the call should be silently
diff --git a/content/services/auction_worklet/context_recycler_unittest.cc b/content/services/auction_worklet/context_recycler_unittest.cc
index a179991..3b27faff 100644
--- a/content/services/auction_worklet/context_recycler_unittest.cc
+++ b/content/services/auction_worklet/context_recycler_unittest.cc
@@ -3854,7 +3854,6 @@
     auction_worklet::mojom::PrivateAggregationRequest expected_request(
         auction_worklet::mojom::AggregatableReportContribution::
             NewHistogramContribution(expected_contribution.Clone()),
-        blink::mojom::AggregationServiceMode::kDefault,
         std::move(debug_mode_details));
 
     ASSERT_EQ(pa_requests.size(), 1u);
@@ -4045,7 +4044,6 @@
     auction_worklet::mojom::PrivateAggregationRequest expected_request_1(
         auction_worklet::mojom::AggregatableReportContribution::
             NewHistogramContribution(expected_contribution_1.Clone()),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New());
 
     blink::mojom::AggregatableReportHistogramContribution
@@ -4054,7 +4052,6 @@
     auction_worklet::mojom::PrivateAggregationRequest expected_request_2(
         auction_worklet::mojom::AggregatableReportContribution::
             NewHistogramContribution(expected_contribution_2.Clone()),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New());
 
     PrivateAggregationRequests pa_requests =
@@ -4604,7 +4601,6 @@
     auction_worklet::mojom::PrivateAggregationRequest expected_request_1(
         auction_worklet::mojom::AggregatableReportContribution::
             NewHistogramContribution(expected_contribution_1.Clone()),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true,
             /*debug_key=*/blink::mojom::DebugKey::New(1234u)));
@@ -4615,7 +4611,6 @@
     auction_worklet::mojom::PrivateAggregationRequest expected_request_2(
         auction_worklet::mojom::AggregatableReportContribution::
             NewHistogramContribution(expected_contribution_2.Clone()),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true,
             /*debug_key=*/blink::mojom::DebugKey::New(1234u)));
@@ -4653,7 +4648,6 @@
     return auction_worklet::mojom::PrivateAggregationRequest::New(
         auction_worklet::mojom::AggregatableReportContribution::
             NewForEventContribution(contribution.Clone()),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New());
   }
 
@@ -4668,7 +4662,6 @@
     auction_worklet::mojom::PrivateAggregationRequest expected_request(
         auction_worklet::mojom::AggregatableReportContribution::
             NewForEventContribution(expected_contribution.Clone()),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New());
 
     ASSERT_EQ(pa_requests.size(), 1u);
diff --git a/content/services/auction_worklet/private_aggregation_bindings.cc b/content/services/auction_worklet/private_aggregation_bindings.cc
index 0660d7f..a82c6a6 100644
--- a/content/services/auction_worklet/private_aggregation_bindings.cc
+++ b/content/services/auction_worklet/private_aggregation_bindings.cc
@@ -478,8 +478,6 @@
                           contribution) {
                  return auction_worklet::mojom::PrivateAggregationRequest::New(
                      std::move(contribution),
-                     // TODO(alexmt): consider allowing this to be set
-                     blink::mojom::AggregationServiceMode::kDefault,
                      debug_mode_details_.Clone());
                });
   private_aggregation_contributions_.clear();
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 44b1eb1a..b80a2a6 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
@@ -34,7 +34,6 @@
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewReservedNonError(
                       mojom::ReservedNonErrorEventType::kReservedOnce))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using reserved.always as the event.
@@ -47,7 +46,6 @@
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewReservedNonError(
                       mojom::ReservedNonErrorEventType::kReservedAlways))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using a custom event.
@@ -59,7 +57,6 @@
                   mojom::ForEventSignalValue::NewIntValue(2),
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewNonReserved("event_type"))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using kWinningBid base_value for bucket and value.
@@ -77,7 +74,6 @@
                                               0)),
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewNonReserved("event_type"))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using kAverageCodeFetchTime for value.
@@ -96,7 +92,6 @@
                           0)),
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewNonReserved("event_type"))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using kAverageCodeFetchTime for bucket.
@@ -115,7 +110,6 @@
                                               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.
@@ -126,7 +120,6 @@
                   /*bucket=*/42,
                   /*value=*/24,
                   /*filtering_id=*/std::nullopt)),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using kWinningBid base_value for bucket and value.
@@ -144,7 +137,6 @@
                                               0)),
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewNonReserved("event_type"))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using kRejectReason for value.
@@ -160,7 +152,6 @@
                           0)),
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewNonReserved("event_type"))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 
   // Using kRejectReason for bucket.
@@ -176,7 +167,6 @@
                   mojom::ForEventSignalValue::NewIntValue(2),
                   /*filtering_id=*/std::nullopt,
                   mojom::EventType::NewNonReserved("event_type"))),
-          blink::mojom::AggregationServiceMode::kDefault,
           blink::mojom::DebugModeDetails::New());
 };
 
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 d1b633d..02e7b26 100644
--- a/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom
+++ b/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom
@@ -145,7 +145,6 @@
 // on the type of contribution.
 struct PrivateAggregationRequest {
   AggregatableReportContribution contribution;
-  blink.mojom.AggregationServiceMode aggregation_mode;
   blink.mojom.DebugModeDetails debug_mode_details;
 };
 
@@ -154,7 +153,6 @@
 // that condition is tracked outside this type).
 struct FinalizedPrivateAggregationRequest {
   blink.mojom.AggregatableReportHistogramContribution contribution;
-  blink.mojom.AggregationServiceMode aggregation_mode;
   blink.mojom.DebugModeDetails debug_mode_details;
 
   // If null, this contribution is unconditional. If populated, this
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc
index 439d17a..11d5a00 100644
--- a/content/services/auction_worklet/seller_worklet_unittest.cc
+++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -7880,7 +7880,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedRequest2(
       mojom::AggregatableReportContribution::NewHistogramContribution(
@@ -7888,7 +7887,6 @@
               /*bucket=*/absl::MakeInt128(/*high=*/1, /*low=*/0),
               /*value=*/1,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 
   mojom::PrivateAggregationRequest kExpectedForEventRequest1(
@@ -7900,7 +7898,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedNonError(
                   mojom::ReservedNonErrorEventType::kReservedWin))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedForEventRequest2(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -7913,7 +7910,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedNonError(
                   mojom::ReservedNonErrorEventType::kReservedWin))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 
   {
@@ -8041,12 +8037,10 @@
     PrivateAggregationRequests expected_pa_requests;
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         kExpectedRequest1.contribution->Clone(),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true, blink::mojom::DebugKey::New(1234u))));
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         kExpectedForEventRequest1.contribution->Clone(),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true, blink::mojom::DebugKey::New(1234u))));
 
@@ -8072,12 +8066,10 @@
     PrivateAggregationRequests expected_pa_requests;
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         kExpectedRequest1.contribution->Clone(),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true, /*debug_key=*/nullptr)));
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         kExpectedRequest2.contribution->Clone(),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true, /*debug_key=*/nullptr)));
 
@@ -8107,7 +8099,6 @@
                 /*bucket=*/123,
                 /*value=*/45,
                 /*filtering_id=*/0)),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         mojom::AggregatableReportContribution::NewForEventContribution(
@@ -8118,7 +8109,6 @@
                 /*event_type=*/
                 mojom::EventType::NewReservedNonError(
                     mojom::ReservedNonErrorEventType::kReservedWin))),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
 
     RunScoreAdWithJavascriptExpectingResult(
@@ -8146,7 +8136,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
   expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -8157,7 +8146,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedError(
                   mojom::ReservedErrorEventType::kReportSuccess))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   RunScoreAdWithJavascriptExpectingResult(
@@ -8184,7 +8172,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   // If the error reporting feature is disabled, the call should be silently
@@ -8213,7 +8200,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedRequest2(
       mojom::AggregatableReportContribution::NewHistogramContribution(
@@ -8221,7 +8207,6 @@
               /*bucket=*/absl::MakeInt128(/*high=*/1, /*low=*/0),
               /*value=*/1,
               /*filtering_id=*/std::nullopt)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
   mojom::PrivateAggregationRequest kExpectedForEventRequest(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -8232,7 +8217,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedNonError(
                   mojom::ReservedNonErrorEventType::kReservedWin))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New());
 
   // Only contributeToHistogram() is called.
@@ -8387,7 +8371,6 @@
     PrivateAggregationRequests expected_pa_requests;
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         kExpectedRequest1.contribution->Clone(),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true, blink::mojom::DebugKey::New(1234u))));
 
@@ -8408,12 +8391,10 @@
     PrivateAggregationRequests expected_pa_requests;
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         kExpectedRequest1.contribution->Clone(),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true, /*debug_key=*/nullptr)));
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         kExpectedRequest2.contribution->Clone(),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New(
             /*is_enabled=*/true, /*debug_key=*/nullptr)));
 
@@ -8456,7 +8437,6 @@
                 /*bucket=*/123,
                 /*value=*/45,
                 /*filtering_id=*/0)),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
     expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
         mojom::AggregatableReportContribution::NewForEventContribution(
@@ -8467,7 +8447,6 @@
                 /*event_type=*/
                 mojom::EventType::NewReservedNonError(
                     mojom::ReservedNonErrorEventType::kReservedWin))),
-        blink::mojom::AggregationServiceMode::kDefault,
         blink::mojom::DebugModeDetails::New()));
 
     RunReportResultCreatedScriptExpectingResult(
@@ -8493,7 +8472,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
   expected_pa_requests.push_back(mojom::PrivateAggregationRequest::New(
       mojom::AggregatableReportContribution::NewForEventContribution(
@@ -8504,7 +8482,6 @@
               /*event_type=*/
               mojom::EventType::NewReservedError(
                   mojom::ReservedErrorEventType::kReportSuccess))),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   RunReportResultCreatedScriptExpectingResult(
@@ -8531,7 +8508,6 @@
               /*bucket=*/123,
               /*value=*/45,
               /*filtering_id=*/0)),
-      blink::mojom::AggregationServiceMode::kDefault,
       blink::mojom::DebugModeDetails::New()));
 
   // If the error reporting feature is disabled, the call should be silently
diff --git a/content/shell/app/paths_mac.mm b/content/shell/app/paths_mac.mm
index a660a02e..97428aa 100644
--- a/content/shell/app/paths_mac.mm
+++ b/content/shell/app/paths_mac.mm
@@ -100,6 +100,6 @@
 
 void OverrideBundleID() {
   NSBundle* bundle = base::apple::OuterBundle();
-  base::apple::SetBaseBundleID(
-      base::SysNSStringToUTF8([bundle bundleIdentifier]).c_str());
+  base::apple::SetBaseBundleIDOverride(
+      base::SysNSStringToUTF8(bundle.bundleIdentifier));
 }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 2c8e8e9b..cc799cd5 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -3252,7 +3252,6 @@
     "//third_party/blink/public:test_support",
     "//third_party/blink/public/common:font_enumeration_table_proto",
     "//third_party/blink/public/common:headers",
-    "//third_party/distributed_point_functions/shim:buildflags",
     "//third_party/icu",
     "//third_party/inspector_protocol:crdtp",
     "//third_party/inspector_protocol:crdtp_test",
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index f67c734..8193dcd 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -525,7 +525,7 @@
 
 # Persistent flaking on Windows and Mac/M1
 crbug.com/365680830 [ amd64 angle-d3d11 graphite-enabled win ] deqp/functional/gles3/occlusionquery_strict.html [ Failure ]
-crbug.com/365680830 [ angle-metal apple sonoma ] deqp/functional/gles3/occlusionquery_strict.html [ RetryOnFailure ]
+crbug.com/365680830 [ mac mac-arm64 angle-metal ] deqp/functional/gles3/occlusionquery_strict.html [ Failure ]
 
 
 ####################
diff --git a/content/test/test_aggregation_service_impl.cc b/content/test/test_aggregation_service_impl.cc
index 84b1f5b..2ac28c4 100644
--- a/content/test/test_aggregation_service_impl.cc
+++ b/content/test/test_aggregation_service_impl.cc
@@ -46,16 +46,6 @@
   }
 }
 
-blink::mojom::AggregationServiceMode ConvertToAggregationMode(
-    TestAggregationService::AggregationMode aggregation_mode) {
-  switch (aggregation_mode) {
-    case TestAggregationService::AggregationMode::kTeeBased:
-      return blink::mojom::AggregationServiceMode::kTeeBased;
-    case TestAggregationService::AggregationMode::kExperimentalPoplar:
-      return blink::mojom::AggregationServiceMode::kExperimentalPoplar;
-  }
-}
-
 void HandleAggregatableReportCallback(
     base::OnceCallback<void(base::Value::Dict)> callback,
     AggregatableReportRequest,
@@ -132,7 +122,6 @@
       {blink::mojom::AggregatableReportHistogramContribution(
           /*bucket=*/request.bucket, /*value=*/request.value,
           /*filtering_id=*/std::nullopt)},
-      ConvertToAggregationMode(request.aggregation_mode),
       /*aggregation_coordinator_origin=*/std::nullopt,
       /*max_contributions_allowed=*/20u,
       // TODO(crbug.com/330744610): Allow setting.
@@ -150,7 +139,7 @@
 
   std::optional<AggregatableReportRequest> report_request =
       AggregatableReportRequest::CreateForTesting(
-          std::move(request.processing_urls), std::move(payload_contents),
+          std::move(request.processing_url), std::move(payload_contents),
           std::move(shared_info));
   if (!report_request.has_value()) {
     std::move(callback).Run(base::Value::Dict());
diff --git a/content/test/test_select_url_fenced_frame_config_observer_impl.cc b/content/test/test_select_url_fenced_frame_config_observer_impl.cc
index 5a7750c..f6159d19 100644
--- a/content/test/test_select_url_fenced_frame_config_observer_impl.cc
+++ b/content/test/test_select_url_fenced_frame_config_observer_impl.cc
@@ -17,7 +17,7 @@
     ~TestSelectURLFencedFrameConfigObserverImpl() = default;
 
 GlobalRenderFrameHostId
-TestSelectURLFencedFrameConfigObserverImpl::AssociatedMainFrameId() const {
+TestSelectURLFencedFrameConfigObserverImpl::AssociatedFrameHostId() const {
   return GlobalRenderFrameHostId();
 }
 
diff --git a/content/test/test_select_url_fenced_frame_config_observer_impl.h b/content/test/test_select_url_fenced_frame_config_observer_impl.h
index 2537358..aa1737f 100644
--- a/content/test/test_select_url_fenced_frame_config_observer_impl.h
+++ b/content/test/test_select_url_fenced_frame_config_observer_impl.h
@@ -20,7 +20,7 @@
   TestSelectURLFencedFrameConfigObserverImpl();
   ~TestSelectURLFencedFrameConfigObserverImpl() override;
 
-  GlobalRenderFrameHostId AssociatedMainFrameId() const override;
+  GlobalRenderFrameHostId AssociatedFrameHostId() const override;
   bool ShouldReceiveAllReports() const override;
 
   void OnSharedStorageAccessed(base::Time access_time,
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc
index e7cec3c..19ada6e 100644
--- a/content/utility/utility_main.cc
+++ b/content/utility/utility_main.cc
@@ -141,7 +141,7 @@
 }
 
 bool ShouldUseAmdGpuPolicy(sandbox::mojom::Sandbox sandbox_type) {
-#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION)
   const bool obtain_gpu_info =
       sandbox_type == sandbox::mojom::Sandbox::kHardwareVideoDecoding ||
       sandbox_type == sandbox::mojom::Sandbox::kHardwareVideoEncoding;
@@ -316,8 +316,7 @@
 #endif
       break;
 #endif  // BUILDFLAG(IS_LINUX)
-#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \
-    (BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))
+#if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION)
     case sandbox::mojom::Sandbox::kHardwareVideoDecoding:
       pre_sandbox_hook =
           base::BindOnce(&media::HardwareVideoDecodingPreSandboxHook);
@@ -326,8 +325,7 @@
       pre_sandbox_hook =
           base::BindOnce(&media::HardwareVideoEncodingPreSandboxHook);
       break;
-#endif  // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) &&
-        // (BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))
+#endif
 #if BUILDFLAG(IS_CHROMEOS)
     case sandbox::mojom::Sandbox::kIme:
       pre_sandbox_hook = base::BindOnce(&ash::ime::ImePreSandboxHook);
diff --git a/crypto/unexportable_key_mac.mm b/crypto/unexportable_key_mac.mm
index 744243a..750ce17b 100644
--- a/crypto/unexportable_key_mac.mm
+++ b/crypto/unexportable_key_mac.mm
@@ -29,13 +29,16 @@
 #include "base/containers/span.h"
 #include "base/logging.h"
 #include "base/memory/scoped_policy.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "crypto/apple_keychain_util.h"
 #include "crypto/apple_keychain_v2.h"
 #include "crypto/signature_verifier.h"
 #include "crypto/unexportable_key_mac.h"
+#include "crypto/unexportable_key_metrics.h"
 #include "third_party/boringssl/src/include/openssl/bn.h"
 #include "third_party/boringssl/src/include/openssl/bytestring.h"
 #include "third_party/boringssl/src/include/openssl/ec.h"
@@ -94,6 +97,27 @@
   return ret;
 }
 
+// Logs `status` to an error histogram capturing that `operation` failed for a
+// key backed by Secure Enclave.
+void LogKeychainOperationError(TPMOperation operation, OSStatus status) {
+  static constexpr char kKeyErrorStatusHistogramFormat[] =
+      "Crypto.SecureEnclaveOperation.Mac.%s.Error";
+  base::UmaHistogramSparse(
+      base::StringPrintf(kKeyErrorStatusHistogramFormat,
+                         OperationToString(operation).c_str()),
+      status);
+}
+
+// Logs `error` to an error histogram capturing that `operation` failed for a
+// key backed by Secure Enclave. Defaults to `errSecCoreFoundationUnknown` if
+// `error` is missing.
+void LogKeychainOperationError(
+    TPMOperation operation,
+    base::apple::ScopedCFTypeRef<CFErrorRef>& error) {
+  LogKeychainOperationError(operation, error ? CFErrorGetCode(error.get())
+                                             : errSecCoreFoundationUnknown);
+}
+
 // UnexportableSigningKeyMac is an implementation of the UnexportableSigningKey
 // interface on top of Apple's Secure Enclave.
 class UnexportableSigningKeyMac : public UnexportableSigningKey {
@@ -149,6 +173,7 @@
             error.InitializeInto()));
     if (!signature) {
       LOG(ERROR) << "Error signing with key: " << error.get();
+      LogKeychainOperationError(TPMOperation::kMessageSigning, error);
       return std::nullopt;
     }
     return CFDataToVec(signature.get());
@@ -271,6 +296,7 @@
           NSToCFPtrCast(attributes), error.InitializeInto()));
   if (!private_key) {
     LOG(ERROR) << "Could not create private key: " << error.get();
+    LogKeychainOperationError(TPMOperation::kNewKeyCreation, error);
     return nullptr;
   }
   base::apple::ScopedCFTypeRef<CFDictionaryRef> key_metadata =
@@ -304,11 +330,13 @@
   if (lacontext) {
     query[CFToNSPtrCast(kSecUseAuthenticationContext)] = lacontext;
   }
-  AppleKeychainV2::GetInstance().ItemCopyMatching(NSToCFPtrCast(query),
-                                                  key_data.InitializeInto());
+  OSStatus status = AppleKeychainV2::GetInstance().ItemCopyMatching(
+      NSToCFPtrCast(query), key_data.InitializeInto());
   CFDictionaryRef key_attributes =
       base::apple::CFCast<CFDictionaryRef>(key_data.get());
   if (!key_attributes) {
+    LOG(ERROR) << "Could not load private key from wrapped: " << status;
+    LogKeychainOperationError(TPMOperation::kWrappedKeyExport, status);
     return nullptr;
   }
   base::apple::ScopedCFTypeRef<SecKeyRef> key(
diff --git a/extensions/browser/api/sockets_tcp_server/BUILD.gn b/extensions/browser/api/sockets_tcp_server/BUILD.gn
index 9d93f72..89e8e272 100644
--- a/extensions/browser/api/sockets_tcp_server/BUILD.gn
+++ b/extensions/browser/api/sockets_tcp_server/BUILD.gn
@@ -17,14 +17,20 @@
 
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
-  deps = [
+  public_deps = [
+    "//base",
     "//content/public/browser",
-    "//content/public/common",
+    "//extensions/browser:browser_sources",
     "//extensions/browser/api/socket",
     "//extensions/browser/api/sockets_tcp",
     "//extensions/common",
     "//extensions/common/api",
+    "//mojo/public/cpp/bindings",
+    "//services/network/public/mojom",
   ]
 
-  public_deps = [ "//extensions/browser:browser_sources" ]
+  deps = [
+    "//content/public/common",
+    "//net",
+  ]
 }
diff --git a/extensions/browser/guest_view/app_view/app_view_guest.cc b/extensions/browser/guest_view/app_view/app_view_guest.cc
index 8d6fc67..0f2c215 100644
--- a/extensions/browser/guest_view/app_view/app_view_guest.cc
+++ b/extensions/browser/guest_view/app_view/app_view_guest.cc
@@ -150,6 +150,7 @@
 }
 
 bool AppViewGuest::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/extensions/browser/guest_view/app_view/app_view_guest.h b/extensions/browser/guest_view/app_view/app_view_guest.h
index 775cfbf..7695578 100644
--- a/extensions/browser/guest_view/app_view/app_view_guest.h
+++ b/extensions/browser/guest_view/app_view/app_view_guest.h
@@ -76,6 +76,7 @@
   bool HandleContextMenu(content::RenderFrameHost& render_frame_host,
                          const content::ContextMenuParams& params) final;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
index 2fca443..5bd9d59 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
@@ -259,6 +259,7 @@
 }
 
 bool ExtensionOptionsGuest::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.h b/extensions/browser/guest_view/extension_options/extension_options_guest.h
index e39031af..56d86e3 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.h
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.h
@@ -70,6 +70,7 @@
                          const content::ContextMenuParams& params) final;
   bool ShouldResumeRequestsForCreatedWindow() override;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
index 60de0d7..0bba5f4 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -449,6 +449,7 @@
 }
 
 bool MimeHandlerViewGuest::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
index 2dcf51f3..7eeffdf 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
@@ -183,6 +183,7 @@
       const content::WebContents* web_contents) override;
   bool ShouldResumeRequestsForCreatedWindow() override;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/fuchsia_web/webengine/browser/frame_impl.cc b/fuchsia_web/webengine/browser/frame_impl.cc
index c10903a8..2c9ef63 100644
--- a/fuchsia_web/webengine/browser/frame_impl.cc
+++ b/fuchsia_web/webengine/browser/frame_impl.cc
@@ -573,6 +573,7 @@
 }
 
 bool FrameImpl::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/fuchsia_web/webengine/browser/frame_impl.h b/fuchsia_web/webengine/browser/frame_impl.h
index 1012a90..756d419 100644
--- a/fuchsia_web/webengine/browser/frame_impl.h
+++ b/fuchsia_web/webengine/browser/frame_impl.h
@@ -304,6 +304,7 @@
                               int32_t line_no,
                               const std::u16string& source_id) override;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index 7ca1e83..b8f48c8 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -203,6 +203,7 @@
   }
 
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/infra/inclusive_language_presubmit_exempt_dirs.txt b/infra/inclusive_language_presubmit_exempt_dirs.txt
index fdaecbd..5f73e2a 100644
--- a/infra/inclusive_language_presubmit_exempt_dirs.txt
+++ b/infra/inclusive_language_presubmit_exempt_dirs.txt
@@ -481,7 +481,6 @@
 third_party/crashpad/crashpad/third_party/ninja 1 1
 third_party/crashpad/crashpad/util/misc 1 1
 third_party/dav1d 2 2
-third_party/distributed_point_functions/code 2 1
 third_party/expat 2 2
 third_party/fdlibm 1 1
 third_party/fusejs/dist 3 1
diff --git a/internal b/internal
index 2feff4b..2331975 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 2feff4bc46c95c907d7d0ab9836fa5d735eb7c96
+Subproject commit 23319755d0789a1e63cc4c1dfb6f38403c9bfa63
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 0acbd3a..ea1d9428 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -555,8 +555,8 @@
 
 - (void)startUpBrowserBackgroundInitialization {
   NSBundle* baseBundle = base::apple::OuterBundle();
-  base::apple::SetBaseBundleID(
-      base::SysNSStringToUTF8([baseBundle bundleIdentifier]).c_str());
+  base::apple::SetBaseBundleIDOverride(
+      base::SysNSStringToUTF8(baseBundle.bundleIdentifier));
 
   // Register default values for experimental settings (Application Preferences)
   // and set the "Version" key in the UserDefaults.
diff --git a/ios/chrome/app/resources/ios_chrome_repack.gni b/ios/chrome/app/resources/ios_chrome_repack.gni
index 135f0b3..ecebfb4 100644
--- a/ios/chrome/app/resources/ios_chrome_repack.gni
+++ b/ios/chrome/app/resources/ios_chrome_repack.gni
@@ -101,6 +101,7 @@
         "${root_gen_dir}/components/components_resources_${_scale}_percent.pak",
         "${root_gen_dir}/ios/chrome/ios_theme_resources_${_scale}_percent.pak",
         "${root_gen_dir}/ui/resources/ui_resources_${_scale}_percent.pak",
+        "${root_gen_dir}/third_party/search_engines_data/search_engines_resources_${_scale}_percent.pak",
       ]
       foreach(_source_pattern, ios_scalable_pack_extra_source_patterns) {
         _source_pattern = string_replace(_source_pattern, "%scale%", _scale)
@@ -114,6 +115,7 @@
                "//components/resources",
                "//ios/chrome/app/theme",
                "//ui/resources",
+               "//third_party/search_engines_data:resources",
              ] + ios_scalable_pack_extra_deps
 
       output = "$target_gen_dir/chrome_${_scale}_percent.pak"
diff --git a/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h b/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h
index d9aff966..6fe535b 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h
+++ b/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h
@@ -54,6 +54,12 @@
 
 // Sets the states for the progress indicator.
 - (void)setProgressState:(ProgressIndicatorState)progressState;
+
+// The accessibility label for the confirmation checkmark.
+// This label is applied and announced by VoiceOver when `progressState` is
+// set to `ProgressIndicatorStateSuccess`.
+@property(nonatomic, copy) NSString* confirmationAccessibilityLabel;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_ALERT_VIEW_UI_BUNDLED_ALERT_CONSUMER_H_
diff --git a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h
index f8a1cea..d6d28491 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h
+++ b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h
@@ -23,6 +23,11 @@
 // Set this property to change between spinner, checkmark, or none.
 @property(nonatomic, assign) ProgressIndicatorState progressState;
 
+// The accessibility label for the confirmation checkmark.
+// This label is applied and announced by VoiceOver when `progressState` is
+// set to `ProgressIndicatorStateSuccess`.
+@property(nonatomic, copy) NSString* confirmationAccessibilityLabel;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_ALERT_VIEW_UI_BUNDLED_ALERT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm
index 0a42581..021f212 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm
+++ b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm
@@ -603,6 +603,11 @@
     _spinner.hidden = YES;
     [_spinner stopAnimating];
     _checkmark.hidden = NO;
+    _checkmark.accessibilityLabel = self.confirmationAccessibilityLabel;
+    _checkmark.isAccessibilityElement =
+        (self.confirmationAccessibilityLabel.length > 0);
+    UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
+                                    _checkmark);
   } else {
     _spinner.hidden = YES;
     [_spinner stopAnimating];
diff --git a/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.h b/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.h
index cb15b4f8..52da58fc 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.h
+++ b/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.h
@@ -18,6 +18,7 @@
 @property(nonatomic, copy) NSString* alertAccessibilityIdentifier;
 @property(nonatomic, assign) BOOL shouldShowActivityIndicator;
 @property(nonatomic, assign) BOOL actionButtonsAreInitiallyDisabled;
+@property(nonatomic, copy) NSString* confirmationAccessibilityLabel;
 
 @end
 
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/promo/BUILD.gn b/ios/chrome/browser/authentication/ui_bundled/signin/promo/BUILD.gn
index 2b51f2e..febe9c8 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/promo/BUILD.gn
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/promo/BUILD.gn
@@ -11,8 +11,11 @@
   ]
   deps = [
     "//components/feature_engagement/public",
+    "//components/signin/public/identity_manager/objc",
+    "//components/sync/service",
     "//components/version_info",
     "//ios/chrome/app/profile",
+    "//ios/chrome/browser/authentication/ui_bundled/history_sync",
     "//ios/chrome/browser/authentication/ui_bundled/signin:signin_headers",
     "//ios/chrome/browser/feature_engagement/model",
     "//ios/chrome/browser/promos_manager/model",
@@ -21,6 +24,7 @@
     "//ios/chrome/browser/promos_manager/model:types",
     "//ios/chrome/browser/promos_manager/ui_bundled:promos",
     "//ios/chrome/browser/shared/coordinator/scene:observing_scene_agent",
+    "//ios/chrome/browser/signin/model:authentication_service",
   ]
 }
 
@@ -31,6 +35,9 @@
   deps = [
     ":promo",
     "//base",
+    "//components/signin/public/base",
+    "//components/sync:test_support",
+    "//components/sync/service",
     "//ios/chrome/app:app_internal",
     "//ios/chrome/app/profile",
     "//ios/chrome/app/profile:test_utils",
@@ -47,10 +54,12 @@
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/model/profile/test",
     "//ios/chrome/browser/signin/model",
+    "//ios/chrome/browser/signin/model:authentication_service",
     "//ios/chrome/browser/signin/model:authentication_service_factory",
     "//ios/chrome/browser/signin/model:fake_system_identity",
     "//ios/chrome/browser/signin/model:fake_system_identity_manager",
     "//ios/chrome/browser/signin/model:test_support",
+    "//ios/chrome/browser/sync/model",
     "//ios/chrome/test:test_support",
     "//ios/web/public/test",
     "//testing/gtest",
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.h b/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.h
index aba9249..649f1f57 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.h
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.h
@@ -9,14 +9,27 @@
 
 #import "ios/chrome/browser/shared/coordinator/scene/observing_scene_state_agent.h"
 
+namespace signin {
+class IdentityManager;
+}
+
+namespace syncer {
+class SyncService;
+}
+
 class PromosManager;
+class AuthenticationService;
+class PrefService;
 
 // A scene agent that registers the Signin fullscreen promo in the promo
 // manager.
 @interface SigninFullscreenPromoSceneAgent : ObservingSceneAgent
 
-- (instancetype)initWithPromosManager:(PromosManager*)promosManager;
-
+- (instancetype)initWithPromosManager:(PromosManager*)promosManager
+                          authService:(AuthenticationService*)authService
+                      identityManager:(signin::IdentityManager*)identityManager
+                          syncService:(syncer::SyncService*)syncService
+                          prefService:(PrefService*)prefService;
 @end
 
 #endif  // IOS_CHROME_BROWSER_AUTHENTICATION_UI_BUNDLED_SIGNIN_PROMO_SIGNIN_FULLSCREEN_PROMO_SCENE_AGENT_H_
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.mm b/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.mm
index 1d49b6f..213f021 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.mm
@@ -5,10 +5,16 @@
 #import "ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.h"
 
 #import "base/memory/raw_ptr.h"
+#import "base/notreached.h"
+#import "components/prefs/pref_service.h"
+#import "components/signin/public/identity_manager/identity_manager.h"
+#import "components/signin/public/identity_manager/objc/identity_manager_observer_bridge.h"
+#import "components/sync/service/sync_service.h"
 #import "components/version_info/version_info.h"
 #import "ios/chrome/app/profile/profile_init_stage.h"
 #import "ios/chrome/app/profile/profile_state.h"
 #import "ios/chrome/app/profile/profile_state_observer.h"
+#import "ios/chrome/browser/authentication/ui_bundled/history_sync/history_sync_utils.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.h"
 #import "ios/chrome/browser/promos_manager/model/constants.h"
 #import "ios/chrome/browser/promos_manager/model/features.h"
@@ -17,18 +23,45 @@
 #import "ios/chrome/browser/shared/model/browser/browser_provider.h"
 #import "ios/chrome/browser/shared/model/browser/browser_provider_interface.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+#import "ios/chrome/browser/signin/model/authentication_service.h"
 
-@interface SigninFullscreenPromoSceneAgent () <ProfileStateObserver>
+@interface SigninFullscreenPromoSceneAgent () <
+    ProfileStateObserver,
+    IdentityManagerObserverBridgeDelegate>
 @end
 
 @implementation SigninFullscreenPromoSceneAgent {
+  // The PromosManager used by the scene agent to manage promo display.
   raw_ptr<PromosManager> _promosManager;
+
+  // The AuthenticationService used by the mediator to monitor sign-in status.
+  raw_ptr<AuthenticationService> _authService;
+
+  // Bridge to observe changes in the identity manager.
+  std::unique_ptr<signin::IdentityManagerObserverBridge>
+      _identityManagerObserver;
+
+  // The SyncService used to check if the history sync can be skipped.
+  raw_ptr<syncer::SyncService> _syncService;
+
+  // The PrefService used to check if the history sync can be skipped.
+  raw_ptr<PrefService> _prefService;
 }
 
-- (instancetype)initWithPromosManager:(PromosManager*)promosManager {
+- (instancetype)initWithPromosManager:(PromosManager*)promosManager
+                          authService:(AuthenticationService*)authService
+                      identityManager:(signin::IdentityManager*)identityManager
+                          syncService:(syncer::SyncService*)syncService
+                          prefService:(PrefService*)prefService {
   self = [super init];
   if (self) {
     _promosManager = promosManager;
+    _authService = authService;
+    _identityManagerObserver =
+        std::make_unique<signin::IdentityManagerObserverBridge>(identityManager,
+                                                                self);
+    _syncService = syncService;
+    _prefService = prefService;
   }
   return self;
 }
@@ -56,6 +89,17 @@
   [self handlePromoRegistration];
 }
 
+- (void)sceneStateDidDisableUI:(SceneState*)sceneState {
+  _identityManagerObserver.reset();
+  _identityManagerObserver = nullptr;
+  _promosManager = nullptr;
+  _authService = nullptr;
+  _syncService = nullptr;
+  _prefService = nullptr;
+  [self.sceneState.profileState removeObserver:self];
+  [self.sceneState removeObserver:self];
+}
+
 #pragma mark - Private
 
 // Registers or deregisters the sign-in fullscreen promo if the profile
@@ -86,4 +130,24 @@
   _promosManager->DeregisterPromo(promos_manager::Promo::SigninFullscreen);
 }
 
+#pragma mark - IdentityManagerObserverBridgeDelegate
+
+- (void)onPrimaryAccountChanged:
+    (const signin::PrimaryAccountChangeEvent&)event {
+  if (_authService->HasPrimaryIdentity(signin::ConsentLevel::kSignin)) {
+    history_sync::HistorySyncSkipReason skipReason =
+        history_sync::GetSkipReason(_syncService, _authService, _prefService,
+                                    /*isOptional=*/YES);
+    if (skipReason != history_sync::HistorySyncSkipReason::kNone) {
+      // Deregister the promo if the user signed in and the history sync can be
+      // skipped.
+      _promosManager->DeregisterPromo(promos_manager::Promo::SigninFullscreen);
+    }
+  }
+}
+
+- (void)onIdentityManagerShutdown:(signin::IdentityManager*)identityManager {
+  NOTREACHED(base::NotFatalUntil::M142);
+}
+
 @end
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent_unittest.mm b/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent_unittest.mm
index abd0d05e..64f30b3 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent_unittest.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent_unittest.mm
@@ -5,6 +5,9 @@
 #import "ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.h"
 
 #import "base/memory/raw_ptr.h"
+#import "components/signin/public/base/signin_metrics.h"
+#import "components/sync/service/sync_service.h"
+#import "components/sync/test/test_sync_service.h"
 #import "ios/chrome/app/profile/profile_state.h"
 #import "ios/chrome/app/profile/profile_state_test_utils.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.h"
@@ -17,12 +20,14 @@
 #import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
 #import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
+#import "ios/chrome/browser/signin/model/authentication_service.h"
 #import "ios/chrome/browser/signin/model/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/model/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/signin/model/fake_authentication_service_delegate.h"
 #import "ios/chrome/browser/signin/model/fake_system_identity.h"
 #import "ios/chrome/browser/signin/model/fake_system_identity_manager.h"
 #import "ios/chrome/browser/signin/model/identity_manager_factory.h"
+#import "ios/chrome/browser/sync/model/sync_service_factory.h"
 #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/platform_test.h"
@@ -50,9 +55,16 @@
         browser_.get();
     OCMStub([scene_state_ browserProviderInterface])
         .andReturn(stub_browser_interface_provider_);
+    authentication_service_ =
+        AuthenticationServiceFactory::GetForProfile(profile_.get());
+    identity_manager_ = IdentityManagerFactory::GetForProfile(profile_.get());
     promos_manager_ = std::make_unique<MockPromosManager>();
     agent_ = [[SigninFullscreenPromoSceneAgent alloc]
-        initWithPromosManager:promos_manager_.get()];
+        initWithPromosManager:promos_manager_.get()
+                  authService:authentication_service_
+              identityManager:identity_manager_
+                  syncService:&sync_service_
+                  prefService:profile_->GetPrefs()];
 
     agent_.sceneState = scene_state_;
 
@@ -60,9 +72,10 @@
     profile_state_.profile = profile_.get();
     scene_state_.profileState = profile_state_;
 
-    identity_manager_ = IdentityManagerFactory::GetForProfile(profile_.get());
     account_manager_service_ =
         ChromeAccountManagerServiceFactory::GetForProfile(profile_.get());
+
+    scene_state_.UIEnabled = YES;
   }
 
   void TearDown() override {
@@ -71,6 +84,7 @@
     [standardDefaults removeObjectForKey:kLastShownAccountGaiaIdVersionKey];
     [standardDefaults removeObjectForKey:kSigninPromoViewDisplayCountKey];
     [standardDefaults synchronize];
+    scene_state_.UIEnabled = NO;
   }
 
   ProfileState* CreateMockProfileState(ProfileInitStage init_stage) {
@@ -84,9 +98,11 @@
   IOSChromeScopedTestingLocalState scoped_testing_local_state_;
   SigninFullscreenPromoSceneAgent* agent_;
   web::WebTaskEnvironment task_environment_;
+  syncer::TestSyncService sync_service_;
   StubBrowserProviderInterface* stub_browser_interface_provider_;
   raw_ptr<signin::IdentityManager> identity_manager_;
   raw_ptr<ChromeAccountManagerService> account_manager_service_;
+  raw_ptr<AuthenticationService> authentication_service_;
   std::unique_ptr<TestProfileIOS> profile_;
   std::unique_ptr<Browser> browser_;
   ProfileState* profile_state_;
@@ -123,3 +139,77 @@
       .Times(0);
   scene_state_.activationLevel = SceneActivationLevelForegroundActive;
 }
+
+// Tests that when a promo was previously registered, it is deregistered when
+// user is signed in and history sync is opted in.
+TEST_F(SigninFullscreenPromoSceneAgentTest,
+       TestPromoDeregistrationWhenSignedInWithHistorySync) {
+  // Register the promo.
+  const base::Version version_1_0("1.0");
+  FakeSystemIdentity* fake_identity1 = [FakeSystemIdentity fakeIdentity1];
+  FakeSystemIdentityManager::FromSystemIdentityManager(
+      GetApplicationContext()->GetSystemIdentityManager())
+      ->AddIdentity(fake_identity1);
+  signin::RecordUpgradePromoSigninStarted(
+      identity_manager_, account_manager_service_, version_1_0);
+  EXPECT_CALL(*promos_manager_.get(),
+              RegisterPromoForContinuousDisplay(
+                  promos_manager::Promo::SigninFullscreen))
+      .Times(1);
+  EXPECT_CALL(*promos_manager_.get(),
+              DeregisterPromo(promos_manager::Promo::SigninFullscreen))
+      .Times(0);
+  scene_state_.activationLevel = SceneActivationLevelForegroundActive;
+
+  // Sign in and enable history sync.
+  EXPECT_CALL(*promos_manager_.get(),
+              RegisterPromoForContinuousDisplay(
+                  promos_manager::Promo::SigninFullscreen))
+      .Times(0);
+  EXPECT_CALL(*promos_manager_.get(),
+              DeregisterPromo(promos_manager::Promo::SigninFullscreen))
+      .Times(1);
+  sync_service_.GetUserSettings()->SetSelectedType(
+      syncer::UserSelectableType::kHistory, YES);
+  sync_service_.GetUserSettings()->SetSelectedType(
+      syncer::UserSelectableType::kTabs, YES);
+  authentication_service_->SignIn(fake_identity1,
+                                  signin_metrics::AccessPoint::kUnknown);
+  EXPECT_TRUE(authentication_service_->HasPrimaryIdentity(
+      signin::ConsentLevel::kSignin));
+}
+
+// Tests that when a promo was previously registered, it is still registered
+// when user is signed in without history sync.
+TEST_F(SigninFullscreenPromoSceneAgentTest,
+       TestPromoRegistrationWhenSignedInWithoutHistorySync) {
+  // Register the promo.
+  const base::Version version_1_0("1.0");
+  FakeSystemIdentity* fake_identity1 = [FakeSystemIdentity fakeIdentity1];
+  FakeSystemIdentityManager::FromSystemIdentityManager(
+      GetApplicationContext()->GetSystemIdentityManager())
+      ->AddIdentity(fake_identity1);
+  signin::RecordUpgradePromoSigninStarted(
+      identity_manager_, account_manager_service_, version_1_0);
+  EXPECT_CALL(*promos_manager_.get(),
+              RegisterPromoForContinuousDisplay(
+                  promos_manager::Promo::SigninFullscreen))
+      .Times(1);
+  EXPECT_CALL(*promos_manager_.get(),
+              DeregisterPromo(promos_manager::Promo::SigninFullscreen))
+      .Times(0);
+  scene_state_.activationLevel = SceneActivationLevelForegroundActive;
+
+  // Sign in without history sync.
+  EXPECT_CALL(*promos_manager_.get(),
+              RegisterPromoForContinuousDisplay(
+                  promos_manager::Promo::SigninFullscreen))
+      .Times(0);
+  EXPECT_CALL(*promos_manager_.get(),
+              DeregisterPromo(promos_manager::Promo::SigninFullscreen))
+      .Times(1);
+  authentication_service_->SignIn(fake_identity1,
+                                  signin_metrics::AccessPoint::kUnknown);
+  EXPECT_TRUE(authentication_service_->HasPrimaryIdentity(
+      signin::ConsentLevel::kSignin));
+}
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/BUILD.gn b/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/BUILD.gn
index a43601b..be5fb755 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/BUILD.gn
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/BUILD.gn
@@ -35,6 +35,7 @@
   deps = [
     ":two_screens_signin",
     "//base/test:test_support",
+    "//components/sync:test_support",
     "//components/sync/base:features",
     "//ios/chrome/browser/authentication/ui_bundled:continuation_test",
     "//ios/chrome/browser/authentication/ui_bundled/fullscreen_signin_screen/ui",
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator.mm b/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator.mm
index 419f035..1d895900 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator.mm
@@ -53,6 +53,9 @@
   UpgradeSigninLogger* _upgradeSigninLogger;
 
   ChangeProfileContinuationProvider _continuationProvider;
+
+  // The current screen type.
+  ScreenType _currentScreenType;
 }
 
 - (instancetype)
@@ -101,16 +104,14 @@
                                                     toolbarClass:nil];
   _navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
 
-  // Check if there is a valid next screen to present. This handles the case
-  // where the flow is already completed (kStepsCompleted) or if other
-  // conditions prevent showing the next screen. Crucially, if
-  // `presentScreenIfNeeded` returns NO (e.g., because the flow completed and it
-  // called `finishPresentingScreens`), `_navigationController` might have been
-  // set to nil. Returning here prevents attempting to present a nil navigation
-  // controller.
-  if (![self presentScreenIfNeeded:[_screenProvider nextScreenType]]) {
+  [self presentScreenIfNeeded:[_screenProvider nextScreenType]];
+
+  // Check if the flow is already completed (kStepsCompleted) to prevent
+  // presenting a nil navigation controller.
+  if (_currentScreenType == kStepsCompleted) {
     return;
   }
+
   // Set the presentation delegate after the child coordinator creation to
   // override the default implementation.
   _navigationController.presentationController.delegate = self;
@@ -161,16 +162,16 @@
 }
 
 // Presents the screen of certain `type`.
-- (BOOL)presentScreenIfNeeded:(ScreenType)type {
+- (void)presentScreenIfNeeded:(ScreenType)type {
+  _currentScreenType = type;
   // If there are no screens remaining, call delegate to stop presenting
   // screens.
   if (type == kStepsCompleted) {
     [self finishPresentingScreens];
-    return NO;
+    return;
   }
   _childCoordinator = [self createChildCoordinatorWithScreenType:type];
   [_childCoordinator start];
-  return YES;
 }
 
 // Creates a screen coordinator according to `type`.
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator_unittest.mm b/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator_unittest.mm
index b1229f54..04b869bf 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator_unittest.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin/two_screens_signin_coordinator_unittest.mm
@@ -11,6 +11,7 @@
 #import "base/test/ios/wait_util.h"
 #import "base/test/metrics/histogram_tester.h"
 #import "base/test/metrics/user_action_tester.h"
+#import "components/sync/test/test_sync_service.h"
 #import "ios/chrome/browser/authentication/ui_bundled/authentication_test_util.h"
 #import "ios/chrome/browser/authentication/ui_bundled/fullscreen_signin_screen/ui/fullscreen_signin_screen_view_controller.h"
 #import "ios/chrome/browser/authentication/ui_bundled/history_sync/history_sync_view_controller.h"
@@ -39,8 +40,12 @@
         AuthenticationServiceFactory::GetInstance(),
         AuthenticationServiceFactory::GetFactoryWithDelegate(
             std::make_unique<FakeAuthenticationServiceDelegate>()));
-    builder.AddTestingFactory(SyncServiceFactory::GetInstance(),
-                              base::BindRepeating(&CreateMockSyncService));
+    builder.AddTestingFactory(
+        SyncServiceFactory::GetInstance(),
+        base::BindRepeating(
+            [](web::BrowserState*) -> std::unique_ptr<KeyedService> {
+              return std::make_unique<syncer::TestSyncService>();
+            }));
     profile_ = std::move(builder).Build();
     browser_ = std::make_unique<TestBrowser>(profile_.get());
 
@@ -121,10 +126,16 @@
   }
 
   // Signs in a fake identity.
-  void SigninFakeIdentity() {
+  void SigninFakeIdentity(bool has_history_sync_opt_in) {
     AuthenticationService* auth_service =
         AuthenticationServiceFactory::GetForProfile(profile_.get());
     auth_service->SignIn(fake_identity_, signin_metrics::AccessPoint::kUnknown);
+    syncer::SyncService* sync_service =
+        SyncServiceFactory::GetForProfile(profile_.get());
+    sync_service->GetUserSettings()->SetSelectedType(
+        syncer::UserSelectableType::kHistory, has_history_sync_opt_in);
+    sync_service->GetUserSettings()->SetSelectedType(
+        syncer::UserSelectableType::kTabs, has_history_sync_opt_in);
   }
 
   // Advances the coordinator to the next screen.
@@ -156,7 +167,7 @@
   EXPECT_NE(PresentedViewController(), nil);
   EXPECT_TRUE([TopViewController()
       isKindOfClass:[FullscreenSigninScreenViewController class]]);
-  SigninFakeIdentity();
+  SigninFakeIdentity(/*has_history_sync_opt_in=*/false);
 
   NextScreen();
 
@@ -177,6 +188,35 @@
       1);
 }
 
+// Tests that the screens are not presented when the user has already signed in
+// and history sync opt-in.
+TEST_F(TwoScreensSigninCoordinatorTest,
+       ScreensNotPresentedWhenSignedInHistorySyncOptIn) {
+  base::HistogramTester histogram_tester;
+  SigninFakeIdentity(/*has_history_sync_opt_in=*/true);
+
+  StartTwoScreensSigninCoordinator(SigninCoordinatorResultSuccess,
+                                   fake_identity_);
+  // Expect the signin screen to not be presented.
+  EXPECT_EQ(PresentedViewController(), nil);
+  EXPECT_FALSE([TopViewController()
+      isKindOfClass:[FullscreenSigninScreenViewController class]]);
+  // Expect the history sync screen to not be presented.
+  EXPECT_FALSE(
+      [TopViewController() isKindOfClass:[HistorySyncViewController class]]);
+
+  // Expect completion block to be run synchronously and be finished without
+  // calling -stop. Since the user has already signed in and history sync
+  // opt-in, the coordinator will call the completion block.
+  EXPECT_TRUE(completion_block_done_);
+  ExpectNoUpgradePromoHistogram(&histogram_tester);
+  histogram_tester.ExpectUniqueSample<signin_metrics::AccessPoint>(
+      "Signin.SignIn.Started", signin_metrics::AccessPoint::kSettings, 0);
+  histogram_tester.ExpectUniqueSample<signin_metrics::AccessPoint>(
+      "Signin.SigninStartedAccessPoint", signin_metrics::AccessPoint::kSettings,
+      0);
+}
+
 // Tests that stopping the coordinator before it is done will interrupt it.
 TEST_F(TwoScreensSigninCoordinatorTest, StopWillInterrupt) {
   base::HistogramTester histogram_tester;
diff --git a/ios/chrome/browser/autofill/model/bottom_sheet/bottom_sheet.ts b/ios/chrome/browser/autofill/model/bottom_sheet/bottom_sheet.ts
index 0a35e1d..954eacd 100644
--- a/ios/chrome/browser/autofill/model/bottom_sheet/bottom_sheet.ts
+++ b/ios/chrome/browser/autofill/model/bottom_sheet/bottom_sheet.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 /**
@@ -70,7 +70,7 @@
   // the conversion to TypeScript is done.
 
   const msg = {
-    'frameID': gCrWebLegacy.message.getFrameId(),
+    'frameID': gCrWeb.getFrameId(),
     'formName': gCrWebLegacy.form.getFormIdentifier(form),
     'formRendererID': gCrWebLegacy.fill.getUniqueID(form),
     'fieldIdentifier': gCrWebLegacy.form.getFieldIdentifier(field),
diff --git a/ios/chrome/browser/autofill/ui_bundled/address_editor/autofill_profile_edit_table_view_controller_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/address_editor/autofill_profile_edit_table_view_controller_unittest.mm
index 416ae67..24c9a56 100644
--- a/ios/chrome/browser/autofill/ui_bundled/address_editor/autofill_profile_edit_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/address_editor/autofill_profile_edit_table_view_controller_unittest.mm
@@ -232,7 +232,9 @@
 }  // namespace
 
 // Tests the items present in the view.
-TEST_P(AutofillProfileEditTableViewControllerTest, TestItems) {
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
+TEST_P(AutofillProfileEditTableViewControllerTest, DISABLED_TestItems) {
   auto test_case = GetParam();
   bool multiple_sections = (test_case.is_settings && test_case.account_profile);
   EXPECT_EQ(NumberOfSections(), multiple_sections ? 2 : 1);
@@ -295,7 +297,9 @@
 }
 
 // Test the contents of the view when the value requirements fail.
-TEST_P(AutofillProfileEditTableViewControllerTest, TestRequirements) {
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
+TEST_P(AutofillProfileEditTableViewControllerTest, DISABLED_TestRequirements) {
   TableViewTextEditItem* city_item =
       static_cast<TableViewTextEditItem*>(GetTableViewItem(0, 4));
   // Remove the city field value.
@@ -353,8 +357,10 @@
 }
 
 // Tests the items in the view when the country value changes.
+// TODO(crbug.com/40281788): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
 TEST_P(AutofillProfileEditTableViewControllerTest,
-       TestItemsOnCountrySelection) {
+       DISABLED_TestItemsOnCountrySelection) {
   auto test_case = GetParam();
   TableViewTextEditItem* city_item =
       static_cast<TableViewTextEditItem*>(GetTableViewItem(0, 4));
@@ -458,7 +464,7 @@
 
 // Tests that the sections and items are as expected on initialization, as well
 // as when the country value is changed.
-// TODO(crbug.com/402776694): Re-enable the test once the NumberOfItemsInSection
+// TODO(crbug.com/416030990): Re-enable the test once the NumberOfItemsInSection
 // based on the selected country problem is fixed.
 TEST_P(AutofillProfileEditTableViewControllerTestWithDynamicFieldsEnabled,
        DISABLED_SectionsAndItems) {
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
index 354a773..c9a4d74 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
@@ -13,6 +13,7 @@
   deps = [
     "//base:base",
     "//components/autofill/core/browser",
+    "//components/strings",
     "//ios/chrome/browser/alert_view/ui_bundled",
     "//ios/chrome/browser/autofill/model:model_internal",
     "//ios/chrome/browser/autofill/ui_bundled:coordinator",
@@ -33,6 +34,7 @@
     "//base/test:test_support",
     "//components/autofill/core/browser",
     "//components/autofill/ios/browser:test_support",
+    "//components/strings",
     "//ios/chrome/browser/alert_view/ui_bundled",
     "//ios/chrome/browser/shared/ui/symbols:symbols",
     "//testing/gtest",
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm
index ae1694e..2f84dfa 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm
@@ -9,10 +9,12 @@
 #import "base/memory/weak_ptr.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/autofill/core/browser/ui/payments/autofill_progress_dialog_controller_impl.h"
+#import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_action.h"
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h"
 #import "ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_delegate.h"
 #import "ios/chrome/browser/shared/ui/symbols/symbols.h"
+#import "ui/base/l10n/l10n_util.h"
 
 AutofillProgressDialogMediator::AutofillProgressDialogMediator(
     base::WeakPtr<autofill::AutofillProgressDialogControllerImpl>
@@ -36,7 +38,8 @@
   if (show_confirmation_before_closing) {
     [consumer_ setProgressState:ProgressIndicatorStateSuccess];
     [consumer_ setActions:@[]];
-
+    consumer_.confirmationAccessibilityLabel = l10n_util::GetNSString(
+        IDS_IOS_AUTOFILL_PROGRESS_DIALOG_CONFIRMATION_ACCESSIBILITY_ANNOUNCEMENT);
     // TODO(crbug.com/413453967): Add dismiss delay logic to IOS autofill
     // progress dialog
     [delegate_ dismissDialog];
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm
index 9320f3e..eb2bc35c 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm
@@ -7,6 +7,7 @@
 #import "base/strings/sys_string_conversions.h"
 #import "components/autofill/core/browser/autofill_progress_dialog_type.h"
 #import "components/autofill/core/browser/ui/payments/autofill_progress_dialog_controller_impl.h"
+#import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_action.h"
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h"
 #import "ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_delegate.h"
@@ -15,6 +16,7 @@
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/gtest_support.h"
+#import "ui/base/l10n/l10n_util.h"
 
 class AutofillProgressDialogMediatorTest : public PlatformTest {
  protected:
@@ -63,7 +65,10 @@
 // Tests that when showing confirmation, the consumer is updated correctly.
 TEST_F(AutofillProgressDialogMediatorTest,
        DismissDialog_ShowConfirmation_UpdatesConsumer) {
+  NSString* expectedLabel = l10n_util::GetNSString(
+      IDS_IOS_AUTOFILL_PROGRESS_DIALOG_CONFIRMATION_ACCESSIBILITY_ANNOUNCEMENT);
   mediator_->SetConsumer(consumer_);
+  OCMExpect([consumer_ setConfirmationAccessibilityLabel:expectedLabel]);
 
   // Expectations for the consumer when showing confirmation.
   OCMExpect([consumer_ setProgressState:ProgressIndicatorStateSuccess]);
diff --git a/ios/chrome/browser/commerce/model/push_notification/BUILD.gn b/ios/chrome/browser/commerce/model/push_notification/BUILD.gn
index da5a4f3f..3fe5b6d5 100644
--- a/ios/chrome/browser/commerce/model/push_notification/BUILD.gn
+++ b/ios/chrome/browser/commerce/model/push_notification/BUILD.gn
@@ -57,6 +57,7 @@
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser/test:test_support",
     "//ios/chrome/browser/shared/model/profile/test",
+    "//ios/chrome/browser/shared/public/features",
     "//ios/chrome/browser/url_loading/model",
     "//ios/chrome/browser/url_loading/model:test_support",
     "//ios/chrome/test:test_support",
diff --git a/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm b/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm
index dd55e96..2693ba51 100644
--- a/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm
+++ b/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm
@@ -41,6 +41,7 @@
 #import "ios/chrome/browser/shared/public/commands/application_commands.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
 #import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h"
+#import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gmock/include/gmock/gmock.h"
@@ -204,10 +205,15 @@
     [browser_->GetCommandDispatcher()
         startDispatchingToTarget:application_handler_
                      forProtocol:@protocol(ApplicationCommands)];
+
+    commerce_push_notification_client_ =
+        IsIOSMultiProfilePushNotificationHandlingEnabled()
+            ? std::make_unique<CommercePushNotificationClient>(profile_.get())
+            : std::make_unique<CommercePushNotificationClient>();
   }
 
   CommercePushNotificationClient* GetCommercePushNotificationClient() {
-    return &commerce_push_notification_client_;
+    return commerce_push_notification_client_.get();
   }
 
   Browser* GetBrowser() { return browser_.get(); }
@@ -219,28 +225,29 @@
   void HandleNotificationInteraction(NSString* action_identifier,
                                      NSDictionary* user_info,
                                      base::OnceClosure completion) {
-    commerce_push_notification_client_.HandleNotificationInteraction(
+    commerce_push_notification_client_->HandleNotificationInteraction(
         action_identifier, user_info, std::move(completion));
   }
 
   std::vector<std::pair<GURL, base::OnceCallback<void(Browser*)>>>&
   GetUrlsDelayedForLoading() {
-    return commerce_push_notification_client_.urls_delayed_for_loading_;
+    return commerce_push_notification_client_->urls_delayed_for_loading_;
   }
 
   void OnSceneActiveForegroundBrowserReady() {
-    commerce_push_notification_client_.OnSceneActiveForegroundBrowserReady();
+    commerce_push_notification_client_->OnSceneActiveForegroundBrowserReady();
   }
 
   Browser* GetSceneLevelForegroundActiveBrowser() {
-    return commerce_push_notification_client_.GetActiveForegroundBrowser();
+    return commerce_push_notification_client_->GetActiveForegroundBrowser();
   }
 
  protected:
   web::WebTaskEnvironment task_environment_;
   IOSChromeScopedTestingLocalState scoped_testing_local_state_;
   TestProfileManagerIOS profile_manager_;
-  CommercePushNotificationClient commerce_push_notification_client_;
+  std::unique_ptr<CommercePushNotificationClient>
+      commerce_push_notification_client_;
   std::unique_ptr<Browser> browser_;
   std::unique_ptr<Browser> background_browser_;
   raw_ptr<TestProfileIOS> profile_;
@@ -319,13 +326,11 @@
     kSerializedPayloadKey : base::SysUTF8ToNSString(serialized_any_escaped)
   };
 
-  CommercePushNotificationClient push_notification_client;
-
   EXPECT_CALL(mock_delegate,
               RemoveFetchedEntriesByHintKeys(
                   testing::_, testing::Eq(optimization_guide::proto::HOST),
                   testing::ElementsAreArray({kHintKey})));
-  push_notification_client.HandleNotificationReception(dict);
+  commerce_push_notification_client_->HandleNotificationReception(dict);
 }
 
 TEST_F(CommercePushNotificationClientTest, TestNotificationInteraction) {
diff --git a/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm b/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm
index f172416..b5776906 100644
--- a/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm
+++ b/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm
@@ -21,6 +21,7 @@
 #import "components/services/patch/in_process_file_patcher.h"
 #import "components/services/unzip/in_process_unzipper.h"
 #import "components/update_client/activity_data_service.h"
+#import "components/update_client/crx_cache.h"
 #import "components/update_client/crx_downloader_factory.h"
 #import "components/update_client/net/network_chromium.h"
 #import "components/update_client/patch/patch_impl.h"
@@ -71,7 +72,7 @@
   GetProtocolHandlerFactory() const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   update_client::UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<update_client::CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
  private:
@@ -83,6 +84,7 @@
   scoped_refptr<update_client::CrxDownloaderFactory> crx_downloader_factory_;
   scoped_refptr<update_client::UnzipperFactory> unzip_factory_;
   scoped_refptr<update_client::PatcherFactory> patch_factory_;
+  scoped_refptr<update_client::CrxCache> crx_cache_;
 
   ~IOSConfigurator() override = default;
 };
@@ -98,7 +100,13 @@
             ApplicationContext* context = GetApplicationContext();
             return context ? context->GetLocalState() : nullptr;
           }),
-          nullptr)) {}
+          nullptr)) {
+  base::FilePath path;
+  bool result = base::PathService::Get(base::DIR_CACHE, &path);
+  crx_cache_ = base::MakeRefCounted<update_client::CrxCache>(
+      result ? std::optional<base::FilePath>(path.AppendASCII("ios_crx_cache"))
+             : std::nullopt);
+}
 
 base::TimeDelta IOSConfigurator::InitialDelay() const {
   return configurator_impl_.InitialDelay();
@@ -227,12 +235,8 @@
   return configurator_impl_.GetUpdaterStateProvider();
 }
 
-std::optional<base::FilePath> IOSConfigurator::GetCrxCachePath() const {
-  base::FilePath path;
-  if (!base::PathService::Get(base::DIR_CACHE, &path)) {
-    return std::nullopt;
-  }
-  return path.Append(FILE_PATH_LITERAL("ios_crx_cache"));
+scoped_refptr<update_client::CrxCache> IOSConfigurator::GetCrxCache() const {
+  return crx_cache_;
 }
 
 bool IOSConfigurator::IsConnectionMetered() const {
diff --git a/ios/chrome/browser/download/coordinator/download_manager_mediator.h b/ios/chrome/browser/download/coordinator/download_manager_mediator.h
index e7cc502..b055f30c 100644
--- a/ios/chrome/browser/download/coordinator/download_manager_mediator.h
+++ b/ios/chrome/browser/download/coordinator/download_manager_mediator.h
@@ -7,6 +7,7 @@
 
 #import "base/files/file_path.h"
 #import "base/memory/weak_ptr.h"
+#import "base/scoped_observation.h"
 #import "components/signin/public/identity_manager/identity_manager.h"
 #import "ios/chrome/browser/download/ui/download_manager_consumer.h"
 #import "ios/chrome/browser/drive/model/upload_task_observer.h"
@@ -124,6 +125,9 @@
   void AppWillEnterForeground();
 
   raw_ptr<signin::IdentityManager> identity_manager_ = nullptr;
+  base::ScopedObservation<signin::IdentityManager,
+                          signin::IdentityManager::Observer>
+      identity_manager_observation_{this};
   raw_ptr<drive::DriveService> drive_service_ = nullptr;
   raw_ptr<PrefService> pref_service_ = nullptr;
   bool is_incognito_;
diff --git a/ios/chrome/browser/download/coordinator/download_manager_mediator.mm b/ios/chrome/browser/download/coordinator/download_manager_mediator.mm
index 7f7ddb99..dcfdd28b 100644
--- a/ios/chrome/browser/download/coordinator/download_manager_mediator.mm
+++ b/ios/chrome/browser/download/coordinator/download_manager_mediator.mm
@@ -32,9 +32,7 @@
 DownloadManagerMediator::~DownloadManagerMediator() {
   DCHECK(!application_foregrounding_observer_);
   SetDownloadTask(nullptr);
-  if (identity_manager_) {
-    identity_manager_->RemoveObserver(this);
-  }
+  identity_manager_observation_.Reset();
   identity_manager_ = nullptr;
 }
 
@@ -46,12 +44,10 @@
 
 void DownloadManagerMediator::SetIdentityManager(
     signin::IdentityManager* identity_manager) {
-  if (identity_manager_) {
-    identity_manager_->RemoveObserver(this);
-  }
+  identity_manager_observation_.Reset();
   identity_manager_ = identity_manager;
   if (identity_manager_) {
-    identity_manager_->AddObserver(this);
+    identity_manager_observation_.Observe(identity_manager_);
     UpdateConsumer();
   }
 }
diff --git a/ios/chrome/browser/enterprise/connectors/BUILD.gn b/ios/chrome/browser/enterprise/connectors/BUILD.gn
index 6c70f97..ef5ed64 100644
--- a/ios/chrome/browser/enterprise/connectors/BUILD.gn
+++ b/ios/chrome/browser/enterprise/connectors/BUILD.gn
@@ -42,8 +42,11 @@
     "//components/resources:components_resources_grit",
     "//components/safe_browsing/core/browser:safe_browsing_metrics_collector",
     "//components/safe_browsing/core/browser/db:v4_protocol_manager_util",
+    "//components/safe_browsing/core/common/proto:realtimeapi_proto",
     "//components/safe_browsing/ios/browser:allow_list",
     "//components/security_interstitials/core",
+    "//ios/chrome/browser/enterprise/connectors/reporting",
+    "//ios/chrome/browser/enterprise/connectors/reporting:util",
     "//ios/chrome/browser/safe_browsing/model",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/profile",
@@ -67,8 +70,10 @@
     "//components/enterprise/connectors/core",
     "//components/policy/core/common",
     "//components/profile_metrics",
+    "//components/security_interstitials/core:unsafe_resource",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/profile",
+    "//ios/components/security_interstitials/safe_browsing",
     "//ios/web/common:user_agent",
     "//ios/web/public",
   ]
@@ -108,12 +113,14 @@
     "//components/signin/public/base",
     "//components/signin/public/identity_manager",
     "//components/signin/public/identity_manager:test_support",
+    "//ios/chrome/browser/enterprise/connectors/reporting",
     "//ios/chrome/browser/policy/model",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/profile",
     "//ios/chrome/browser/shared/model/profile/test",
     "//ios/chrome/browser/signin/model",
     "//ios/chrome/browser/signin/model:test_support",
+    "//ios/components/security_interstitials/safe_browsing",
     "//ios/web/public/test",
     "//ios/web/public/test/fakes",
     "//services/network:test_support",
diff --git a/ios/chrome/browser/enterprise/connectors/connectors_util.mm b/ios/chrome/browser/enterprise/connectors/connectors_util.mm
index 596653d..67dc239 100644
--- a/ios/chrome/browser/enterprise/connectors/connectors_util.mm
+++ b/ios/chrome/browser/enterprise/connectors/connectors_util.mm
@@ -6,6 +6,7 @@
 
 #import <optional>
 
+#import "base/feature_list.h"
 #import "components/enterprise/connectors/core/common.h"
 #import "components/policy/core/common/cloud/cloud_policy_core.h"
 #import "components/policy/core/common/cloud/cloud_policy_store.h"
@@ -17,6 +18,7 @@
 #import "ios/chrome/browser/shared/model/profile/profile_attributes_storage_ios.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/chrome/browser/shared/model/profile/profile_manager_ios.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/web/common/user_agent.h"
 #import "ios/web/public/web_client.h"
 
diff --git a/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial.mm b/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial.mm
index 9915255..7a03a13 100644
--- a/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial.mm
+++ b/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial.mm
@@ -7,8 +7,10 @@
 #import "components/grit/components_resources.h"
 #import "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
 #import "components/safe_browsing/core/browser/safe_browsing_metrics_collector.h"
+#import "components/safe_browsing/core/common/proto/realtimeapi.pb.h"
 #import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h"
 #import "components/security_interstitials/core/urls.h"
+#import "ios/chrome/browser/enterprise/connectors/reporting/reporting_util.h"
 #import "ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
@@ -47,6 +49,9 @@
       : IOSEnterpriseInterstitial(resource, std::move(client)) {
     DCHECK_EQ(resource.threat_type,
               safe_browsing::SBThreatType::SB_THREAT_TYPE_MANAGED_POLICY_BLOCK);
+
+    ReportEnterpriseUrlFilteringEvent(UrlFilteringEventType::kBlockedSeen,
+                                      request_url(), web_state());
   }
 
   // EnterpriseInterstitialBase:
@@ -63,6 +68,8 @@
       : IOSEnterpriseInterstitial(resource, std::move(client)) {
     DCHECK_EQ(resource.threat_type,
               safe_browsing::SBThreatType::SB_THREAT_TYPE_MANAGED_POLICY_WARN);
+    ReportEnterpriseUrlFilteringEvent(UrlFilteringEventType::kWarnedSeen,
+                                      request_url(), web_state());
   }
 
   // EnterpriseInterstitialBase:
@@ -204,6 +211,10 @@
         return;
       }
 
+      // Report that the user bypassed the warning.
+      ReportEnterpriseUrlFilteringEvent(UrlFilteringEventType::kBypassed,
+                                        request_url_, web_state());
+
       // Add the URL to the allowlist for this specific threat type.
       if (SafeBrowsingUrlAllowList* allow_list =
               SafeBrowsingUrlAllowList::FromWebState(web_state())) {
diff --git a/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial_unittest.mm b/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial_unittest.mm
index 85cd7a7..07e0d32 100644
--- a/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial_unittest.mm
+++ b/ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial_unittest.mm
@@ -4,20 +4,33 @@
 
 #import "ios/chrome/browser/enterprise/connectors/ios_enterprise_interstitial.h"
 
+#import <string.h>
+
 #import "base/strings/strcat.h"
 #import "base/test/ios/wait_util.h"
 #import "base/test/metrics/histogram_tester.h"
+#import "base/test/scoped_feature_list.h"
+#import "components/enterprise/connectors/core/features.h"
+#import "components/enterprise/connectors/core/reporting_event_router.h"
+#import "components/keyed_service/core/keyed_service.h"
+#import "components/safe_browsing/core/common/proto/csd.pb.h"
 #import "components/safe_browsing/core/common/proto/realtimeapi.pb.h"
 #import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h"
 #import "components/security_interstitials/core/metrics_helper.h"
+#import "ios/chrome/browser/enterprise/connectors/features.h"
+#import "ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client.h"
+#import "ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.h"
+#import "ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/web/public/test/fakes/fake_navigation_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
 #import "testing/platform_test.h"
+#import "url/gurl.h"
 
 namespace enterprise_connectors {
 
@@ -25,6 +38,9 @@
 using base::test::ios::WaitUntilConditionOrTimeout;
 using safe_browsing::SBThreatType;
 using safe_browsing::ThreatSource;
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::InSequence;
 
 namespace {
 
@@ -39,10 +55,44 @@
 constexpr char kTestUrl[] = "http://example.com";
 constexpr char kTestMessage[] = "Test message";
 
+class MockReportingEventRouter : public ReportingEventRouter {
+  using ReferrerChain =
+      google::protobuf::RepeatedPtrField<safe_browsing::ReferrerChainEntry>;
+
+ public:
+  explicit MockReportingEventRouter(
+      IOSRealtimeReportingClient* reporting_client)
+      : ReportingEventRouter(reporting_client) {}
+
+  MOCK_METHOD(void,
+              OnUrlFilteringInterstitial,
+              (const GURL& url,
+               const std::string& threat_type,
+               const safe_browsing::RTLookupResponse& response,
+               const ReferrerChain& referrer_chain),
+              (override));
+};
+
+std::unique_ptr<KeyedService> BuildTestingReportingEventRouter(
+    web::BrowserState* browser_state) {
+  auto* profile = ProfileIOS::FromBrowserState(browser_state);
+  return std::make_unique<MockReportingEventRouter>(
+      IOSRealtimeReportingClientFactory::GetForProfile(profile));
+}
+
 class IOSEnterpriseInterstitialTest : public PlatformTest {
  public:
-  IOSEnterpriseInterstitialTest()
-      : profile_(TestProfileIOS::Builder().Build()) {
+  IOSEnterpriseInterstitialTest() {
+    TestProfileIOS::Builder builder = TestProfileIOS::Builder();
+    builder.AddTestingFactory(
+        IOSReportingEventRouterFactory::GetInstance(),
+        base::BindRepeating(&BuildTestingReportingEventRouter));
+
+    profile_ = std::move(builder).Build();
+
+    event_router_ = static_cast<MockReportingEventRouter*>(
+        IOSReportingEventRouterFactory::GetForProfile(profile_.get()));
+
     auto navigation_manager = std::make_unique<web::FakeNavigationManager>();
     navigation_manager->SetBrowserState(profile_.get());
     navigation_manager_ = navigation_manager.get();
@@ -50,6 +100,7 @@
     web_state_.SetBrowserState(profile_.get());
 
     SafeBrowsingUrlAllowList::CreateForWebState(&web_state_);
+    SafeBrowsingUnsafeResourceContainer::CreateForWebState(&web_state_);
   }
 
   security_interstitials::UnsafeResource CreateBlockUnsafeResource() {
@@ -89,10 +140,31 @@
     unsafe_resource.rt_lookup_response = response;
   }
 
+  void RegisterUnsafeResource(
+      const security_interstitials::UnsafeResource& resource) {
+    SafeBrowsingUrlAllowList::FromWebState(&web_state_)
+        ->AddPendingUnsafeNavigationDecision(resource.url,
+                                             resource.threat_type);
+    SafeBrowsingUnsafeResourceContainer::FromWebState(&web_state_)
+        ->StoreMainFrameUnsafeResource(resource);
+  }
+
+  std::unique_ptr<IOSEnterpriseInterstitial> CreateBlockingPage(
+      const security_interstitials::UnsafeResource& resource) {
+    RegisterUnsafeResource(resource);
+    return IOSEnterpriseInterstitial::CreateBlockingPage(resource);
+  }
+  std::unique_ptr<IOSEnterpriseInterstitial> CreateWarningPage(
+      const security_interstitials::UnsafeResource& resource) {
+    RegisterUnsafeResource(resource);
+    return IOSEnterpriseInterstitial::CreateWarningPage(resource);
+  }
+
  protected:
   web::WebTaskEnvironment task_environment_{
       web::WebTaskEnvironment::MainThreadType::IO};
-  std::unique_ptr<ProfileIOS> profile_;
+  std::unique_ptr<TestProfileIOS> profile_;
+  raw_ptr<MockReportingEventRouter> event_router_ = nullptr;
   web::FakeWebState web_state_;
   raw_ptr<web::FakeNavigationManager> navigation_manager_ = nullptr;
 };
@@ -100,11 +172,21 @@
 }  // namespace
 
 TEST_F(IOSEnterpriseInterstitialTest, EnterpriseBlock_MetricsRecorded) {
+  base::test::ScopedFeatureList feature;
+  feature.InitWithFeatures(
+      /*enable_features=*/{kEnterpriseRealtimeEventReportingOnIOS,
+                           kIOSEnterpriseRealtimeUrlFiltering},
+      /*disable_features=*/{});
+
   base::HistogramTester histograms;
   histograms.ExpectTotalCount(kBlockDecisionHistogram, 0);
 
-  auto test_page = IOSEnterpriseInterstitial::CreateBlockingPage(
-      CreateBlockUnsafeResource());
+  // Creating the blocking page should trigger a blocked seen event.;
+  EXPECT_CALL(*event_router_,
+              OnUrlFilteringInterstitial(Eq(GURL(kTestUrl)),
+                                         Eq("ENTERPRISE_BLOCKED_SEEN"), _, _));
+
+  auto test_page = CreateBlockingPage(CreateBlockUnsafeResource());
   EXPECT_TRUE(test_page->ShouldCreateNewNavigation());
   EXPECT_EQ(test_page->request_url(), GURL(kTestUrl));
 
@@ -123,11 +205,28 @@
 }
 
 TEST_F(IOSEnterpriseInterstitialTest, EnterpriseWarn_MetricsRecorded) {
+  base::test::ScopedFeatureList feature;
+  feature.InitWithFeatures(
+      /*enable_features=*/{kEnterpriseRealtimeEventReportingOnIOS,
+                           kIOSEnterpriseRealtimeUrlFiltering},
+      /*disable_features=*/{});
+
   base::HistogramTester histograms;
   histograms.ExpectTotalCount(kWarnDecisionHistogram, 0);
 
-  auto test_page =
-      IOSEnterpriseInterstitial::CreateWarningPage(CreateWarnUnsafeResource());
+  {
+    InSequence seq;
+    // Creating the warning page should trigger a warned seen event.;
+    EXPECT_CALL(*event_router_,
+                OnUrlFilteringInterstitial(Eq(GURL(kTestUrl)),
+                                           Eq("ENTERPRISE_WARNED_SEEN"), _, _));
+    // Proceed command should trigger repoting a bypass event;
+    EXPECT_CALL(*event_router_,
+                OnUrlFilteringInterstitial(
+                    Eq(GURL(kTestUrl)), Eq("ENTERPRISE_WARNED_BYPASS"), _, _));
+  }
+
+  auto test_page = CreateWarningPage(CreateWarnUnsafeResource());
   EXPECT_TRUE(test_page->ShouldCreateNewNavigation());
   EXPECT_EQ(test_page->request_url(), GURL(kTestUrl));
 
@@ -162,7 +261,7 @@
   auto warn_resource = CreateWarnUnsafeResource();
   AddCustomMessageToResource(warn_resource,
                              safe_browsing::RTLookupResponse::ThreatInfo::WARN);
-  EXPECT_NE(IOSEnterpriseInterstitial::CreateWarningPage(warn_resource)
+  EXPECT_NE(CreateWarningPage(warn_resource)
                 ->GetHtmlContents()
                 .find(expected_primary_paragraph),
             std::string::npos);
@@ -183,8 +282,7 @@
   ASSERT_EQ(1, navigation_manager_->GetLastCommittedItemIndex());
   ASSERT_TRUE(navigation_manager_->CanGoBack());
 
-  auto test_page = IOSEnterpriseInterstitial::CreateBlockingPage(
-      CreateBlockUnsafeResource());
+  auto test_page = CreateBlockingPage(CreateBlockUnsafeResource());
 
   test_page->HandleCommand(security_interstitials::CMD_DONT_PROCEED);
 
@@ -203,8 +301,7 @@
 // WebState if there is no safe NavigationItem to navigate back to.
 TEST_F(IOSEnterpriseInterstitialTest, HandleDontProceedCommandWithoutSafeItem) {
   // Send the don't proceed command.
-  auto test_page = IOSEnterpriseInterstitial::CreateBlockingPage(
-      CreateBlockUnsafeResource());
+  auto test_page = CreateBlockingPage(CreateBlockUnsafeResource());
 
   test_page->HandleCommand(security_interstitials::CMD_DONT_PROCEED);
 
@@ -225,8 +322,7 @@
   ASSERT_FALSE(allow_list->AreUnsafeNavigationsAllowed(GURL(kTestUrl)));
   ASSERT_FALSE(navigation_manager_->ReloadWasCalled());
 
-  auto test_page =
-      IOSEnterpriseInterstitial::CreateWarningPage(CreateWarnUnsafeResource());
+  auto test_page = CreateWarningPage(CreateWarnUnsafeResource());
   test_page->HandleCommand(security_interstitials::CMD_PROCEED);
 
   std::set<SBThreatType> allowed_threats;
@@ -254,8 +350,7 @@
       pending_threats,
       ::testing::ElementsAre(SBThreatType::SB_THREAT_TYPE_MANAGED_POLICY_WARN));
 
-  auto test_page =
-      IOSEnterpriseInterstitial::CreateWarningPage(CreateWarnUnsafeResource());
+  auto test_page = CreateWarningPage(CreateWarnUnsafeResource());
   // Destroying interstitial should remove pending allow list decisions.
   test_page = nullptr;
   EXPECT_FALSE(allow_list->IsUnsafeNavigationDecisionPending(GURL(kTestUrl)));
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/BUILD.gn b/ios/chrome/browser/enterprise/connectors/reporting/BUILD.gn
index 94d6293..7bab717 100644
--- a/ios/chrome/browser/enterprise/connectors/reporting/BUILD.gn
+++ b/ios/chrome/browser/enterprise/connectors/reporting/BUILD.gn
@@ -36,6 +36,25 @@
   ]
 }
 
+source_set("util") {
+  sources = [
+    "reporting_util.h",
+    "reporting_util.mm",
+  ]
+
+  deps = [
+    ":reporting",
+    "//base",
+    "//components/enterprise/connectors/core",
+    "//components/security_interstitials/core:unsafe_resource",
+    "//ios/chrome/browser/enterprise/connectors:features",
+    "//ios/chrome/browser/shared/model/profile",
+    "//ios/components/security_interstitials/safe_browsing",
+    "//ios/web/public",
+    "//url",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/reporting_util.h b/ios/chrome/browser/enterprise/connectors/reporting/reporting_util.h
new file mode 100644
index 0000000..40d9ad86
--- /dev/null
+++ b/ios/chrome/browser/enterprise/connectors/reporting/reporting_util.h
@@ -0,0 +1,39 @@
+// Copyright 2025 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_ENTERPRISE_CONNECTORS_REPORTING_REPORTING_UTIL_H_
+#define IOS_CHROME_BROWSER_ENTERPRISE_CONNECTORS_REPORTING_REPORTING_UTIL_H_
+
+class GURL;
+
+namespace web {
+class WebState;
+}  // namespace web
+
+namespace enterprise_connectors {
+
+// Enum representing the type of URL filtering event being reported.
+enum class UrlFilteringEventType {
+  // Interstitial for a blocked URL was shown.
+  kBlockedSeen,
+  // Interstitial for a flagged URL was shown.
+  kWarnedSeen,
+  // User chose to bypass the warning interstitial.
+  kBypassed,
+};
+
+// Reports a URL filtering event (e.g., interstitial shown, bypassed) to the
+// enterprise reporting system.
+//
+// Parameters:
+//   event_type: The type of event that occurred (see UrlFilteringEventType).
+//   page_url: The URL that triggered the event.
+//   web_state: The WebState associated with the event.
+void ReportEnterpriseUrlFilteringEvent(UrlFilteringEventType event_type,
+                                       const GURL& page_url,
+                                       web::WebState* web_state);
+
+}  // namespace enterprise_connectors
+
+#endif  // IOS_CHROME_BROWSER_ENTERPRISE_CONNECTORS_REPORTING_REPORTING_UTIL_H_
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/reporting_util.mm b/ios/chrome/browser/enterprise/connectors/reporting/reporting_util.mm
new file mode 100644
index 0000000..5e4c3d447
--- /dev/null
+++ b/ios/chrome/browser/enterprise/connectors/reporting/reporting_util.mm
@@ -0,0 +1,80 @@
+// Copyright 2025 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/enterprise/connectors/reporting/reporting_util.h"
+
+#import <string.h>
+
+#import "base/check.h"
+#import "base/feature_list.h"
+#import "components/enterprise/connectors/core/features.h"
+#import "components/enterprise/connectors/core/reporting_event_router.h"
+#import "components/safe_browsing/core/common/proto/csd.pb.h"
+#import "components/security_interstitials/core/unsafe_resource.h"
+#import "ios/chrome/browser/enterprise/connectors/features.h"
+#import "ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
+#import "ios/web/public/web_state.h"
+#import "url/gurl.h"
+
+namespace {
+
+using enterprise_connectors::UrlFilteringEventType;
+
+// Converts the UrlFilteringEventType enum to the string expected by the
+// ReportingEventRouter.
+std::string GetEventTypeString(UrlFilteringEventType event_type) {
+  switch (event_type) {
+    case UrlFilteringEventType::kBlockedSeen:
+      return "ENTERPRISE_BLOCKED_SEEN";
+    case UrlFilteringEventType::kWarnedSeen:
+      return "ENTERPRISE_WARNED_SEEN";
+    case UrlFilteringEventType::kBypassed:
+      return "ENTERPRISE_WARNED_BYPASS";
+  }
+}
+
+}  // namespace
+
+namespace enterprise_connectors {
+
+void ReportEnterpriseUrlFilteringEvent(UrlFilteringEventType event_type,
+                                       const GURL& page_url,
+                                       web::WebState* web_state) {
+  if (!base::FeatureList::IsEnabled(kEnterpriseRealtimeEventReportingOnIOS)) {
+    return;
+  }
+  if (!base::FeatureList::IsEnabled(kIOSEnterpriseRealtimeUrlFiltering)) {
+    return;
+  }
+
+  CHECK(web_state);
+  SafeBrowsingUnsafeResourceContainer* container =
+      SafeBrowsingUnsafeResourceContainer::FromWebState(web_state);
+  // There is no container when opening the interstitial directly
+  // through the chrome://interstitials WebUI page. No-op as there was no real
+  // Url Filtering event.
+  if (!container) {
+    return;
+  }
+
+  const security_interstitials::UnsafeResource* resource =
+      container->GetMainFrameUnsafeResource();
+  CHECK(resource);
+
+  ProfileIOS* profile =
+      ProfileIOS::FromBrowserState(web_state->GetBrowserState());
+  CHECK(profile);
+
+  ReportingEventRouter* event_router =
+      IOSReportingEventRouterFactory::GetForProfile(profile);
+  CHECK(event_router);
+  // ReferrerChain is not supported on ios for now.
+  event_router->OnUrlFilteringInterstitial(
+      page_url, GetEventTypeString(event_type), resource->rt_lookup_response,
+      /*referrer_chain=*/{});
+}
+
+}  // namespace enterprise_connectors
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index b7624e9..8c015e1 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1566,6 +1566,9 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(kIOSReactivationNotifications,
                                     kIOSReactivationNotificationsVariations,
                                     "IOSReactivationNotifications")},
+    {"ios-expanded-tips", flag_descriptions::kIOSExpandedTipsName,
+     flag_descriptions::kIOSExpandedTipsDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kIOSExpandedTips)},
     {"invalidate-search-engine-choice-on-device-restore-detection",
      flag_descriptions::
          kInvalidateSearchEngineChoiceOnDeviceRestoreDetectionName,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 5abec46..3f9df4e 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -726,6 +726,11 @@
     "Enables a feature to send provisional notifications of interest to new"
     "users and encourage them to return to the app.";
 
+const char kIOSExpandedTipsName[] = "Expanded Tips Notifications";
+const char kIOSExpandedTipsDescription[] =
+    "Enables a feature that adds several new Tips Notifications that can be "
+    "sent.";
+
 const char kIOSProvidesAppNotificationSettingsName[] =
     "IOS Provides App Notification Settings";
 const char kIOSProvidesAppNotificationSettingsDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index bf06289..15c6288 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -418,6 +418,9 @@
 extern const char kIOSReactivationNotificationsName[];
 extern const char kIOSReactivationNotificationsDescription[];
 
+extern const char kIOSExpandedTipsName[];
+extern const char kIOSExpandedTipsDescription[];
+
 extern const char kIOSProvidesAppNotificationSettingsName[];
 extern const char kIOSProvidesAppNotificationSettingsDescription[];
 
diff --git a/ios/chrome/browser/infobars/ui_bundled/modals/autofill_address_profile/legacy_infobar_edit_address_profile_table_view_controller_unittest.mm b/ios/chrome/browser/infobars/ui_bundled/modals/autofill_address_profile/legacy_infobar_edit_address_profile_table_view_controller_unittest.mm
index d419e631..d88a419 100644
--- a/ios/chrome/browser/infobars/ui_bundled/modals/autofill_address_profile/legacy_infobar_edit_address_profile_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/infobars/ui_bundled/modals/autofill_address_profile/legacy_infobar_edit_address_profile_table_view_controller_unittest.mm
@@ -147,8 +147,10 @@
 };
 
 // Tests the edit view initialisation for the save prompt of an account profile.
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
 TEST_F(LegacyInfobarEditAddressProfileTableViewControllerTest,
-       TestEditForAccountProfile) {
+       DISABLED_TestEditForAccountProfile) {
   CreateAccountProfile();
 
   NSString* expected_footer_text = l10n_util::GetNSStringF(
@@ -170,8 +172,10 @@
 };
 
 // Tests the edit view initialisation for the migration prompt to account.
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
 TEST_F(LegacyInfobarEditAddressProfileTableViewControllerMigrationPromptTest,
-       TestMigrationPrompt) {
+       DISABLED_TestMigrationPrompt) {
   NSString* expected_footer_text = l10n_util::GetNSStringF(
       IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_FOOTER, kTestSyncingEmail);
   TestModelRowsAndButtons(
diff --git a/ios/chrome/browser/metrics/model/metrics_app_interface.mm b/ios/chrome/browser/metrics/model/metrics_app_interface.mm
index b6f5020..ed783cb 100644
--- a/ios/chrome/browser/metrics/model/metrics_app_interface.mm
+++ b/ios/chrome/browser/metrics/model/metrics_app_interface.mm
@@ -70,8 +70,9 @@
 + (BOOL)setMetricsAndCrashReportingForTesting:(BOOL)enabled {
   BOOL previousValue = g_metrics_enabled;
   g_metrics_enabled = enabled;
-  GetApplicationContext()->GetMetricsServicesManager()->UpdateUploadPermissions(
-      true);
+  GetApplicationContext()
+      ->GetMetricsServicesManager()
+      ->UpdateUploadPermissions();
   return previousValue;
 }
 
diff --git a/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios_unittest.mm b/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios_unittest.mm
index 07fc79d9..cbca660 100644
--- a/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios_unittest.mm
+++ b/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios_unittest.mm
@@ -32,10 +32,16 @@
     CGRect rect = CGRectMake(0, 0, 100, 20);
     textfield_ = [[OmniboxTextFieldIOS alloc] initWithFrame:rect
                                               isLensOverlay:NO];
-    [GetAnyKeyWindow() addSubview:textfield_];
+    root_view_controller_ = GetAnyKeyWindow().rootViewController;
+    [root_view_controller_.view addSubview:textfield_];
   }
 
-  void TearDown() override { [textfield_ removeFromSuperview]; }
+  void TearDown() override {
+    if ([textfield_ isFirstResponder]) {
+      [textfield_ resignFirstResponder];
+    }
+    [textfield_ removeFromSuperview];
+  }
 
   void ExpectRectEqual(CGRect expectedRect, CGRect actualRect) {
     EXPECT_EQ(expectedRect.origin.x, actualRect.origin.x);
@@ -52,8 +58,10 @@
     // The NSRange conversion mechanism only works when the field is first
     // responder.
     [textfield_ setText:text];
-    [textfield_ becomeFirstResponder];
-    ASSERT_TRUE([textfield_ isFirstResponder]);
+    if (![textfield_ isFirstResponder]) {
+      [textfield_ becomeFirstResponder];
+    }
+    EXPECT_TRUE([textfield_ isFirstResponder]);
 
     // `i` and `j` hold the start and end offsets of the range that is currently
     // being tested.  This function iterates through all possible combinations
@@ -102,25 +110,15 @@
       j = i + 1;
       start = [textfield_ positionFromPosition:beginning offset:i];
     }
-
-    [textfield_ resignFirstResponder];
   }
 
+  UIViewController* root_view_controller_;
   OmniboxTextFieldIOS* textfield_;
   base::test::TaskEnvironment task_environment_;
 };
 
-// TODO:(crbug.com/1156541): Re-enable this test on devices.
-#if TARGET_OS_SIMULATOR
-#define MAYBE_SelectedRanges SelectedRanges
-#else
-#define MAYBE_SelectedRanges FLAKY_SelectedRanges
-#endif
-TEST_F(OmniboxTextFieldIOSTest, MAYBE_SelectedRanges) {
-  if (@available(iOS 17, *)) {
-    // TODO:(crbug.com/1468176): Failing on iOS17 beta 5.
-    return;
-  }
+// Tests that selectedNSRange and selectedTextRange returns similar values.
+TEST_F(OmniboxTextFieldIOSTest, SelectedRanges) {
   base::FilePath test_data_directory;
   ASSERT_TRUE(base::PathService::Get(ios::DIR_TEST_DATA, &test_data_directory));
   base::FilePath test_file = test_data_directory.Append(
diff --git a/ios/chrome/browser/omnibox/ui_bundled/BUILD.gn b/ios/chrome/browser/omnibox/ui_bundled/BUILD.gn
index 773497b..67787f2 100644
--- a/ios/chrome/browser/omnibox/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/omnibox/ui_bundled/BUILD.gn
@@ -4,6 +4,7 @@
 
 # TODO(crbug.com/394567614): Remove after moving internal.
 source_set("omnibox_icon_type_constants") {
+  sources = [ "omnibox_icon_type.h" ]
   public_deps =
       [ "//ios/chrome/browser/omnibox/ui:omnibox_icon_type_constants" ]
 }
diff --git a/ios/chrome/browser/omnibox/ui_bundled/omnibox_icon_type.h b/ios/chrome/browser/omnibox/ui_bundled/omnibox_icon_type.h
new file mode 100644
index 0000000..432bcf73
--- /dev/null
+++ b/ios/chrome/browser/omnibox/ui_bundled/omnibox_icon_type.h
@@ -0,0 +1,10 @@
+// Copyright 2025 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_OMNIBOX_UI_BUNDLED_OMNIBOX_ICON_TYPE_H_
+#define IOS_CHROME_BROWSER_OMNIBOX_UI_BUNDLED_OMNIBOX_ICON_TYPE_H_
+
+#import "ios/chrome/browser/omnibox/ui/omnibox_icon_type.h"
+
+#endif  // IOS_CHROME_BROWSER_OMNIBOX_UI_BUNDLED_OMNIBOX_ICON_TYPE_H_
diff --git a/ios/chrome/browser/passwords/model/password_controller_unittest.mm b/ios/chrome/browser/passwords/model/password_controller_unittest.mm
index 4d7f2b54..02153199 100644
--- a/ios/chrome/browser/passwords/model/password_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/model/password_controller_unittest.mm
@@ -1949,7 +1949,7 @@
                // Reattaching it manually for test purposes.
                "       frames[0].addEventListener('unload', function(event) {"
                "  window.webkit.messageHandlers['FrameBecameUnavailable']."
-               "      postMessage(frames[0].__gCrWeb.message.getFrameId());"
+               "      postMessage(frames[0].__gCrWeb.getFrameId());"
                "});"
                "}"
                "</script>"
@@ -2019,7 +2019,7 @@
                // Reattaching it manually for test purposes.
                "       frames[0].addEventListener('unload', function(event) {"
                "  window.webkit.messageHandlers['FrameBecameUnavailable']."
-               "      postMessage(frames[0].__gCrWeb.message.getFrameId());"
+               "      postMessage(frames[0].__gCrWeb.getFrameId());"
                "});"
                "}"
                "</script>"
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 9d800e393..4be152ab 100644
--- a/ios/chrome/browser/push_notification/model/push_notification_delegate.mm
+++ b/ios/chrome/browser/push_notification/model/push_notification_delegate.mm
@@ -429,6 +429,12 @@
   }
 
   client_manager->HandleNotificationInteraction(response);
+
+  // Also allow the app-scoped clients the opportunity to handle interactions.
+  GetApplicationContext()
+      ->GetPushNotificationService()
+      ->GetPushNotificationClientManager()
+      ->HandleNotificationInteraction(response);
 }
 
 // Creates a `ChangeProfileContinuation` callback bound with the original
@@ -1029,6 +1035,7 @@
 
   if (IsIOSMultiProfilePushNotificationHandlingEnabled()) {
     [self handleProfileSpecificNotificationResponse:response];
+    return;
   }
 
   // Notifications are intentionally passed on to the `appWideClientManager`
@@ -1061,6 +1068,10 @@
       response.notification.request.content.userInfo);
 
   if (profileName.empty()) {
+    // No profile name was found, so allow app-wide clients the opportunity to
+    // handle interactions.
+    self.appWideClientManager->HandleNotificationInteraction(response);
+
     RecordClientManagerAccessFailure(PushNotificationClientManagerFailurePoint::
                                          kHandleInteractionInvalidProfileName);
 
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm b/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm
index b727d9f..df444c7 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm
@@ -153,7 +153,9 @@
   if ([self
           isRunningTest:@selector(testRestoreToWarningPagePreservesHistory)] ||
       [self isRunningTest:@selector(testMalwarePage)] ||
-      [self isRunningTest:@selector(testProceedingPastMalwareWarning)]) {
+      [self isRunningTest:@selector(testProceedingPastMalwareWarning)] ||
+      [self
+          isRunningTest:@selector(testProceedingPastMalwareWarningReported)]) {
     config.additional_args.push_back(std::string(
         "--disable-features=SafeBrowsingHashPrefixRealTimeLookups"));
   } else {
@@ -172,6 +174,7 @@
     config.additional_args.push_back(
         base::StrCat({"<dict><key>", kEnrollmentTokenPolicyName,
                       "</key><string>", kEnrollmentToken, "</string></dict>"}));
+    config.relaunch_policy = ForceRelaunchByKilling;
   }
 
   config.additional_args.push_back(
@@ -300,7 +303,9 @@
 
 - (BOOL)isRunningEnterpriseReportingTest {
   return
-      [self isRunningTest:@selector(testProceedingPastPhishingWarningReported)];
+      [self
+          isRunningTest:@selector(testProceedingPastPhishingWarningReported)] ||
+      [self isRunningTest:@selector(testProceedingPastMalwareWarningReported)];
 }
 
 - (void)waitForEnterpriseReports:(int)count {
@@ -582,9 +587,7 @@
 
 // Tests expanding the details on a malware warning, and proceeding past the
 // warning is reported to an enterprise connector.
-// TODO(crbug.com/415736132): Re-enable test and add to Enterprise reporting
-// list `isRunningEnterpriseReportingTest`.
-- (void)DISABLED_testProceedingPastMalwareWarningReported {
+- (void)testProceedingPastMalwareWarningReported {
   [ChromeEarlGrey loadURL:_safeURL1];
   [ChromeEarlGrey waitForWebStateContainingText:_safeContent1];
 
diff --git a/ios/chrome/browser/search_engine_choice/ui_bundled/BUILD.gn b/ios/chrome/browser/search_engine_choice/ui_bundled/BUILD.gn
index e0854cc0..c639459 100644
--- a/ios/chrome/browser/search_engine_choice/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/search_engine_choice/ui_bundled/BUILD.gn
@@ -66,12 +66,16 @@
   ]
   deps = [
     "//base",
+    "//build:branding_buildflags",
     "//components/regional_capabilities",
+    "//components/resources:components_scaled_resources_grit",
     "//components/search_engines",
     "//ios/chrome/browser/favicon/model",
     "//ios/chrome/common/ui/favicon",
     "//ios/chrome/common/ui/favicon:favicon_constants",
+    "//third_party/search_engines_data:search_engines_scaled_resources_grit",
     "//ui/base",
+    "//ui/resources",
   ]
   frameworks = [ "UIKit.framework" ]
 }
diff --git a/ios/chrome/browser/search_engine_choice/ui_bundled/search_engine_choice_ui_util.mm b/ios/chrome/browser/search_engine_choice/ui_bundled/search_engine_choice_ui_util.mm
index defb1aef..37556a6 100644
--- a/ios/chrome/browser/search_engine_choice/ui_bundled/search_engine_choice_ui_util.mm
+++ b/ios/chrome/browser/search_engine_choice/ui_bundled/search_engine_choice_ui_util.mm
@@ -4,25 +4,49 @@
 
 #import "ios/chrome/browser/search_engine_choice/ui_bundled/search_engine_choice_ui_util.h"
 
+#import <algorithm>
+#import <string>
+
 #import "base/strings/utf_string_conversions.h"
+#import "build/branding_buildflags.h"
+#import "components/grit/components_scaled_resources.h"
 #import "components/regional_capabilities/regional_capabilities_service.h"
 #import "components/search_engines/template_url.h"
 #import "components/search_engines/template_url_service.h"
 #import "ios/chrome/common/ui/favicon/favicon_attributes.h"
 #import "ios/chrome/common/ui/favicon/favicon_constants.h"
+#import "third_party/search_engines_data/search_engines_scaled_resources_map.h"
 #import "ui/base/resource/resource_bundle.h"
+#import "ui/resources/grit/ui_resources.h"
 
 UIImage* SearchEngineFaviconFromTemplateURL(const TemplateURL& template_url) {
   // Only works for prepopulated search engines.
   CHECK_GT(template_url.prepopulate_id(), 0)
       << base::UTF16ToUTF8(template_url.short_name());
-  std::u16string engine_keyword = template_url.data().keyword();
-  int resource_id = search_engines::GetIconResourceId(engine_keyword);
-  if (resource_id == -1) {
-    // It is possible to have no resource id for a prepopulated search engine
-    // that was selected from a country outside of EEA countries.
-    return nil;
+
+  // This would be better served by ResourcesUtil::GetThemeResourceId(), but
+  // the symbol appears to be unreachable from the ios/chrome/browser.
+  std::string resource_name = template_url.data().GetBuiltinImageResourceId();
+  int resource_id = IDR_DEFAULT_FAVICON;
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  // Google resources are part of the Chrome resources bundle and require
+  // special case handling.
+  if (resource_name == "IDR_SEARCH_ENGINE_GOOGLE_IMAGE") {
+    resource_id = IDR_SEARCH_ENGINE_GOOGLE_IMAGE;
+  } else
+#endif
+  {
+    auto resource_it = std::ranges::find_if(
+        kSearchEnginesScaledResources,
+        [&](const auto& resource) { return resource.path == resource_name; });
+
+    // Note: it is possible to have no resource id for a prepopulated search
+    // engine that was selected from a country outside of EEA countries.
+    if (resource_it != std::end(kSearchEnginesScaledResources)) {
+      resource_id = resource_it->id;
+    }
   }
+
   ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
   return resource_bundle.GetNativeImageNamed(resource_id).ToUIImage();
 }
diff --git a/ios/chrome/browser/search_engines/model/extension_search_engine_data_updater_unittest.mm b/ios/chrome/browser/search_engines/model/extension_search_engine_data_updater_unittest.mm
index a7a0d974..4f17300 100644
--- a/ios/chrome/browser/search_engines/model/extension_search_engine_data_updater_unittest.mm
+++ b/ios/chrome/browser/search_engines/model/extension_search_engine_data_updater_unittest.mm
@@ -94,9 +94,10 @@
       std::string_view(), std::string_view(), std::string_view(),
       std::string_view(), std::string_view(), std::string_view(),
       std::string_view(), std::string_view(), std::string_view(),
-      std::string_view(), std::string_view(), {}, std::string_view(),
-      std::string_view(), std::u16string_view(), base::Value::List(), false,
-      false, 0, base::span<TemplateURLData::RegulatoryExtension>());
+      std::string_view(), std::string_view(), std::string_view(), {},
+      std::string_view(), std::string_view(), std::u16string_view(),
+      base::Value::List(), false, false, 0,
+      base::span<TemplateURLData::RegulatoryExtension>());
   TemplateURL google_template_url(google_template_url_data);
 
   template_url_service()->SetUserSelectedDefaultSearchProvider(
diff --git a/ios/chrome/browser/sessions/model/BUILD.gn b/ios/chrome/browser/sessions/model/BUILD.gn
index f585166..7f4a219 100644
--- a/ios/chrome/browser/sessions/model/BUILD.gn
+++ b/ios/chrome/browser/sessions/model/BUILD.gn
@@ -422,15 +422,11 @@
     ":test_support",
     "//base",
     "//base/test:test_support",
-    "//components/data_sharing:test_support",
     "//components/prefs",
-    "//components/saved_tab_groups/test_support",
     "//components/sessions:session_id",
     "//components/tab_groups",
-    "//ios/chrome/browser/data_sharing/model",
     "//ios/chrome/browser/main/model",
     "//ios/chrome/browser/ntp/model",
-    "//ios/chrome/browser/saved_tab_groups/model",
     "//ios/chrome/browser/sessions/model/proto",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser/test:test_support",
diff --git a/ios/chrome/browser/sessions/model/legacy_session_restoration_service_unittest.mm b/ios/chrome/browser/sessions/model/legacy_session_restoration_service_unittest.mm
index 50964dd..e2f8840d 100644
--- a/ios/chrome/browser/sessions/model/legacy_session_restoration_service_unittest.mm
+++ b/ios/chrome/browser/sessions/model/legacy_session_restoration_service_unittest.mm
@@ -22,10 +22,6 @@
 #import "base/test/metrics/histogram_tester.h"
 #import "base/test/scoped_feature_list.h"
 #import "base/time/time.h"
-#import "components/data_sharing/test_support/mock_data_sharing_service.h"
-#import "components/saved_tab_groups/test_support/fake_tab_group_sync_service.h"
-#import "ios/chrome/browser/data_sharing/model/data_sharing_service_factory.h"
-#import "ios/chrome/browser/saved_tab_groups/model/tab_group_sync_service_factory.h"
 #import "ios/chrome/browser/sessions/model/session_constants.h"
 #import "ios/chrome/browser/sessions/model/session_internal_util.h"
 #import "ios/chrome/browser/sessions/model/session_loading.h"
@@ -376,22 +372,7 @@
 
     // Create a test ProfileIOS and an object to track the files
     // that are created by the session restoration service operations.
-    TestProfileIOS::Builder builder;
-    builder.AddTestingFactory(
-        tab_groups::TabGroupSyncServiceFactory::GetInstance(),
-        base::BindOnce(
-            [](web::BrowserState* context) -> std::unique_ptr<KeyedService> {
-              // Creates a FakeTabGroupSyncService, as the real implementation
-              // affects the list of created files.
-              return std::make_unique<tab_groups::FakeTabGroupSyncService>();
-            }));
-    builder.AddTestingFactory(
-        data_sharing::DataSharingServiceFactory::GetInstance(),
-        base::BindOnce(
-            [](web::BrowserState* context) -> std::unique_ptr<KeyedService> {
-              return std::make_unique<data_sharing::MockDataSharingService>();
-            }));
-    profile_ = std::move(builder).Build();
+    profile_ = TestProfileIOS::Builder().Build();
     file_tracker_.Start(profile_->GetStatePath());
 
     SessionServiceIOS* session_service_ios = [[SessionServiceIOS alloc]
diff --git a/ios/chrome/browser/sessions/model/session_restoration_service_factory_unittest.mm b/ios/chrome/browser/sessions/model/session_restoration_service_factory_unittest.mm
index 1d6108a..8fd20a3 100644
--- a/ios/chrome/browser/sessions/model/session_restoration_service_factory_unittest.mm
+++ b/ios/chrome/browser/sessions/model/session_restoration_service_factory_unittest.mm
@@ -7,9 +7,7 @@
 #import "base/run_loop.h"
 #import "base/test/metrics/histogram_tester.h"
 #import "base/types/cxx23_to_underlying.h"
-#import "components/data_sharing/test_support/mock_data_sharing_service.h"
 #import "components/prefs/pref_service.h"
-#import "ios/chrome/browser/data_sharing/model/data_sharing_service_factory.h"
 #import "ios/chrome/browser/sessions/model/proto/storage.pb.h"
 #import "ios/chrome/browser/sessions/model/session_constants.h"
 #import "ios/chrome/browser/sessions/model/session_internal_util.h"
@@ -104,23 +102,12 @@
   return ios::sessions::ParseProto(session_path, session_storage);
 }
 
-// Creates a MockDataSharingService.
-std::unique_ptr<KeyedService> CreateMockDataSharingService(
-    web::BrowserState* context) {
-  return std::make_unique<data_sharing::MockDataSharingService>();
-}
-
 }  // namespace
 
 class SessionRestorationServiceFactoryTest : public PlatformTest {
  public:
-  SessionRestorationServiceFactoryTest() {
-    TestProfileIOS::Builder builder;
-    builder.AddTestingFactory(
-        data_sharing::DataSharingServiceFactory::GetInstance(),
-        base::BindRepeating(&CreateMockDataSharingService));
-    profile_ = std::move(builder).Build();
-  }
+  SessionRestorationServiceFactoryTest()
+      : profile_(TestProfileIOS::Builder().Build()) {}
 
   ProfileIOS* profile() { return profile_.get(); }
 
diff --git a/ios/chrome/browser/sessions/model/session_restoration_service_impl_unittest.mm b/ios/chrome/browser/sessions/model/session_restoration_service_impl_unittest.mm
index 099affc..073572c 100644
--- a/ios/chrome/browser/sessions/model/session_restoration_service_impl_unittest.mm
+++ b/ios/chrome/browser/sessions/model/session_restoration_service_impl_unittest.mm
@@ -20,10 +20,6 @@
 #import "base/scoped_multi_source_observation.h"
 #import "base/test/metrics/histogram_tester.h"
 #import "base/time/time.h"
-#import "components/data_sharing/test_support/mock_data_sharing_service.h"
-#import "components/saved_tab_groups/test_support/fake_tab_group_sync_service.h"
-#import "ios/chrome/browser/data_sharing/model/data_sharing_service_factory.h"
-#import "ios/chrome/browser/saved_tab_groups/model/tab_group_sync_service_factory.h"
 #import "ios/chrome/browser/sessions/model/proto/storage.pb.h"
 #import "ios/chrome/browser/sessions/model/session_constants.h"
 #import "ios/chrome/browser/sessions/model/session_internal_util.h"
@@ -368,22 +364,7 @@
 
     // Create a test ProfileIOS and an object to track the files
     // that are created by the session restoration service operations.
-    TestProfileIOS::Builder builder;
-    builder.AddTestingFactory(
-        tab_groups::TabGroupSyncServiceFactory::GetInstance(),
-        base::BindOnce(
-            [](web::BrowserState* context) -> std::unique_ptr<KeyedService> {
-              // Creates a FakeTabGroupSyncService, as the real implementation
-              // affects the list of created files.
-              return std::make_unique<tab_groups::FakeTabGroupSyncService>();
-            }));
-    builder.AddTestingFactory(
-        data_sharing::DataSharingServiceFactory::GetInstance(),
-        base::BindOnce(
-            [](web::BrowserState* context) -> std::unique_ptr<KeyedService> {
-              return std::make_unique<data_sharing::MockDataSharingService>();
-            }));
-    profile_ = std::move(builder).Build();
+    profile_ = TestProfileIOS::Builder().Build();
     file_tracker_.Start(profile_->GetStatePath());
 
     // Create the service, force enabling features support.
diff --git a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm
index c59ed0b..7d59f94 100644
--- a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm
@@ -87,7 +87,10 @@
 };
 
 // Default test case of no addresses or credit cards.
-TEST_F(AutofillSettingsProfileEditTableViewControllerTest, TestInitialization) {
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
+TEST_F(AutofillSettingsProfileEditTableViewControllerTest,
+       DISABLED_TestInitialization) {
   TableViewModel* model = [controller() tableViewModel];
 
   EXPECT_EQ(1, [model numberOfSections]);
@@ -166,24 +169,30 @@
 };
 
 // Adding an account address results in an address section.
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
 TEST_F(AutofillSettingsProfileEditTableViewControllerTestWithUnionViewEnabled,
-       TestAccountProfileView) {
+       DISABLED_TestAccountProfileView) {
   CreateAccountProfile();
   EXPECT_EQ(2, [[controller() tableViewModel] numberOfSections]);
   TestViewData();
 }
 
 // Adding an address results in an address section.
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
 TEST_F(AutofillSettingsProfileEditTableViewControllerTestWithUnionViewEnabled,
-       TestProfileView) {
+       DISABLED_TestProfileView) {
   EXPECT_EQ(1, [[controller() tableViewModel] numberOfSections]);
   TestViewData();
 }
 
 // Tests the footer text of the view controller for the address profiles with
 // source kAccount.
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
 TEST_F(AutofillSettingsProfileEditTableViewControllerTestWithUnionViewEnabled,
-       TestFooterTextWithEmail) {
+       DISABLED_TestFooterTextWithEmail) {
   CreateAccountProfile();
   TableViewModel* model = [controller() tableViewModel];
 
@@ -218,8 +227,10 @@
 };
 
 // Tests the number of sections and the number of items in the sections.
+// TODO(crbug.com/416030990): Adapt test to
+// AutofillDynamicallyLoadsFieldsForAddressInput and re-enable the test.
 TEST_F(AutofillSettingsProfileEditTableViewControllerWithMigrationButtonTest,
-       TestElementsInView) {
+       DISABLED_TestElementsInView) {
   TableViewModel* model = [controller() tableViewModel];
   int rowCnt = 12;
 
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_coordinator.mm b/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_coordinator.mm
index 4949b31c..adb0c9a9 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_coordinator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_coordinator.mm
@@ -511,6 +511,8 @@
 #pragma mark - Private
 
 - (void)dismissActionSheetCoordinator {
+  UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
+                                  self.viewController.customLeftBarButtonItem);
   [self.actionSheetCoordinator stop];
   self.actionSheetCoordinator = nil;
 }
diff --git a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
index 8f27376d..ffe30634 100644
--- a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
+++ b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
@@ -189,6 +189,7 @@
     "//ios/chrome/browser/snapshots/model",
     "//ios/chrome/browser/start_surface/ui_bundled",
     "//ios/chrome/browser/start_surface/ui_bundled:feature_flags",
+    "//ios/chrome/browser/sync/model",
     "//ios/chrome/browser/tab_insertion/model",
     "//ios/chrome/browser/tab_switcher/ui_bundled:utils",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid",
diff --git a/ios/chrome/browser/shared/coordinator/scene/DEPS b/ios/chrome/browser/shared/coordinator/scene/DEPS
index 1ae06c35..b52a2d92 100644
--- a/ios/chrome/browser/shared/coordinator/scene/DEPS
+++ b/ios/chrome/browser/shared/coordinator/scene/DEPS
@@ -40,6 +40,7 @@
   "+ios/chrome/browser/signin/model",
   "+ios/chrome/browser/snapshots/model",
   "+ios/chrome/browser/start_surface/ui_bundled",
+  "+ios/chrome/browser/sync/model/sync_service_factory.h",
   "+ios/chrome/browser/tab_insertion/model",
   "+ios/chrome/browser/tab_switcher/ui_bundled",
   "+ios/chrome/browser/url_loading/model",
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
index ce26c36..bcd1a1b 100644
--- a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
+++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
@@ -182,6 +182,7 @@
 #import "ios/chrome/browser/start_surface/ui_bundled/start_surface_recent_tab_browser_agent.h"
 #import "ios/chrome/browser/start_surface/ui_bundled/start_surface_scene_agent.h"
 #import "ios/chrome/browser/start_surface/ui_bundled/start_surface_util.h"
+#import "ios/chrome/browser/sync/model/sync_service_factory.h"
 #import "ios/chrome/browser/tab_insertion/model/tab_insertion_browser_agent.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator_delegate.h"
@@ -1335,8 +1336,15 @@
                            initWithPromosManager:promosManager]];
 
   if (IsFullscreenSigninPromoManagerMigrationEnabled()) {
-    [sceneState addAgent:[[SigninFullscreenPromoSceneAgent alloc]
-                             initWithPromosManager:promosManager]];
+    [sceneState
+        addAgent:
+            [[SigninFullscreenPromoSceneAgent alloc]
+                initWithPromosManager:promosManager
+                          authService:authService
+                      identityManager:IdentityManagerFactory::GetForProfile(
+                                          profile)
+                          syncService:SyncServiceFactory::GetForProfile(profile)
+                          prefService:prefService]];
   }
 }
 
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h
index 0a32223..531f33f4 100644
--- a/ios/chrome/browser/shared/public/features/features.h
+++ b/ios/chrome/browser/shared/public/features/features.h
@@ -862,6 +862,16 @@
 // Returns whether `kIOSReactivationNotifications` is enabled.
 bool IsIOSReactivationNotificationsEnabled();
 
+// Feature flag to enable Expanded Tips.
+BASE_DECLARE_FEATURE(kIOSExpandedTips);
+
+// Feature param containing a comma separated list of integers that represent
+// cases of the `TipsNotificationType` enum.
+extern const char kIOSExpandedTipsOrderParam[];
+
+// Returns whether `kIOSExpandTips` is enabled.
+bool IsIOSExpandedTipsEnabled();
+
 // Feature flag to show an alert to the user when only provisiona notifications
 // are allowed.
 BASE_DECLARE_FEATURE(kProvisionalNotificationAlert);
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm
index b99ba511..e5239cd 100644
--- a/ios/chrome/browser/shared/public/features/features.mm
+++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -1005,6 +1005,15 @@
   return base::FeatureList::IsEnabled(kIOSReactivationNotifications);
 }
 
+BASE_FEATURE(kIOSExpandedTips,
+             "IOSExpandedTips",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+const char kIOSExpandedTipsOrderParam[] = "expanded_tips_order";
+
+bool IsIOSExpandedTipsEnabled() {
+  return base::FeatureList::IsEnabled(kIOSExpandedTips);
+}
+
 BASE_FEATURE(kProvisionalNotificationAlert,
              "ProvisionalNotificationAlert",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -1051,7 +1060,7 @@
 
 BASE_FEATURE(kIOSPushNotificationMultiProfile,
              "IOSPushNotificationMultiProfile",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 bool IsIOSMultiProfilePushNotificationHandlingEnabled() {
   return base::FeatureList::IsEnabled(kIOSPushNotificationMultiProfile);
diff --git a/ios/chrome/browser/web/model/BUILD.gn b/ios/chrome/browser/web/model/BUILD.gn
index b7d6d9a8..c5be1e9 100644
--- a/ios/chrome/browser/web/model/BUILD.gn
+++ b/ios/chrome/browser/web/model/BUILD.gn
@@ -269,6 +269,8 @@
     "//components/variations/field_trial_config",
     "//components/variations/service",
     "//components/version_info",
+    "//components/webauthn/ios",
+    "//components/webauthn/ios:features",
     "//components/webui/flags",
     "//ios/chrome/app/resources:ios_resources",
     "//ios/chrome/browser/application_context/model",
diff --git a/ios/chrome/browser/web/model/chrome_main_parts.mm b/ios/chrome/browser/web/model/chrome_main_parts.mm
index 9908584..ef33a57 100644
--- a/ios/chrome/browser/web/model/chrome_main_parts.mm
+++ b/ios/chrome/browser/web/model/chrome_main_parts.mm
@@ -480,6 +480,5 @@
 
   // TODO(crbug.com/40894426) Add an EG2 test for cloned install detection.
   application_context_->GetMetricsService()->CheckForClonedInstall();
-  application_context_->GetMetricsServicesManager()->UpdateUploadPermissions(
-      true);
+  application_context_->GetMetricsServicesManager()->UpdateUploadPermissions();
 }
diff --git a/ios/chrome/browser/web/model/chrome_web_client.mm b/ios/chrome/browser/web/model/chrome_web_client.mm
index 3dd35ed..cc2c8f2 100644
--- a/ios/chrome/browser/web/model/chrome_web_client.mm
+++ b/ios/chrome/browser/web/model/chrome_web_client.mm
@@ -37,6 +37,8 @@
 #import "components/supervised_user/core/browser/supervised_user_interstitial.h"
 #import "components/translate/ios/browser/translate_java_script_feature.h"
 #import "components/version_info/version_info.h"
+#import "components/webauthn/ios/features.h"
+#import "components/webauthn/ios/passkey_java_script_feature.h"
 #import "ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_java_script_feature.h"
 #import "ios/chrome/browser/browser_container/model/edit_menu_tab_helper.h"
 #import "ios/chrome/browser/content_settings/model/host_content_settings_map_factory.h"
@@ -419,6 +421,11 @@
   features.push_back(ImageFetchJavaScriptFeature::GetInstance());
   features.push_back(
       password_manager::PasswordManagerJavaScriptFeature::GetInstance());
+
+  if (base::FeatureList::IsEnabled(kIOSPasskeyShim)) {
+    features.push_back(PasskeyJavaScriptFeature::GetInstance());
+  }
+
   features.push_back(LinkToTextJavaScriptFeature::GetInstance());
   features.push_back(WebSelectionJavaScriptFeature::GetInstance());
 
diff --git a/ios/chrome/browser/web/model/java_script_console/resources/console.ts b/ios/chrome/browser/web/model/java_script_console/resources/console.ts
index c1f8a280..ccc7fb2 100644
--- a/ios/chrome/browser/web/model/java_script_console/resources/console.ts
+++ b/ios/chrome/browser/web/model/java_script_console/resources/console.ts
@@ -7,7 +7,7 @@
 
 /* eslint-disable no-console */
 
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 type LogLevel = 'log'|'debug'|'info'|'warn'|'error';
@@ -20,7 +20,7 @@
   } catch (err) {
   }
   sendWebKitMessage('ConsoleMessageHandler', {
-    'sender_frame': gCrWebLegacy.message.getFrameId(),
+    'sender_frame': gCrWeb.getFrameId(),
     'log_level': logLevel,
     'message': message,
     'url': document.location.href,
diff --git a/ios/chrome/browser/webui/ui_bundled/about/about_ui.cc b/ios/chrome/browser/webui/ui_bundled/about/about_ui.cc
index e07a9b4..1333b3b 100644
--- a/ios/chrome/browser/webui/ui_bundled/about/about_ui.cc
+++ b/ios/chrome/browser/webui/ui_bundled/about/about_ui.cc
@@ -16,12 +16,14 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/strings/escape.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "components/grit/components_resources.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #include "ios/chrome/browser/shared/model/url/chrome_url_constants.h"
+#include "ios/components/webui/web_ui_url_constants.h"
 #include "ios/web/public/webui/url_data_source_ios.h"
 #include "ui/base/device_form_factor.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -84,6 +86,25 @@
   output->append("</body>\n</html>\n");
 }
 
+void AppendHost(std::string* output, std::string_view host, bool can_follow) {
+  const std::string chrome_url = base::StrCat({kChromeUIScheme, "://", host});
+  output->append("<li>");
+  if (can_follow) {
+    output->append(base::StrCat({
+        "<a href='",
+        chrome_url,
+        "' id='",
+        host,
+        "'>",
+        chrome_url,
+        "</a>",
+    }));
+  } else {
+    output->append(chrome_url);
+  }
+  output->append("</li>\n");
+}
+
 std::string ChromeURLs() {
   std::string html;
   AppendHeader(&html, 0, "Chrome URLs");
@@ -92,10 +113,8 @@
   std::vector<std::string> hosts(kChromeHostURLs,
                                  kChromeHostURLs + kNumberOfChromeHostURLs);
   std::sort(hosts.begin(), hosts.end());
-  for (std::vector<std::string>::const_iterator i = hosts.begin();
-       i != hosts.end(); ++i) {
-    html += "<li><a href='chrome://" + *i + "/' id='" + *i + "'>chrome://" +
-            *i + "</a></li>\n";
+  for (const auto& host : hosts) {
+    AppendHost(&html, host, host != kChromeUINewTabHost);
   }
   html += "</ul>\n";
   AppendFooter(&html);
diff --git a/ios/chrome/browser/webui/ui_bundled/chrome_urls/chrome_urls_handler.mm b/ios/chrome/browser/webui/ui_bundled/chrome_urls/chrome_urls_handler.mm
index 26932a5..71f1fab 100644
--- a/ios/chrome/browser/webui/ui_bundled/chrome_urls/chrome_urls_handler.mm
+++ b/ios/chrome/browser/webui/ui_bundled/chrome_urls/chrome_urls_handler.mm
@@ -51,7 +51,7 @@
     chrome_urls::mojom::WebuiUrlInfoPtr url_info(
         chrome_urls::mojom::WebuiUrlInfo::New());
     url_info->url = url;
-    url_info->enabled = true;
+    url_info->enabled = host != kChromeUINewTabHost;
     url_info->internal = IsWebUIInternal(host);
     webui_urls.push_back(std::move(url_info));
   }
diff --git a/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm b/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm
index 9bbc91c6..f339f5b 100644
--- a/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm
+++ b/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm
@@ -107,13 +107,15 @@
   if (url_host == kChromeUIAutofillInternalsHost) {
     return &NewWebUIIOS<AutofillInternalsUIIOS>;
   }
-  if (base::FeatureList::IsEnabled(chrome_urls::kInternalOnlyUisPref) &&
-      url_host == kChromeUIChromeURLsHost) {
-    // New ChromeUrlsUI is behind the kInternalOnlyUisPref feature flag.
-    return &NewWebUIIOS<chrome_urls::ChromeUrlsUI>;
+  if (url_host == kChromeUIChromeURLsHost) {
+    if (base::FeatureList::IsEnabled(chrome_urls::kInternalOnlyUisPref)) {
+      // New ChromeUrlsUI is behind the kInternalOnlyUisPref feature flag.
+      return &NewWebUIIOS<chrome_urls::ChromeUrlsUI>;
+    } else {
+      return &NewWebUIIOS<AboutUI>;
+    }
   }
-  if (url_host == kChromeUIChromeURLsHost ||
-      url_host == kChromeUIHistogramHost || url_host == kChromeUICreditsHost) {
+  if (url_host == kChromeUIHistogramHost || url_host == kChromeUICreditsHost) {
     return &NewWebUIIOS<AboutUI>;
   }
   if (url_host == commerce::kChromeUICommerceInternalsHost) {
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 486ddfb..08db82b 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -447,10 +447,7 @@
     "//ui/base:test_support",
   ]
 
-  sources = [
-    "web_state/js/common_js_unittest.mm",
-    "web_state/js/message_js_unittest.mm",
-  ]
+  sources = [ "web_state/js/common_js_unittest.mm" ]
 }
 
 source_set("ios_web_web_state_ui_unittests") {
diff --git a/ios/web/js_features/fullscreen/BUILD.gn b/ios/web/js_features/fullscreen/BUILD.gn
index 7e2f104..07563ac 100644
--- a/ios/web/js_features/fullscreen/BUILD.gn
+++ b/ios/web/js_features/fullscreen/BUILD.gn
@@ -25,7 +25,7 @@
 
   sources = [ "resources/fullscreen.ts" ]
   deps = [
-    "//ios/web/public/js_messaging:frame_id",
+    "//ios/web/public/js_messaging:gcrweb",
     "//ios/web/public/js_messaging:util_scripts",
   ]
 }
diff --git a/ios/web/js_features/fullscreen/resources/fullscreen.ts b/ios/web/js_features/fullscreen/resources/fullscreen.ts
index 79382e0..0050501b 100644
--- a/ios/web/js_features/fullscreen/resources/fullscreen.ts
+++ b/ios/web/js_features/fullscreen/resources/fullscreen.ts
@@ -6,7 +6,7 @@
  * @fileoverview Reports viewport details to the app.
  */
 
-import { getFrameId } from '//ios/web/public/js_messaging/resources/frame_id.js';
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 /**
@@ -18,7 +18,7 @@
     const coverValue =
         viewportMeta.getAttribute('content')?.includes('viewport-fit=cover');
     sendWebKitMessage('FullscreenViewportHandler', {
-      'frame_id': getFrameId(),
+      'frame_id': gCrWeb.getFrameId(),
       'cover': coverValue,
     });
   }
diff --git a/ios/web/js_messaging/BUILD.gn b/ios/web/js_messaging/BUILD.gn
index 8f6f2e9..d3bb70f 100644
--- a/ios/web/js_messaging/BUILD.gn
+++ b/ios/web/js_messaging/BUILD.gn
@@ -170,7 +170,6 @@
   sources = [ "resources/frame_listeners.ts" ]
 
   deps = [
-    "//ios/web/public/js_messaging:frame_id",
     "//ios/web/public/js_messaging:gcrweb",
     "//ios/web/public/js_messaging:util_scripts",
   ]
diff --git a/ios/web/js_messaging/resources/frame_listeners.ts b/ios/web/js_messaging/resources/frame_listeners.ts
index 44d1f59..8de5f11 100644
--- a/ios/web/js_messaging/resources/frame_listeners.ts
+++ b/ios/web/js_messaging/resources/frame_listeners.ts
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {getFrameId} from '//ios/web/public/js_messaging/resources/frame_id.js';
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb, gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 window.addEventListener('unload', function() {
-  sendWebKitMessage('FrameBecameUnavailable', getFrameId());
+  sendWebKitMessage('FrameBecameUnavailable', gCrWeb.getFrameId());
 });
 
 /**
diff --git a/ios/web/js_messaging/resources/message.ts b/ios/web/js_messaging/resources/message.ts
index 989d1d4..a08ebab 100644
--- a/ios/web/js_messaging/resources/message.ts
+++ b/ios/web/js_messaging/resources/message.ts
@@ -7,7 +7,7 @@
  * the native code.
  */
 
-import {getFrameId, registerFrame} from '//ios/web/public/js_messaging/resources/frame_id.js';
+import {registerFrame} from '//ios/web/public/js_messaging/resources/frame_id.js';
 import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 
 /**
@@ -36,6 +36,5 @@
 }
 
 gCrWebLegacy.message = {
-  getFrameId,
   getExistingFrames,
 };
diff --git a/ios/web/js_messaging/web_frame_impl_inttest.mm b/ios/web/js_messaging/web_frame_impl_inttest.mm
index 4a4688ec..42384c1 100644
--- a/ios/web/js_messaging/web_frame_impl_inttest.mm
+++ b/ios/web/js_messaging/web_frame_impl_inttest.mm
@@ -55,7 +55,7 @@
 
   __block bool called = false;
   main_frame->CallJavaScriptFunction(
-      "message.getFrameId", base::Value::List(),
+      "getFrameId", base::Value::List(),
       base::BindOnce(^(const base::Value* value) {
         ASSERT_TRUE(value->is_string());
         EXPECT_EQ(value->GetString(), main_frame->GetFrameId());
@@ -84,7 +84,7 @@
 
   __block bool called = false;
   iframe->CallJavaScriptFunction(
-      "message.getFrameId", base::Value::List(),
+      "getFrameId", base::Value::List(),
       base::BindOnce(^(const base::Value* value) {
         ASSERT_TRUE(value->is_string());
         EXPECT_EQ(value->GetString(), iframe->GetFrameId());
diff --git a/ios/web/navigation/resources/navigation.ts b/ios/web/navigation/resources/navigation.ts
index d51c332..e7d7121 100644
--- a/ios/web/navigation/resources/navigation.ts
+++ b/ios/web/navigation/resources/navigation.ts
@@ -6,7 +6,7 @@
  * @fileoverview Navigation related APIs.
  */
 
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 declare interface Message {
@@ -82,7 +82,7 @@
     stateObject: object, pageTitle: string, pageUrl: string|URL): void {
   messageQueue.queueNavigationEventMessage({
     'command': 'willChangeState',
-    'frame_id': gCrWebLegacy.message.getFrameId(),
+    'frame_id': gCrWeb.getFrameId(),
   });
 
   // JSONStringify throws an exception when given a cyclical object. This
@@ -104,7 +104,7 @@
     'stateObject': serializedState,
     'baseUrl': document.baseURI,
     'pageUrl': pageUrl.toString(),
-    'frame_id': gCrWebLegacy.message.getFrameId(),
+    'frame_id': gCrWeb.getFrameId(),
   });
 };
 
@@ -112,7 +112,7 @@
     stateObject: object, pageTitle: string, pageUrl: string|URL): void {
   messageQueue.queueNavigationEventMessage({
     'command': 'willChangeState',
-    'frame_id': gCrWebLegacy.message.getFrameId(),
+    'frame_id': gCrWeb.getFrameId(),
   });
 
   // JSONStringify throws an exception when given a cyclical object. This
@@ -136,6 +136,6 @@
     'stateObject': serializedState,
     'baseUrl': document.baseURI,
     'pageUrl': pageUrl.toString(),
-    'frame_id': gCrWebLegacy.message.getFrameId(),
+    'frame_id': gCrWeb.getFrameId(),
   });
 };
diff --git a/ios/web/navigation/resources/navigation_listeners.ts b/ios/web/navigation/resources/navigation_listeners.ts
index 4eace95..78fbea1 100644
--- a/ios/web/navigation/resources/navigation_listeners.ts
+++ b/ios/web/navigation/resources/navigation_listeners.ts
@@ -6,11 +6,11 @@
  * @fileoverview Navigation listener to report hash change.
  */
 
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 window.addEventListener('hashchange', () => {
   sendWebKitMessage(
       'NavigationEventMessage',
-      {'command': 'hashchange', 'frame_id': gCrWebLegacy.message.getFrameId()});
+      {'command': 'hashchange', 'frame_id': gCrWeb.getFrameId()});
 });
diff --git a/ios/web/public/js_messaging/BUILD.gn b/ios/web/public/js_messaging/BUILD.gn
index 66b415c..ff5016419 100644
--- a/ios/web/public/js_messaging/BUILD.gn
+++ b/ios/web/public/js_messaging/BUILD.gn
@@ -61,6 +61,8 @@
 # compiled TypeScript to be used as a dependency by other TypeScript targets.
 compile_ts("gcrweb") {
   sources = [ "resources/gcrweb.ts" ]
+
+  deps = [ ":util_scripts" ]
 }
 
 optimize_js("gcrweb_js") {
diff --git a/ios/web/public/js_messaging/gcrweb_javascript_test.mm b/ios/web/public/js_messaging/gcrweb_javascript_test.mm
index d2702a68..b219323a 100644
--- a/ios/web/public/js_messaging/gcrweb_javascript_test.mm
+++ b/ios/web/public/js_messaging/gcrweb_javascript_test.mm
@@ -76,3 +76,37 @@
   EXPECT_NSEQ(@"Error: API crWebAPI already registered.",
               execution_error.userInfo[@"WKJavaScriptExceptionMessage"]);
 }
+
+// Tests that a frameId is created.
+TEST_F(CrWebJavaScriptTest, FrameId) {
+  id frame_id1 = web::test::ExecuteJavaScript(
+      web_view(), @"__gCrWeb.unit_tests.getFrameId()");
+
+  ASSERT_TRUE(frame_id1);
+  ASSERT_TRUE([frame_id1 isKindOfClass:[NSString class]]);
+  EXPECT_GT([frame_id1 length], 0ul);
+
+  // Validating that once created the frame id remain the same if the page isn't
+  // reloaded.
+  id frame_id2 = web::test::ExecuteJavaScript(
+      web_view(), @"__gCrWeb.unit_tests.getFrameId()");
+  EXPECT_NSEQ(frame_id1, frame_id2);
+}
+
+// Tests that the frameId is unique between two page loads.
+TEST_F(CrWebJavaScriptTest, UniqueFrameID) {
+  ASSERT_TRUE(LoadHtml(@"<p>"));
+  id frame_id1 = web::test::ExecuteJavaScript(
+      web_view(), @"__gCrWeb.unit_tests.getFrameId()");
+
+  ASSERT_TRUE(LoadHtml(@"<p>"));
+  id frame_id2 = web::test::ExecuteJavaScript(
+      web_view(), @"__gCrWeb.unit_tests.getFrameId()");
+
+  // Validate second frameId.
+  ASSERT_TRUE(frame_id2);
+  ASSERT_TRUE([frame_id2 isKindOfClass:[NSString class]]);
+  EXPECT_GT([frame_id2 length], 0ul);
+
+  EXPECT_NSNE(frame_id1, frame_id2);
+}
diff --git a/ios/web/public/js_messaging/resources/frame_id.ts b/ios/web/public/js_messaging/resources/frame_id.ts
index 68cae48..bf254850 100644
--- a/ios/web/public/js_messaging/resources/frame_id.ts
+++ b/ios/web/public/js_messaging/resources/frame_id.ts
@@ -2,25 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {gCrWebLegacy} from '//ios/web/public/js_messaging/resources/gcrweb.js';
-import {generateRandomId, sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
-
-/**
- * Returns the frameId associated with this frame. A new value will be created
- * for this frame the first time it is called. The frameId will persist as long
- * as this JavaScript context lives. For example, the frameId will be the same
- * when navigating 'back' to this frame.
- */
-export function getFrameId(): string {
-  if (!gCrWebLegacy.hasOwnProperty('frameId')) {
-    gCrWebLegacy.frameId = generateRandomId();
-  }
-  return gCrWebLegacy.frameId;
-}
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
 
 /**
  * Registers this frame by sending its frameId to the native application.
  */
 export function registerFrame() {
-  sendWebKitMessage('FrameBecameAvailable', {'crwFrameId': getFrameId()});
+  sendWebKitMessage(
+    'FrameBecameAvailable', {'crwFrameId': gCrWeb.getFrameId()});
 }
diff --git a/ios/web/public/js_messaging/resources/gcrweb.ts b/ios/web/public/js_messaging/resources/gcrweb.ts
index 54d9a841..4a6439a 100644
--- a/ios/web/public/js_messaging/resources/gcrweb.ts
+++ b/ios/web/public/js_messaging/resources/gcrweb.ts
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {generateRandomId} from '//ios/web/public/js_messaging/resources/utils.js';
+
 /**
  * @fileoverview This file exports `gCrWeb` API to be used by other
  * files to augment its functionality. `gCrWeb` is intended
@@ -12,6 +14,7 @@
 
 class CrWeb {
   private readonly registeredApis: {[id: string]: CrWebApi} = {};
+  private frameId: string = generateRandomId();
 
   /*
    * Register a Javascript API into the CrWeb object. In case
@@ -27,6 +30,19 @@
   getRegisteredApi(apiIdentifier: string): CrWebApi|undefined {
     return this.registeredApis[apiIdentifier];
   }
+
+  /**
+   * Returns the frameId associated with this frame. A new value will be created
+   * for this frame the first time it is called. The frameId will persist as
+   * long as this JavaScript context lives. For example, the frameId will be the
+   * same when navigating 'back' to this frame.
+   */
+  getFrameId(): string {
+    if (!this.frameId) {
+      this.frameId = generateRandomId();
+    }
+    return this.frameId;
+  }
 }
 
 export class CrWebApi {
diff --git a/ios/web/public/js_messaging/resources/gcrweb_test_api.ts b/ios/web/public/js_messaging/resources/gcrweb_test_api.ts
index e5d99bc..14ccc39 100644
--- a/ios/web/public/js_messaging/resources/gcrweb_test_api.ts
+++ b/ios/web/public/js_messaging/resources/gcrweb_test_api.ts
@@ -24,5 +24,6 @@
 gCrWebLegacy.unit_tests = {
   registerApi: gCrWeb.registerApi.bind(gCrWeb),
   getRegisteredApi: gCrWeb.getRegisteredApi.bind(gCrWeb),
+  getFrameId: gCrWeb.getFrameId.bind(gCrWeb),
   setupRegisterApi,
 };
diff --git a/ios/web/web_state/js/message_js_unittest.mm b/ios/web/web_state/js/message_js_unittest.mm
deleted file mode 100644
index abb9892..0000000
--- a/ios/web/web_state/js/message_js_unittest.mm
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Foundation/Foundation.h>
-
-#import "ios/web/public/test/javascript_test.h"
-#import "ios/web/public/test/js_test_util.h"
-#import "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-
-namespace web {
-
-// Test fixture to test message.js.
-class MessageJsTest : public web::JavascriptTest {
- protected:
-  MessageJsTest() {}
-  ~MessageJsTest() override {}
-
-  void SetUp() override {
-    web::JavascriptTest::SetUp();
-
-    AddGCrWebScript();
-    AddCommonScript();
-    AddMessageScript();
-  }
-};
-
-// Tests that a frameId is created.
-TEST_F(MessageJsTest, FrameId) {
-  ASSERT_TRUE(LoadHtml(@"<p>"));
-
-  id result = web::test::ExecuteJavaScript(web_view(),
-                                           @"__gCrWeb.message.getFrameId()");
-
-  ASSERT_TRUE(result);
-  ASSERT_TRUE([result isKindOfClass:[NSString class]]);
-  EXPECT_GT([result length], 0ul);
-}
-
-// Tests that the frameId is unique between two page loads.
-TEST_F(MessageJsTest, UniqueFrameID) {
-  ASSERT_TRUE(LoadHtml(@"<p>"));
-  id frame_id1 = web::test::ExecuteJavaScript(web_view(),
-                                              @"__gCrWeb.message.getFrameId()");
-
-  ASSERT_TRUE(LoadHtml(@"<p>"));
-  id frame_id2 = web::test::ExecuteJavaScript(web_view(),
-                                              @"__gCrWeb.message.getFrameId()");
-  // Validate second frameId.
-  ASSERT_TRUE(frame_id2);
-  ASSERT_TRUE([frame_id2 isKindOfClass:[NSString class]]);
-  EXPECT_GT([frame_id2 length], 0ul);
-
-  EXPECT_NSNE(frame_id1, frame_id2);
-}
-
-}  // namespace web
diff --git a/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm b/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm
index f7d66f1..3809a43d 100644
--- a/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm
+++ b/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm
@@ -21,6 +21,7 @@
 #import "components/services/patch/in_process_file_patcher.h"
 #import "components/services/unzip/in_process_unzipper.h"
 #import "components/update_client/activity_data_service.h"
+#import "components/update_client/crx_cache.h"
 #import "components/update_client/crx_downloader_factory.h"
 #import "components/update_client/net/network_chromium.h"
 #import "components/update_client/patch/patch_impl.h"
@@ -73,7 +74,7 @@
   GetProtocolHandlerFactory() const override;
   std::optional<bool> IsMachineExternallyManaged() const override;
   update_client::UpdaterStateProvider GetUpdaterStateProvider() const override;
-  std::optional<base::FilePath> GetCrxCachePath() const override;
+  scoped_refptr<update_client::CrxCache> GetCrxCache() const override;
   bool IsConnectionMetered() const override;
 
  private:
@@ -85,6 +86,7 @@
   scoped_refptr<update_client::CrxDownloaderFactory> crx_downloader_factory_;
   scoped_refptr<update_client::UnzipperFactory> unzip_factory_;
   scoped_refptr<update_client::PatcherFactory> patch_factory_;
+  scoped_refptr<update_client::CrxCache> crx_cache_;
 
   ~WebViewConfigurator() override = default;
 };
@@ -101,7 +103,14 @@
             ApplicationContext* context = ApplicationContext::GetInstance();
             return context ? context->GetLocalState() : nullptr;
           }),
-          nullptr)) {}
+          nullptr)) {
+  base::FilePath path;
+  bool result = base::PathService::Get(base::DIR_CACHE, &path);
+  crx_cache_ = base::MakeRefCounted<update_client::CrxCache>(
+      result ? std::optional<base::FilePath>(
+                   path.AppendASCII("ios_webview_crx_cache"))
+             : std::nullopt);
+}
 
 base::TimeDelta WebViewConfigurator::InitialDelay() const {
   return configurator_impl_.InitialDelay();
@@ -231,12 +240,9 @@
   return configurator_impl_.GetUpdaterStateProvider();
 }
 
-std::optional<base::FilePath> WebViewConfigurator::GetCrxCachePath() const {
-  base::FilePath path;
-  if (!base::PathService::Get(base::DIR_CACHE, &path)) {
-    return std::nullopt;
-  }
-  return path.Append(FILE_PATH_LITERAL("ios_webview_crx_cache"));
+scoped_refptr<update_client::CrxCache> WebViewConfigurator::GetCrxCache()
+    const {
+  return crx_cache_;
 }
 
 bool WebViewConfigurator::IsConnectionMetered() const {
diff --git a/ios/web_view/test/web_view_autofill_inttest.mm b/ios/web_view/test/web_view_autofill_inttest.mm
index 6c1f78d..9c2d993 100644
--- a/ios/web_view/test/web_view_autofill_inttest.mm
+++ b/ios/web_view/test/web_view_autofill_inttest.mm
@@ -162,7 +162,7 @@
   }
 
   NSString* GetMainFrameId() {
-    NSString* main_frame_id_script = @"__gCrWeb.message.getFrameId();";
+    NSString* main_frame_id_script = @"__gCrWeb.getFrameId();";
     return test::EvaluateJavaScript(web_view_, main_frame_id_script);
   }
 
diff --git a/ios_internal b/ios_internal
index f52bf951..56c2b01 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit f52bf9510b206c97e50249032c3e9b3b461f8694
+Subproject commit 56c2b01d07aad9c323ad655a8cb07b849923ac99
diff --git a/media/audio/audio_debug_recording_helper.h b/media/audio/audio_debug_recording_helper.h
index 91ad2983..81f1036 100644
--- a/media/audio/audio_debug_recording_helper.h
+++ b/media/audio/audio_debug_recording_helper.h
@@ -23,7 +23,11 @@
 
 class AudioBus;
 
-enum class AudioDebugRecordingStreamType { kInput = 0, kOutput = 1 };
+enum class AudioDebugRecordingStreamType {
+  kInput = 0,
+  kOutput = 1,
+  kLoopback = 2
+};
 
 // Interface for feeding data to a recorder.
 class AudioDebugRecorder {
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc
index a8cc99d..a6e5143 100644
--- a/media/audio/audio_manager_base.cc
+++ b/media/audio/audio_manager_base.cc
@@ -358,11 +358,15 @@
       // created stream and cleans it up when it is Close()d, transparently to
       // the user of the stream. I the case where the audio manager closes the
       // stream (Mac), this will result in a dangling pointer.
+      AudioDebugRecordingStreamType stream_type =
+          (device_id == media::AudioDeviceDescription::kLoopbackInputDeviceId)
+              ? AudioDebugRecordingStreamType::kLoopback
+              : AudioDebugRecordingStreamType::kInput;
       stream = new AudioInputStreamDataInterceptor(
           base::BindRepeating(
               &AudioDebugRecordingManager::RegisterDebugRecordingSource,
-              base::Unretained(debug_recording_manager_.get()),
-              AudioDebugRecordingStreamType::kInput, params),
+              base::Unretained(debug_recording_manager_.get()), stream_type,
+              params),
           stream);
     }
   }
diff --git a/media/base/android/media_codec_bridge_impl.cc b/media/base/android/media_codec_bridge_impl.cc
index 3d24046..fe3a1a7 100644
--- a/media/base/android/media_codec_bridge_impl.cc
+++ b/media/base/android/media_codec_bridge_impl.cc
@@ -164,10 +164,10 @@
       break;
     }
     case AudioCodec::kAAC: {
-      if (config.aac_extra_data().empty()) {
+      if (config.extra_data().empty()) {
         return false;
       }
-      *output_csd0 = config.aac_extra_data();
+      *output_csd0 = config.extra_data();
       *output_frame_has_adts_header =
           config.profile() != AudioCodecProfile::kXHE_AAC;
       break;
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc
index 8c6dcd80..9a0bffa 100644
--- a/media/base/audio_decoder_config.cc
+++ b/media/base/audio_decoder_config.cc
@@ -89,8 +89,7 @@
        config.should_discard_decoder_delay()) &&
       (target_output_channel_layout() ==
        config.target_output_channel_layout()) &&
-      (target_output_sample_format() == config.target_output_sample_format()) &&
-      (aac_extra_data() == config.aac_extra_data()));
+      (target_output_sample_format() == config.target_output_sample_format()));
 }
 
 std::string AudioDecoderConfig::AsHumanReadableString() const {
@@ -112,8 +111,7 @@
     << ", target_output_channel_layout: "
     << ChannelLayoutToString(target_output_channel_layout())
     << ", target_output_sample_format: "
-    << SampleFormatToString(target_output_sample_format())
-    << ", has aac extra data: " << base::ToString(!aac_extra_data().empty());
+    << SampleFormatToString(target_output_sample_format());
   return s.str();
 }
 
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h
index 0169da0..147d11f 100644
--- a/media/base/audio_decoder_config.h
+++ b/media/base/audio_decoder_config.h
@@ -122,11 +122,6 @@
     return target_output_sample_format_;
   }
 
-  void set_aac_extra_data(std::vector<uint8_t> aac_extra_data) {
-    aac_extra_data_ = std::move(aac_extra_data);
-  }
-  const std::vector<uint8_t>& aac_extra_data() const { return aac_extra_data_; }
-
  private:
   // WARNING: When modifying or adding any parameters, update the following:
   // - AudioDecoderConfig::AsHumanReadableString()
@@ -162,12 +157,6 @@
   // Desired output format of bitstream. Optionally set. See setter comments.
   SampleFormat target_output_sample_format_ = kUnknownSampleFormat;
 
-  // This is a hack for backward compatibility. For AAC, to preserve existing
-  // behavior, we set `aac_extra_data_` on all platforms but only set
-  // `extra_data` on Android.
-  // TODO(crbug.com/40198159): Remove this after we land a long term fix.
-  std::vector<uint8_t> aac_extra_data_;
-
   // Indicates if a decoder should implicitly discard decoder delay without it
   // being explicitly marked in discard padding.
   bool should_discard_decoder_delay_ = true;
diff --git a/media/base/win/mf_helpers.cc b/media/base/win/mf_helpers.cc
index e05556e..591f9da 100644
--- a/media/base/win/mf_helpers.cc
+++ b/media/base/win/mf_helpers.cc
@@ -460,9 +460,7 @@
   ComPtr<IMFMediaType> media_type;
   RETURN_IF_FAILED(GetDefaultAudioType(decoder_config, &media_type));
 
-  // On Windows `extra_data` is not populated for AAC in `decoder_config`. Use
-  // `aac_extra_data` instead. See crbug.com/1245123.
-  const auto& extra_data = decoder_config.aac_extra_data();
+  const auto& extra_data = decoder_config.extra_data();
 
   size_t wave_format_size = sizeof(HEAACWAVEINFO) + extra_data.size();
   std::vector<uint8_t> wave_format_buffer(wave_format_size);
diff --git a/media/base/win/mf_helpers.h b/media/base/win/mf_helpers.h
index 32c686e..19839d0 100644
--- a/media/base/win/mf_helpers.h
+++ b/media/base/win/mf_helpers.h
@@ -135,7 +135,7 @@
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
 // Given an AudioDecoderConfig which represents AAC audio, get its
 // corresponding IMFMediaType format (by calling GetDefaultAudioType)
-// and populate the aac_extra_data in the decoder_config into the
+// and copy the extra_data from the decoder_config into the
 // returned IMFMediaType.
 MEDIA_EXPORT HRESULT GetAacAudioType(const AudioDecoderConfig& decoder_config,
                                      IMFMediaType** media_type_out);
diff --git a/media/cast/openscreen/remoting_proto_utils.cc b/media/cast/openscreen/remoting_proto_utils.cc
index 61a8c88..6332e27 100644
--- a/media/cast/openscreen/remoting_proto_utils.cc
+++ b/media/cast/openscreen/remoting_proto_utils.cc
@@ -183,25 +183,9 @@
       audio_config.seek_preroll().InMicroseconds());
   audio_message->set_codec_delay(audio_config.codec_delay());
 
-  // We choose to not expose the "aac_extra_data" field to the remoting
-  // protobuf, because it is due to an internal Chrome bug. Instead, use the
-  // "extra_data" field as receivers should expect.
-  //
-  // TODO(crbug.com/40198159): Remove all references to "aac_extra_data" when it
-  // is removed as part of a media/ cleanup.
-#if DCHECK_IS_ON()
-  if (!audio_config.extra_data().empty() &&
-      !audio_config.aac_extra_data().empty() &&
-      audio_config.extra_data() != audio_config.aac_extra_data()) {
-    LOG(WARNING) << "mismatch between extra data and AAC extra data.";
-  }
-#endif
-  const bool is_aac = audio_config.codec() == media::AudioCodec::kAAC;
-  const std::vector<uint8_t>& extra_data =
-      is_aac ? audio_config.aac_extra_data() : audio_config.extra_data();
-
-  if (!extra_data.empty()) {
-    audio_message->set_extra_data(extra_data.data(), extra_data.size());
+  if (!audio_config.extra_data().empty()) {
+    audio_message->set_extra_data(audio_config.extra_data().data(),
+                                  audio_config.extra_data().size());
   }
 }
 
@@ -210,28 +194,17 @@
     media::AudioDecoderConfig* audio_config) {
   DCHECK(audio_config);
 
-  // Either "extra_data" or "aac_extra_data" should be populated but not both.
-  const bool is_aac =
-      audio_message.codec() == openscreen::cast::AudioDecoderConfig::kCodecAAC;
   const auto extra_data = base::span(audio_message.extra_data());
   audio_config->Initialize(
       ToMediaAudioCodec(audio_message.codec()).value(),
       ToMediaSampleFormat(audio_message.sample_format()).value(),
       ToMediaChannelLayout(audio_message.channel_layout()).value(),
       audio_message.samples_per_second(),
-      is_aac ? std::vector<uint8_t>{}
-             : std::vector<uint8_t>(extra_data.begin(), extra_data.end()),
+      std::vector<uint8_t>(extra_data.begin(), extra_data.end()),
       media::EncryptionScheme::kUnencrypted,
       base::Microseconds(audio_message.seek_preroll_usec()),
       audio_message.codec_delay());
 
-  // TODO(crbug.com/40198159): Remove all references to "aac_extra_data" when it
-  // is removed as part of a media/ cleanup.
-  if (is_aac) {
-    audio_config->set_aac_extra_data(
-        std::vector<uint8_t>(extra_data.begin(), extra_data.end()));
-  }
-
   return audio_config->IsValidConfig();
 }
 
diff --git a/media/cast/openscreen/remoting_proto_utils_unittest.cc b/media/cast/openscreen/remoting_proto_utils_unittest.cc
index 15d7fa9..6a248ca 100644
--- a/media/cast/openscreen/remoting_proto_utils_unittest.cc
+++ b/media/cast/openscreen/remoting_proto_utils_unittest.cc
@@ -113,33 +113,6 @@
   ASSERT_TRUE(audio_config.Matches(audio_output_config));
 }
 
-TEST_F(ProtoUtilsTest, AudioDecoderConfigHandlesAacExtraDataCorrectly) {
-  constexpr char aac_extra_data[4] = {'A', 'C', 'E', 'G'};
-  media::AudioDecoderConfig audio_config(
-      media::AudioCodec::kAAC, media::kSampleFormatF32,
-      media::CHANNEL_LAYOUT_MONO, 48000, std::vector<uint8_t>{},
-      media::EncryptionScheme::kUnencrypted);
-  audio_config.set_aac_extra_data(std::vector<uint8_t>(
-      std::begin(aac_extra_data), std::end(aac_extra_data)));
-  ASSERT_TRUE(audio_config.IsValidConfig());
-
-  openscreen::cast::AudioDecoderConfig audio_message;
-  ConvertAudioDecoderConfigToProto(audio_config, &audio_message);
-
-  // We should have filled the "extra_data" protobuf field with
-  // "aac_extra_data."
-  const std::vector<uint8_t> proto_extra_data(
-      audio_message.extra_data().begin(), audio_message.extra_data().end());
-  EXPECT_THAT(proto_extra_data, testing::ElementsAreArray(aac_extra_data));
-
-  media::AudioDecoderConfig audio_output_config;
-  ASSERT_TRUE(
-      ConvertProtoToAudioDecoderConfig(audio_message, &audio_output_config));
-  ASSERT_TRUE(audio_config.Matches(audio_output_config))
-      << "expected=" << audio_config.AsHumanReadableString()
-      << ", actual=" << audio_output_config.AsHumanReadableString();
-}
-
 TEST_F(ProtoUtilsTest, PipelineStatisticsConversion) {
   media::PipelineStatistics original;
   // NOTE: all fields should be initialised here.
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 610be2d3..23ba2cc 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -438,8 +438,6 @@
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
   if (codec == AudioCodec::kAAC) {
-    config->set_aac_extra_data(extra_data);
-
     // TODO(dalecurtis): Just use the profile from the codec context if ffmpeg
     // ever starts supporting xHE-AAC.
     // FFmpeg provides the (defined_profile - 1) for AVCodecContext::profile
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index 4cb8011..0f2f4796 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -228,11 +228,11 @@
 
 #if (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)) && \
     BUILDFLAG(USE_PROPRIETARY_CODECS)
-    // MediaCodec type requires config->aac_extra_data() for AAC codec. For ADTS
+    // MediaCodec type requires config->extra_data() for AAC codec. For ADTS
     // streams we need to extract it with a separate procedure.
     if ((decoder_type_ == AudioDecoderType::kMediaCodec ||
          decoder_type_ == AudioDecoderType::kMediaFoundation) &&
-        params_.codec == AudioCodec::kAAC && config.aac_extra_data().empty()) {
+        params_.codec == AudioCodec::kAAC && config.extra_data().empty()) {
       int sample_rate;
       ChannelLayout channel_layout;
       std::vector<uint8_t> extra_data;
@@ -243,7 +243,6 @@
       config.Initialize(AudioCodec::kAAC, kSampleFormatS16, channel_layout,
                         sample_rate, extra_data, EncryptionScheme::kUnencrypted,
                         base::TimeDelta(), 0);
-      config.set_aac_extra_data(extra_data);
       ASSERT_FALSE(config.extra_data().empty());
     }
 #endif
diff --git a/media/filters/mac/audio_toolbox_audio_decoder.cc b/media/filters/mac/audio_toolbox_audio_decoder.cc
index daad923..1414388c 100644
--- a/media/filters/mac/audio_toolbox_audio_decoder.cc
+++ b/media/filters/mac/audio_toolbox_audio_decoder.cc
@@ -235,7 +235,7 @@
       // Input is xHE-AAC / USAC.
       CHECK_EQ(config.profile(), AudioCodecProfile::kXHE_AAC);
       input_format.mFormatID = kAudioFormatMPEGD_USAC;
-      magic_cookie = mp4::ESDescriptor::CreateEsds(config.aac_extra_data());
+      magic_cookie = mp4::ESDescriptor::CreateEsds(config.extra_data());
 
       // Have macOS fill in the rest of the input_format for us.
       UInt32 format_size = sizeof(input_format);
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index f3806ab..4b2b596 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -515,9 +515,6 @@
       AudioCodecProfile profile = AudioCodecProfile::kUnknown;
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS) ||
         // BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
-      std::vector<uint8_t> aac_extra_data;
-#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
       if (audio_format == FOURCC_OPUS) {
         codec = AudioCodec::kOpus;
@@ -618,10 +615,7 @@
           profile = aac.GetProfile();
           channel_layout = aac.GetChannelLayout(has_sbr_);
           sample_per_second = aac.GetOutputSamplesPerSecond(has_sbr_);
-          // Set `aac_extra_data` on all platforms. This is for backward
-          // compatibility until we have a better solution.
-          // See crbug.com/1245123 for details.
-          aac_extra_data = aac.codec_specific_data();
+          extra_data = aac.codec_specific_data();
 #if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)
         } else if (audio_type == kAC3) {
           codec = AudioCodec::kAC3;
@@ -704,7 +698,6 @@
       if (codec == AudioCodec::kAAC) {
         audio_config.disable_discard_decoder_delay();
         audio_config.set_profile(profile);
-        audio_config.set_aac_extra_data(std::move(aac_extra_data));
       }
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 #if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
diff --git a/media/mojo/mojom/audio_decoder_config_mojom_traits.cc b/media/mojo/mojom/audio_decoder_config_mojom_traits.cc
index 472409f4..d148083 100644
--- a/media/mojo/mojom/audio_decoder_config_mojom_traits.cc
+++ b/media/mojo/mojom/audio_decoder_config_mojom_traits.cc
@@ -50,17 +50,12 @@
   if (!input.ReadTargetOutputSampleFormat(&target_output_sample_format))
     return false;
 
-  std::vector<uint8_t> aac_extra_data;
-  if (!input.ReadAacExtraData(&aac_extra_data))
-    return false;
-
   output->Initialize(codec, sample_format, channel_layout,
                      input.samples_per_second(), std::move(extra_data),
                      encryption_scheme, seek_preroll, input.codec_delay());
   output->set_profile(profile);
   output->set_target_output_channel_layout(target_output_channel_layout);
   output->set_target_output_sample_format(target_output_sample_format);
-  output->set_aac_extra_data(std::move(aac_extra_data));
 
   if (!input.should_discard_decoder_delay())
     output->disable_discard_decoder_delay();
diff --git a/media/mojo/mojom/audio_decoder_config_mojom_traits.h b/media/mojo/mojom/audio_decoder_config_mojom_traits.h
index e2d814436..efec4db7 100644
--- a/media/mojo/mojom/audio_decoder_config_mojom_traits.h
+++ b/media/mojo/mojom/audio_decoder_config_mojom_traits.h
@@ -70,11 +70,6 @@
     return input.should_discard_decoder_delay();
   }
 
-  static const std::vector<uint8_t>& aac_extra_data(
-      const media::AudioDecoderConfig& input) {
-    return input.aac_extra_data();
-  }
-
   static bool Read(media::mojom::AudioDecoderConfigDataView input,
                    media::AudioDecoderConfig* output);
 };
diff --git a/media/mojo/mojom/audio_decoder_config_mojom_traits_unittest.cc b/media/mojo/mojom/audio_decoder_config_mojom_traits_unittest.cc
index 2a6eba8..4f4c880 100644
--- a/media/mojo/mojom/audio_decoder_config_mojom_traits_unittest.cc
+++ b/media/mojo/mojom/audio_decoder_config_mojom_traits_unittest.cc
@@ -95,21 +95,4 @@
   EXPECT_EQ(output.target_output_sample_format(), kSampleFormatDts);
 }
 
-TEST(AudioDecoderConfigStructTraitsTest, AacExtraData) {
-  const uint8_t kAacExtraData[] = "aac extra data";
-  const std::vector<uint8_t> kAacExtraDataVector(
-      kAacExtraData, kAacExtraData + std::size(kAacExtraData));
-
-  AudioDecoderConfig input;
-  input.Initialize(AudioCodec::kAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND,
-                   48000, EmptyExtraData(), EncryptionScheme::kUnencrypted,
-                   base::TimeDelta(), 0);
-  input.set_aac_extra_data(kAacExtraDataVector);
-  std::vector<uint8_t> data = mojom::AudioDecoderConfig::Serialize(&input);
-  AudioDecoderConfig output;
-  EXPECT_TRUE(mojom::AudioDecoderConfig::Deserialize(std::move(data), &output));
-  EXPECT_TRUE(output.Matches(input));
-  EXPECT_EQ(output.aac_extra_data(), kAacExtraDataVector);
-}
-
 }  // namespace media
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom
index 207c27e..108ff17 100644
--- a/media/mojo/mojom/media_types.mojom
+++ b/media/mojo/mojom/media_types.mojom
@@ -206,7 +206,6 @@
   ChannelLayout target_output_channel_layout;
   SampleFormat target_output_sample_format;
   bool should_discard_decoder_delay;
-  array<uint8> aac_extra_data;
 };
 
 // This defines a mojo transport format for media::VideoDecoderConfig.
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index d201aa74..4deb6d46 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@
 #   hash function for preloaded entries again (we have already done so once).
 #
 
-# Last updated: 2025-05-05 12:54 UTC
+# Last updated: 2025-05-06 12:54 UTC
 PinsListTimestamp
-1746449652
+1746536071
 
 TestSPKI
 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json
index 385cb26c..a854f4c 100644
--- a/net/http/transport_security_state_static_pins.json
+++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@
 // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets'
 // refer to, and the timestamp at which the pins list was last updated.
 //
-// Last updated: 2025-05-05 12:54 UTC
+// Last updated: 2025-05-06 12:54 UTC
 //
 {
   "pinsets": [
diff --git a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java
index 02180224..aa7fbd8 100644
--- a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java
+++ b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java
@@ -24,12 +24,14 @@
 import org.chromium.net.test.util.CertTestUtil;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * A simple file server for java tests.
  *
- * An example use:
+ * <p>An example use:
  *
  * <pre>
  * EmbeddedTestServer s = EmbeddedTestServer.createAndStartServer(context);
@@ -488,6 +490,21 @@
     }
 
     /**
+     * Get the full URLs for the given relative URLs.
+     *
+     * @see #getURL(String)
+     * @param relativeUrls The relative URLs for which full URLs will be obtained.
+     * @return The URLs as a List.
+     */
+    public List<String> getURLs(List<String> relativeUrls) {
+        List<String> absoluteUrls = new ArrayList<>(relativeUrls.size());
+        for (String relativeUrl : relativeUrls) {
+            absoluteUrls.add(getURL(relativeUrl));
+        }
+        return absoluteUrls;
+    }
+
+    /**
      * Get the request headers observed on the server for the given relative URL.
      *
      * @param relativeUrl The relative URL for which request headers should be returned.
diff --git a/remoting/host/installer/mac/Scripts/remoting_postflight.sh b/remoting/host/installer/mac/Scripts/remoting_postflight.sh
index aa9a1b7..202a2d3 100755
--- a/remoting/host/installer/mac/Scripts/remoting_postflight.sh
+++ b/remoting/host/installer/mac/Scripts/remoting_postflight.sh
@@ -138,7 +138,8 @@
 # started until a host process connects to
 # chromoting.agent_process_broker_mojo_ipc.
 logger Loading broker service
-launchctl load -w $BROKER_PLIST
+logger launchctl bootstrap system $BROKER_PLIST
+launchctl bootstrap system $BROKER_PLIST
 
 # Load the host service for each user for whom the service was unloaded in the
 # preflight script (this includes the root user, in case only the login screen
diff --git a/remoting/host/installer/mac/Scripts/remoting_preflight.sh b/remoting/host/installer/mac/Scripts/remoting_preflight.sh
index f5e83680..781414e9 100755
--- a/remoting/host/installer/mac/Scripts/remoting_preflight.sh
+++ b/remoting/host/installer/mac/Scripts/remoting_preflight.sh
@@ -11,6 +11,7 @@
 HOST_BUNDLE_NAME=@@HOST_BUNDLE_NAME@@
 CONFIG_FILE="$HELPERTOOLS/$SERVICE_NAME.json"
 OLD_SCRIPT_FILE="$HELPERTOOLS/$SERVICE_NAME.me2me.sh"
+HOST_BUNDLE_PATH="$HELPERTOOLS/$HOST_BUNDLE_NAME"
 HOST_SERVICE_BINARY="$HELPERTOOLS/$HOST_BUNDLE_NAME/Contents/MacOS/remoting_me2me_host_service"
 USERS_TMP_FILE="$HOST_SERVICE_BINARY.users"
 PLIST=/Library/LaunchAgents/org.chromium.chromoting.plist
@@ -18,6 +19,7 @@
 ENABLED_FILE="$HELPERTOOLS/$SERVICE_NAME.me2me_enabled"
 ENABLED_FILE_BACKUP="$ENABLED_FILE.backup"
 PREF_PANE=/Library/PreferencePanes/ChromeRemoteDesktop.prefPane
+BROKER_SERVICE_TARGET="system/org.chromium.chromoting.broker"
 
 # In case of errors, log the fact, but continue to unload launchd jobs as much
 # as possible. When finished, this preflight script should exit successfully in
@@ -122,7 +124,15 @@
 done
 
 logger Unloading broker service
-launchctl unload -w $BROKER_PLIST
+logger launchctl bootout $BROKER_SERVICE_TARGET
+launchctl bootout $BROKER_SERVICE_TARGET
+
+# Processes such as the native messaging hosts may keep running after the
+# binaries get updated, causing unexpected issues. So we kill them to prevent
+# the issues.
+logger Killing all processes in $HOST_BUNDLE_PATH
+logger pkill -9 -f "^$HOST_BUNDLE_PATH"'.*$'
+pkill -9 -f "^$HOST_BUNDLE_PATH"'.*$'
 
 # The installer no longer includes a preference-pane applet, so remove any
 # pref-pane from a previous installation.
diff --git a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
index e0e3424..09d5b0b1 100644
--- a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
+++ b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
@@ -14,6 +14,7 @@
 
 #include "base/mac/authorization_util.h"
 #include "base/mac/scoped_authorizationref.h"
+#include "base/strings/stringprintf.h"
 #include "remoting/host/mac/constants_mac.h"
 
 void logOutput(FILE* pipe) {
@@ -116,12 +117,18 @@
     [self runCommand:launchCtl withArguments:argsUnload];
   }
 
-  if ([NSFileManager.defaultManager
-          fileExistsAtPath:@(remoting::kBrokerPlistPath)]) {
-    const char* argsUnload[] = {"unload", "-w", remoting::kBrokerPlistPath,
-                                nullptr};
-    [self sudoCommand:launchCtl withArguments:argsUnload usingAuth:authRef];
-  }
+  const char* argsUnloadBroker[] = {"bootout", remoting::kBrokerServiceTarget,
+                                    nullptr};
+  [self sudoCommand:launchCtl withArguments:argsUnloadBroker usingAuth:authRef];
+}
+
+- (void)killAllRemotingProcessesUsingAuth:(AuthorizationRef)authRef {
+  const char* pkill = "/usr/bin/pkill";
+  std::string remoting_processes_regex =
+      base::StringPrintf("^%s.*$", remoting::kHostBinaryPath);
+  const char* argsPkill[] = {"-9", "-f", remoting_processes_regex.data(),
+                             nullptr};
+  [self sudoCommand:pkill withArguments:argsPkill usingAuth:authRef];
 }
 
 - (void)keystoneUnregisterUsingAuth:(AuthorizationRef)authRef {
@@ -156,6 +163,7 @@
   [self sudoDelete:remoting::kHostEnabledPath usingAuth:authRef];
 
   [self shutdownServiceUsingAuth:authRef];
+  [self killAllRemotingProcessesUsingAuth:authRef];
 
   [self sudoDelete:remoting::kServicePlistPath usingAuth:authRef];
   [self sudoDelete:remoting::kBrokerPlistPath usingAuth:authRef];
diff --git a/remoting/host/mac/constants_mac.cc b/remoting/host/mac/constants_mac.cc
index bbe7f5ca..1d130c3 100644
--- a/remoting/host/mac/constants_mac.cc
+++ b/remoting/host/mac/constants_mac.cc
@@ -63,4 +63,6 @@
 const char kUnbrandedUninstallerPath[] =
     APPLICATIONS_DIR "Chromoting Host Uninstaller.app";
 
+const char kBrokerServiceTarget[] = "system/" BROKER_NAME;
+
 }  // namespace remoting
diff --git a/remoting/host/mac/constants_mac.h b/remoting/host/mac/constants_mac.h
index ab9b74f2..a3f7605 100644
--- a/remoting/host/mac/constants_mac.h
+++ b/remoting/host/mac/constants_mac.h
@@ -67,6 +67,10 @@
 extern const char kBrandedUninstallerPath[];
 extern const char kUnbrandedUninstallerPath[];
 
+// The launchctl service target (domain_target/service_name) that can be used to
+// unload the broker service.
+extern const char kBrokerServiceTarget[];
+
 }  // namespace remoting
 
 #endif  // REMOTING_HOST_MAC_CONSTANTS_MAC_H_
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 9bba43c..3b658cc 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -161,6 +161,7 @@
       "$google_play_services_package:google_play_services_base_java",
       "$google_play_services_package:google_play_services_basement_java",
       "$google_play_services_package:google_play_services_location_java",
+      "$google_play_services_package:google_play_services_tasks_java",
       "$google_play_services_package:google_play_services_vision_common_java",
       "$google_play_services_package:google_play_services_vision_java",
       "//base:base_java",
diff --git a/services/audio/public/cpp/debug_recording_mojom_traits.cc b/services/audio/public/cpp/debug_recording_mojom_traits.cc
index 3f3dd7f..3d1b2220 100644
--- a/services/audio/public/cpp/debug_recording_mojom_traits.cc
+++ b/services/audio/public/cpp/debug_recording_mojom_traits.cc
@@ -15,6 +15,8 @@
       return audio::mojom::DebugRecordingStreamType::kInput;
     case media::AudioDebugRecordingStreamType::kOutput:
       return audio::mojom::DebugRecordingStreamType::kOutput;
+    case media::AudioDebugRecordingStreamType::kLoopback:
+      return audio::mojom::DebugRecordingStreamType::kLoopback;
   }
   NOTREACHED();
 }
@@ -30,6 +32,9 @@
     case audio::mojom::DebugRecordingStreamType::kOutput:
       *out = media::AudioDebugRecordingStreamType::kOutput;
       return true;
+    case audio::mojom::DebugRecordingStreamType::kLoopback:
+      *out = media::AudioDebugRecordingStreamType::kLoopback;
+      return true;
   }
   NOTREACHED();
 }
diff --git a/services/audio/public/cpp/debug_recording_session.cc b/services/audio/public/cpp/debug_recording_session.cc
index f8e4c1c..e1c31fd 100644
--- a/services/audio/public/cpp/debug_recording_session.cc
+++ b/services/audio/public/cpp/debug_recording_session.cc
@@ -30,6 +30,8 @@
       return FILE_PATH_LITERAL("input");
     case media::AudioDebugRecordingStreamType::kOutput:
       return FILE_PATH_LITERAL("output");
+    case media::AudioDebugRecordingStreamType::kLoopback:
+      return FILE_PATH_LITERAL("loopback");
   }
   NOTREACHED();
 }
diff --git a/services/audio/public/mojom/debug_recording.mojom b/services/audio/public/mojom/debug_recording.mojom
index 995a9b2..0f15025 100644
--- a/services/audio/public/mojom/debug_recording.mojom
+++ b/services/audio/public/mojom/debug_recording.mojom
@@ -10,6 +10,7 @@
 enum DebugRecordingStreamType {
   kInput = 0,
   kOutput = 1,
+  kLoopback = 2,
 };
 
 // Implemented by the browser process to create audio debug recording files on
diff --git a/services/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java b/services/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java
index c77f388..c125985 100644
--- a/services/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java
+++ b/services/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java
@@ -13,15 +13,11 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.build.annotations.NullMarked;
 
-import java.util.concurrent.FutureTask;
-
 /**
- * Implements the Java side of LocationProviderAndroid.
- * Delegates all real functionality to the implementation
- * returned from LocationProviderFactory.
- * See detailed documentation on
- * content/browser/geolocation/location_api_adapter_android.h.
- * Based on android.webkit.GeolocationService.java
+ * Implements the Java side of LocationProviderAndroid. Delegates all real functionality to the
+ * implementation returned from LocationProviderFactory. See detailed documentation on
+ * content/browser/geolocation/location_api_adapter_android.h. Based on
+ * android.webkit.GeolocationService.java
  */
 @NullMarked
 public class LocationProviderAdapter {
@@ -41,35 +37,18 @@
 
     /**
      * Start listening for location updates until we're told to quit. May be called in any thread.
+     *
      * @param enableHighAccuracy Whether or not to enable high accuracy location providers.
      */
     @CalledByNative
     public void start(final boolean enableHighAccuracy) {
-        FutureTask<Void> task =
-                new FutureTask<Void>(
-                        new Runnable() {
-                            @Override
-                            public void run() {
-                                mImpl.start(enableHighAccuracy);
-                            }
-                        },
-                        null);
-        ThreadUtils.runOnUiThread(task);
+        ThreadUtils.runOnUiThread(() -> mImpl.start(enableHighAccuracy));
     }
 
     /** Stop listening for location updates. May be called in any thread. */
     @CalledByNative
     public void stop() {
-        FutureTask<Void> task =
-                new FutureTask<Void>(
-                        new Runnable() {
-                            @Override
-                            public void run() {
-                                mImpl.stop();
-                            }
-                        },
-                        null);
-        ThreadUtils.runOnUiThread(task);
+        ThreadUtils.runOnUiThread(mImpl::stop);
     }
 
     /**
diff --git a/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java b/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java
index 66c750fd..ff607aa 100644
--- a/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java
+++ b/services/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java
@@ -7,11 +7,16 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.location.LocationManager;
 
 import com.google.android.gms.location.FusedLocationProviderClient;
+import com.google.android.gms.location.LocationCallback;
+import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.tasks.Tasks;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -137,6 +142,9 @@
         Context context = Mockito.mock(Context.class);
         FusedLocationProviderClient fusedLocationProviderClient =
                 Mockito.mock(FusedLocationProviderClient.class);
+        when(fusedLocationProviderClient.requestLocationUpdates(
+                        (LocationRequest) any(), (LocationCallback) any(), any()))
+                .thenReturn(Tasks.forCanceled());
 
         LocationProviderGmsCore locationProviderGmsCore =
                 new LocationProviderGmsCore(context, fusedLocationProviderClient);
diff --git a/services/network/http_cache_data_counter_unittest.cc b/services/network/http_cache_data_counter_unittest.cc
index 0f8e558..cbdbd96 100644
--- a/services/network/http_cache_data_counter_unittest.cc
+++ b/services/network/http_cache_data_counter_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "services/network/http_cache_data_counter.h"
 
 #include <algorithm>
@@ -113,7 +108,7 @@
 
       auto io_buf =
           base::MakeRefCounted<net::IOBufferWithSize>(test_entry.size);
-      std::fill(io_buf->data(), io_buf->data() + test_entry.size, 0);
+      std::ranges::fill(io_buf->span(), 0);
 
       net::TestCompletionCallback write_data_callback;
       int rv = entry->WriteData(1, 0, io_buf.get(), test_entry.size,
diff --git a/services/network/mdns_responder_unittest.cc b/services/network/mdns_responder_unittest.cc
index 1897e6b..2e339e74 100644
--- a/services/network/mdns_responder_unittest.cc
+++ b/services/network/mdns_responder_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "services/network/mdns_responder.h"
 
 #include <array>
@@ -134,11 +129,9 @@
       /*validate_records=*/true,
       /*validate_names_as_internet_hostnames=*/false);
   DCHECK(response_cache_flush.io_buffer() != nullptr);
-  buf = base::MakeRefCounted<net::IOBufferWithSize>(
+  base::span<uint8_t> response_bytes = response_cache_flush.io_buffer()->first(
       response_cache_flush.io_buffer_size());
-  memcpy(buf->data(), response_cache_flush.io_buffer()->data(),
-         response_cache_flush.io_buffer_size());
-  return std::string(buf->data(), buf->size());
+  return std::string(base::as_string_view(response_bytes));
 }
 
 // A mock mDNS socket factory to create sockets that can fail sending or
diff --git a/services/network/public/cpp/cors/cors_unittest.cc b/services/network/public/cpp/cors/cors_unittest.cc
index dd92276..8599602 100644
--- a/services/network/public/cpp/cors/cors_unittest.cc
+++ b/services/network/public/cpp/cors/cors_unittest.cc
@@ -2,15 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "services/network/public/cpp/cors/cors.h"
 
 #include <limits.h>
 
+#include <algorithm>
+
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
@@ -240,17 +237,15 @@
   EXPECT_TRUE(IsCorsSafelistedHeader("accept", "text/html"));
   EXPECT_TRUE(IsCorsSafelistedHeader("AccepT", "text/html"));
 
-  constexpr char kAllowed[] =
+  constexpr std::string_view kAllowed =
       "\t !#$%&'*+,-./0123456789;="
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
   for (int i = 0; i < 128; ++i) {
     SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
     char c = static_cast<char>(i);
-    // 1 for the trailing null character.
-    auto* end = kAllowed + std::size(kAllowed) - 1;
-    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+    EXPECT_EQ(std::ranges::find(kAllowed, c) != kAllowed.end(),
               IsCorsSafelistedHeader("accept", std::string(1, c)));
-    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+    EXPECT_EQ(std::ranges::find(kAllowed, c) != kAllowed.end(),
               IsCorsSafelistedHeader("AccepT", std::string(1, c)));
   }
   for (int i = 128; i <= 255; ++i) {
@@ -270,14 +265,12 @@
   EXPECT_TRUE(IsCorsSafelistedHeader("accept-language", "en,ja"));
   EXPECT_TRUE(IsCorsSafelistedHeader("aCcEPT-lAngUAge", "en,ja"));
 
-  constexpr char kAllowed[] =
+  constexpr std::string_view kAllowed =
       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz *,-.;=";
   for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
     SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
     char c = static_cast<char>(i);
-    // 1 for the trailing null character.
-    auto* end = kAllowed + std::size(kAllowed) - 1;
-    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+    EXPECT_EQ(std::ranges::find(kAllowed, c) != kAllowed.end(),
               IsCorsSafelistedHeader("aCcEPT-lAngUAge", std::string(1, c)));
   }
   EXPECT_TRUE(IsCorsSafelistedHeader("accept-language", std::string(128, 'a')));
@@ -329,16 +322,14 @@
   EXPECT_TRUE(IsCorsSafelistedHeader("content-language", "en,ja"));
   EXPECT_TRUE(IsCorsSafelistedHeader("cONTent-LANguaGe", "en,ja"));
 
-  constexpr char kAllowed[] =
+  constexpr std::string_view kAllowed =
       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz *,-.;=";
   for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
     SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
     char c = static_cast<char>(i);
-    // 1 for the trailing null character.
-    auto* end = kAllowed + std::size(kAllowed) - 1;
-    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+    EXPECT_EQ(std::ranges::find(kAllowed, c) != kAllowed.end(),
               IsCorsSafelistedHeader("content-language", std::string(1, c)));
-    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+    EXPECT_EQ(std::ranges::find(kAllowed, c) != kAllowed.end(),
               IsCorsSafelistedHeader("cONTent-LANguaGe", std::string(1, c)));
   }
   EXPECT_TRUE(
@@ -352,15 +343,13 @@
 }
 
 TEST_F(CorsTest, SafelistedContentType) {
-  constexpr char kAllowed[] =
+  constexpr std::string_view kAllowed =
       "\t !#$%&'*+,-./0123456789;="
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
   for (int i = 0; i < 128; ++i) {
     SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
     const char c = static_cast<char>(i);
-    // 1 for the trailing null character.
-    const auto* const end = kAllowed + std::size(kAllowed) - 1;
-    const bool is_allowed = std::find(kAllowed, end, c) != end;
+    const bool is_allowed = std::ranges::find(kAllowed, c) != kAllowed.end();
     const std::string value = std::string("text/plain; charset=") + c;
 
     EXPECT_EQ(is_allowed, IsCorsSafelistedHeader("content-type", value));
diff --git a/services/network/public/cpp/integrity_policy.cc b/services/network/public/cpp/integrity_policy.cc
index 7a0298a..d33bb58 100644
--- a/services/network/public/cpp/integrity_policy.cc
+++ b/services/network/public/cpp/integrity_policy.cc
@@ -14,5 +14,6 @@
 
 IntegrityPolicy::IntegrityPolicy(const IntegrityPolicy&) = default;
 IntegrityPolicy& IntegrityPolicy::operator=(const IntegrityPolicy&) = default;
+bool IntegrityPolicy::operator==(const IntegrityPolicy&) const = default;
 
 }  // namespace network
diff --git a/services/network/public/cpp/integrity_policy.h b/services/network/public/cpp/integrity_policy.h
index c00413a..0aaa3812da 100644
--- a/services/network/public/cpp/integrity_policy.h
+++ b/services/network/public/cpp/integrity_policy.h
@@ -29,6 +29,8 @@
   IntegrityPolicy(const IntegrityPolicy&);
   IntegrityPolicy& operator=(const IntegrityPolicy&);
 
+  bool operator==(const IntegrityPolicy&) const;
+
   std::vector<mojom::IntegrityPolicy_Destination> blocked_destinations;
   std::vector<mojom::IntegrityPolicy_Source> sources;
   std::vector<std::string> endpoints;
diff --git a/services/network/public/cpp/parsed_headers.cc b/services/network/public/cpp/parsed_headers.cc
index 4da15c7..3bd2c9c 100644
--- a/services/network/public/cpp/parsed_headers.cc
+++ b/services/network/public/cpp/parsed_headers.cc
@@ -26,6 +26,8 @@
 #include "services/network/public/cpp/document_isolation_policy_parser.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/fence_event_reporting_parser.h"
+#include "services/network/public/cpp/integrity_policy.h"
+#include "services/network/public/cpp/integrity_policy_parser.h"
 #include "services/network/public/cpp/link_header_parser.h"
 #include "services/network/public/cpp/no_vary_search_header_parser.h"
 #include "services/network/public/cpp/origin_agent_cluster_parser.h"
@@ -56,6 +58,14 @@
   parsed_headers->document_isolation_policy =
       ParseDocumentIsolationPolicy(*headers);
 
+  if (base::FeatureList::IsEnabled(network::features::kIntegrityPolicyScript)) {
+    parsed_headers->integrity_policy = ParseIntegrityPolicyFromHeaders(
+        *headers, IntegrityPolicyHeaderType::kEnforce);
+    parsed_headers->integrity_policy_report_only =
+        ParseIntegrityPolicyFromHeaders(*headers,
+                                        IntegrityPolicyHeaderType::kReportOnly);
+  }
+
   std::string origin_agent_cluster =
       headers->GetNormalizedHeader("Origin-Agent-Cluster")
           .value_or(std::string());
diff --git a/services/network/public/cpp/parsed_headers_unittest.cc b/services/network/public/cpp/parsed_headers_unittest.cc
index a04cb06..bf8b36c 100644
--- a/services/network/public/cpp/parsed_headers_unittest.cc
+++ b/services/network/public/cpp/parsed_headers_unittest.cc
@@ -363,5 +363,20 @@
       ::testing::Optional(::testing::ElementsAre("logged_in", "user_lang")));
 }
 
+TEST(ParsedHeadersTest, IntegrityPolicy) {
+  base::test::ScopedFeatureList enable{features::kIntegrityPolicyScript};
+  const std::string_view headers =
+      "HTTP/1.1 200 OK\r\n"
+      "Integrity-Policy: blocked-destinations=(script)\r\n"
+      "Integrity-Policy-Report-Only: blocked-destinations=(script)\r\n\r\n";
+  const auto parsed_headers = ParseHeaders(headers);
+
+  ASSERT_TRUE(parsed_headers);
+  EXPECT_EQ(parsed_headers->integrity_policy.blocked_destinations.size(), 1u);
+  EXPECT_EQ(
+      parsed_headers->integrity_policy_report_only.blocked_destinations.size(),
+      1u);
+}
+
 }  // namespace
 }  // namespace network
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc
index d1825e6..6648eec 100644
--- a/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "services/network/public/cpp/simple_url_loader.h"
 
 #include <stdint.h>
diff --git a/services/network/public/mojom/parsed_headers.mojom b/services/network/public/mojom/parsed_headers.mojom
index 6173c821..0ed1479 100644
--- a/services/network/public/mojom/parsed_headers.mojom
+++ b/services/network/public/mojom/parsed_headers.mojom
@@ -7,6 +7,7 @@
 import "services/network/public/mojom/content_security_policy.mojom";
 import "services/network/public/mojom/cross_origin_embedder_policy.mojom";
 import "services/network/public/mojom/cross_origin_opener_policy.mojom";
+import "services/network/public/mojom/integrity_policy.mojom";
 import "services/network/public/mojom/document_isolation_policy.mojom";
 import "services/network/public/mojom/link_header.mojom";
 import "services/network/public/mojom/no_vary_search.mojom";
@@ -44,6 +45,11 @@
   // Document-Isolation-Policy-Report-Only headers.
   DocumentIsolationPolicy document_isolation_policy;
 
+  // The parsed value of the Integrity-Policy header.
+  IntegrityPolicy integrity_policy;
+  // The parsed value of the Integrity-Policy-Report-Only header.
+  IntegrityPolicy integrity_policy_report_only;
+
   // The parsed value of the Origin-Agent-Cluster header.
   OriginAgentClusterValue origin_agent_cluster;
 
diff --git a/services/network/shared_dictionary/shared_dictionary_on_disk_unittest.cc b/services/network/shared_dictionary/shared_dictionary_on_disk_unittest.cc
index ed22d44..8e40099 100644
--- a/services/network/shared_dictionary/shared_dictionary_on_disk_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_on_disk_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "services/network/shared_dictionary/shared_dictionary_on_disk.h"
 
 #include "base/run_loop.h"
@@ -113,7 +108,7 @@
       .Run(disk_cache::EntryResult::MakeOpened(entry.release()));
   ASSERT_TRUE(buffer);
   ASSERT_TRUE(read_all_callback);
-  memcpy(buffer->data(), kTestData.c_str(), kTestData.size());
+  buffer->span().copy_prefix_from(base::as_byte_span(kTestData));
   std::move(read_all_callback).Run(base::checked_cast<int>(expected_size));
   EXPECT_TRUE(read_all_finished);
   EXPECT_EQ(kTestData,
@@ -173,7 +168,7 @@
 
   ASSERT_TRUE(buffer);
   ASSERT_TRUE(read_all_callback);
-  memcpy(buffer->data(), kTestData.c_str(), kTestData.size());
+  buffer->span().copy_prefix_from(base::as_byte_span(kTestData));
   std::move(read_all_callback).Run(base::checked_cast<int>(expected_size));
   EXPECT_TRUE(read_all_finished);
   EXPECT_EQ(kTestData,
@@ -214,7 +209,7 @@
         EXPECT_EQ(1, index);
         EXPECT_EQ(0, offset);
         EXPECT_EQ(base::checked_cast<int>(expected_size), buf_len);
-        memcpy(buf->data(), kTestData.c_str(), kTestData.size());
+        buf->span().copy_prefix_from(base::as_byte_span(kTestData));
         return base::checked_cast<int>(expected_size);
       });
 
@@ -264,7 +259,7 @@
         EXPECT_EQ(1, index);
         EXPECT_EQ(0, offset);
         EXPECT_EQ(base::checked_cast<int>(expected_size), buf_len);
-        memcpy(buf->data(), kTestData.c_str(), kTestData.size());
+        buf->span().copy_prefix_from(base::as_byte_span(kTestData));
         return base::checked_cast<int>(expected_size);
       });
 
diff --git a/services/network/tls_client_socket_unittest.cc b/services/network/tls_client_socket_unittest.cc
index 9456f70..13c5d21 100644
--- a/services/network/tls_client_socket_unittest.cc
+++ b/services/network/tls_client_socket_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <stdint.h>
 
 #include <string>
@@ -53,8 +48,8 @@
 const size_t kMsgSize = strlen(kMsg);
 
 // Message sent over the tls connection.
-const char kSecretMsg[] = "here is secret.";
-const size_t kSecretMsgSize = strlen(kSecretMsg);
+constexpr std::string_view kSecretMsg = "here is secret.";
+constexpr size_t kSecretMsgSize = kSecretMsg.size();
 
 class TLSClientSocketTestBase {
  public:
@@ -578,8 +573,8 @@
 
   EXPECT_EQ(MOJO_RESULT_OK,
             post_tls_send_handle()->get().WriteData(
-                base::byte_span_from_cstring(kSecretMsg),
-                MOJO_WRITE_DATA_FLAG_NONE, actually_written_bytes));
+                base::as_byte_span(kSecretMsg), MOJO_WRITE_DATA_FLAG_NONE,
+                actually_written_bytes));
   EXPECT_EQ(kSecretMsg, Read(post_tls_recv_handle(), kSecretMsgSize));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(ssl_socket.ConnectDataConsumed());
@@ -619,8 +614,8 @@
   size_t actually_written_bytes = 0;
   EXPECT_EQ(MOJO_RESULT_OK,
             post_tls_send_handle()->get().WriteData(
-                base::byte_span_from_cstring(kSecretMsg),
-                MOJO_WRITE_DATA_FLAG_NONE, actually_written_bytes));
+                base::as_byte_span(kSecretMsg), MOJO_WRITE_DATA_FLAG_NONE,
+                actually_written_bytes));
   EXPECT_EQ(kSecretMsg, Read(post_tls_recv_handle(), kSecretMsgSize));
   EXPECT_EQ(net::ERR_CONNECTION_CLOSED,
             post_tls_observer()->WaitForReadError());
@@ -661,8 +656,8 @@
   size_t actually_written_bytes = 0;
   EXPECT_EQ(MOJO_RESULT_OK,
             post_tls_send_handle()->get().WriteData(
-                base::byte_span_from_cstring(kSecretMsg),
-                MOJO_WRITE_DATA_FLAG_NONE, actually_written_bytes));
+                base::as_byte_span(kSecretMsg), MOJO_WRITE_DATA_FLAG_NONE,
+                actually_written_bytes));
   EXPECT_EQ(net::ERR_CONNECTION_CLOSED,
             post_tls_observer()->WaitForWriteError());
 
@@ -710,8 +705,8 @@
   size_t actually_written_bytes = 0;
   EXPECT_EQ(MOJO_RESULT_OK,
             post_tls_send_handle()->get().WriteData(
-                base::byte_span_from_cstring(kSecretMsg),
-                MOJO_WRITE_DATA_FLAG_NONE, actually_written_bytes));
+                base::as_byte_span(kSecretMsg), MOJO_WRITE_DATA_FLAG_NONE,
+                actually_written_bytes));
   EXPECT_EQ(kSecretMsg, Read(post_tls_recv_handle(), kSecretMsgSize));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(ssl_socket.ConnectDataConsumed());
@@ -760,8 +755,8 @@
 
   EXPECT_EQ(MOJO_RESULT_OK,
             post_tls_send_handle()->get().WriteData(
-                base::byte_span_from_cstring(kSecretMsg),
-                MOJO_WRITE_DATA_FLAG_NONE, actually_written_bytes));
+                base::as_byte_span(kSecretMsg), MOJO_WRITE_DATA_FLAG_NONE,
+                actually_written_bytes));
   EXPECT_EQ(kSecretMsg, Read(post_tls_recv_handle(), kSecretMsgSize));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(ssl_socket.ConnectDataConsumed());
@@ -811,8 +806,8 @@
 
   EXPECT_EQ(MOJO_RESULT_OK,
             post_tls_send_handle()->get().WriteData(
-                base::byte_span_from_cstring(kSecretMsg),
-                MOJO_WRITE_DATA_FLAG_NONE, actually_written_bytes));
+                base::as_byte_span(kSecretMsg), MOJO_WRITE_DATA_FLAG_NONE,
+                actually_written_bytes));
   EXPECT_EQ(kSecretMsg, Read(post_tls_recv_handle(), kSecretMsgSize));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(ssl_socket.ConnectDataConsumed());
@@ -1038,7 +1033,7 @@
       size_t actually_written_bytes = 0;
       EXPECT_EQ(MOJO_RESULT_OK,
                 post_tls_send_handle()->get().WriteData(
-                    base::byte_span_from_cstring(kSecretMsg).subspan(i, 1u),
+                    base::as_byte_span(kSecretMsg).subspan(i, 1u),
                     MOJO_WRITE_DATA_FLAG_NONE, actually_written_bytes));
       // Flush the 1 byte write.
       base::RunLoop().RunUntilIdle();
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index c22f2654..70005e0e 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "services/network/url_loader.h"
 
 #include <stdint.h>
 
+#include <algorithm>
 #include <limits>
 #include <list>
 #include <memory>
@@ -29,6 +25,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/no_destructor.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/escape.h"
@@ -250,7 +247,7 @@
       std::string packet = packets_.front();
       packets_.pop_front();
       CHECK_GE(buf_size, static_cast<int>(packet.length()));
-      memcpy(buf->data(), packet.c_str(), packet.length());
+      buf->span().copy_prefix_from(base::as_byte_span(packet));
       result = packet.length();
     }
 
@@ -330,7 +327,7 @@
   int ReadRawData(net::IOBuffer* buf, int buf_size) override {
     DCHECK_GT(buf_size, 0);
     if (fill_entire_buffer_) {
-      memset(buf->data(), 'a', buf_size);
+      std::ranges::fill(buf->first(base::checked_cast<size_t>(buf_size)), 'a');
       return buf_size;
     }
 
@@ -419,7 +416,7 @@
 
     // Pretend this is the entire network stack, which has sent the buffer
     // to some worker thread to be written to disk.
-    memset(buf->data(), 'a', buf_size);
+    std::ranges::fill(buf->first(base::checked_cast<size_t>(buf_size)), 'a');
     *simulated_cache_dest_ = buf;
 
     // The network stack will not report the read result until the write
diff --git a/services/viz/public/mojom/compositing/layer.mojom b/services/viz/public/mojom/compositing/layer.mojom
index e9e66e7..1275ca0d 100644
--- a/services/viz/public/mojom/compositing/layer.mojom
+++ b/services/viz/public/mojom/compositing/layer.mojom
@@ -31,6 +31,11 @@
 struct RareProperties {
   cc.mojom.FilterQuality filter_quality = cc.mojom.FilterQuality.kLow;
 
+  // NOTE: Instances of this struct are initialized by reading the
+  // corresponding instances of the C++-level struct, and thus no explicit
+  // default value is needed here.
+  cc.mojom.DynamicRangeLimit dynamic_range_limit;
+
   // The bounds of elements marked for potential region capture, stored in
   // the coordinate space of this layer.
   // NOTE: This field has no explicitly-set default value in the C++ struct.
diff --git a/services/webnn/coreml/graph_builder_coreml.h b/services/webnn/coreml/graph_builder_coreml.h
index f6b8cf3..e85bcb6 100644
--- a/services/webnn/coreml/graph_builder_coreml.h
+++ b/services/webnn/coreml/graph_builder_coreml.h
@@ -184,13 +184,13 @@
     base::expected<void, mojom::ErrorPtr> WeightItemFinalize(size_t byte_size);
 
     base::File weights_file_;
-    OperandId current_offset_ = 0;
+    uint64_t current_offset_ = 0;
     uint32_t num_of_weights_ = 0;
     base::TimeDelta weights_write_time_;
     bool has_error_ = false;
     bool finalized_ = false;
     // Maps operand IDs to offsets in the weight file.
-    base::flat_map<OperandId, OperandId> constant_offsets_;
+    base::flat_map<OperandId, uint64_t> constant_offsets_;
   };
 
   GraphBuilderCoreml(
diff --git a/services/webnn/webnn_graph_builder_impl.cc b/services/webnn/webnn_graph_builder_impl.cc
index 375a63d..e42b390 100644
--- a/services/webnn/webnn_graph_builder_impl.cc
+++ b/services/webnn/webnn_graph_builder_impl.cc
@@ -1591,7 +1591,7 @@
     return false;
   }
 
-  const std::optional<uint32_t>& bias_operand_id = gru_cell.bias_operand_id;
+  const std::optional<OperandId>& bias_operand_id = gru_cell.bias_operand_id;
   if (bias_operand_id.has_value()) {
     if (!id_to_operand_map_->contains(bias_operand_id.value()) ||
         !processed_operands_.contains(gru_cell.bias_operand_id)) {
@@ -1599,7 +1599,7 @@
     }
     NoteInputDependency(bias_operand_id.value(), operation_id);
   }
-  const std::optional<uint32_t>& recurrent_bias_operand_id =
+  const std::optional<OperandId>& recurrent_bias_operand_id =
       gru_cell.recurrent_bias_operand_id;
   if (recurrent_bias_operand_id.has_value()) {
     if (!id_to_operand_map_->contains(recurrent_bias_operand_id.value()) ||
diff --git a/storage/browser/blob/blob_data_item.cc b/storage/browser/blob/blob_data_item.cc
index e878100..48d33db 100644
--- a/storage/browser/blob/blob_data_item.cc
+++ b/storage/browser/blob/blob_data_item.cc
@@ -84,15 +84,6 @@
 // static
 scoped_refptr<BlobDataItem> BlobDataItem::CreateFile(
     base::FilePath path,
-    file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
-        file_access) {
-  return CreateFile(path, 0, blink::BlobUtils::kUnknownSize, base::Time(),
-                    nullptr, std::move(file_access));
-}
-
-// static
-scoped_refptr<BlobDataItem> BlobDataItem::CreateFile(
-    base::FilePath path,
     uint64_t offset,
     uint64_t length,
     base::Time expected_modification_time,
diff --git a/storage/browser/blob/blob_data_item.h b/storage/browser/blob/blob_data_item.h
index dfa2128..dccf568 100644
--- a/storage/browser/blob/blob_data_item.h
+++ b/storage/browser/blob/blob_data_item.h
@@ -88,10 +88,6 @@
   static scoped_refptr<BlobDataItem> CreateBytesDescription(size_t length);
   static scoped_refptr<BlobDataItem> CreateFile(
       base::FilePath path,
-      file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
-          file_access = base::NullCallback());
-  static scoped_refptr<BlobDataItem> CreateFile(
-      base::FilePath path,
       uint64_t offset,
       uint64_t length,
       base::Time expected_modification_time = base::Time(),
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index deb35c1..6aae15b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1718,21 +1718,6 @@
             ]
         }
     ],
-    "AutofillDynamicallyLoadsFieldsForAddressInput": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "AutofillDynamicallyLoadsFieldsForAddressInput"
-                    ]
-                }
-            ]
-        }
-    ],
     "AutofillEnableBuyNowPayLaterDesktop": [
         {
             "platforms": [
@@ -3048,28 +3033,6 @@
             ]
         }
     ],
-    "BackgroundTabLoadingFromPerformanceManager": [
-        {
-            "platforms": [
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledWithMainFrameState",
-                    "params": {
-                        "min_site_engagement": "15",
-                        "restore_main_frame_state": "true"
-                    },
-                    "enable_features": [
-                        "BackgroundTabLoadingFromPerformanceManager"
-                    ]
-                }
-            ]
-        }
-    ],
     "BatchNativeEventsInMessagePumpEpoll": [
         {
             "platforms": [
@@ -7845,21 +7808,6 @@
             ]
         }
     ],
-    "DisableListTabSwitcher": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DisableListTabSwitcher"
-                    ]
-                }
-            ]
-        }
-    ],
     "DisableMemoryReclaimerInBackground": [
         {
             "platforms": [
@@ -12548,6 +12496,26 @@
             ]
         }
     ],
+    "IntegrityPolicyScript": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "IntegrityPolicyScript"
+                    ]
+                }
+            ]
+        }
+    ],
     "InvalidateSearchEngineChoiceOnDeviceRestoreDetection": [
         {
             "platforms": [
@@ -13517,6 +13485,27 @@
             ]
         }
     ],
+    "LocalNetworkAccessChecks": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "EnabledWarning",
+                    "params": {
+                        "LocalNetworkAccessChecksWarn": "true"
+                    },
+                    "enable_features": [
+                        "LocalNetworkAccessChecks"
+                    ]
+                }
+            ]
+        }
+    ],
     "LocalWebApprovalsIos": [
         {
             "platforms": [
@@ -16469,7 +16458,7 @@
                         "hats_survey_ukm_id": "1027171324",
                         "ppm_survey_segment_name1": "ChromeOS",
                         "ppm_survey_uniform_sample": "true",
-                        "probability": "0.88",
+                        "probability": "0.088",
                         "survey": "performance-ppm"
                     },
                     "enable_features": [
@@ -21925,7 +21914,8 @@
                         "ShopCardVariant": "arm_3"
                     },
                     "enable_features": [
-                        "ShopCard"
+                        "ShopCard",
+                        "ShopCardImpressionLimits"
                     ]
                 }
             ]
@@ -23813,23 +23803,6 @@
             ]
         }
     ],
-    "UseContextSnapshot": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "android_weblayer"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "UseContextSnapshot"
-                    ]
-                }
-            ]
-        }
-    ],
     "UseDMSAAForTiles": [
         {
             "platforms": [
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn
index cf8f1d66..6bd58b02 100644
--- a/third_party/android_deps/BUILD.gn
+++ b/third_party/android_deps/BUILD.gn
@@ -201,194 +201,6 @@
   }
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt(
-        "google_android_datatransport_transport_backend_cct_java") {
-      aar_path = "cipd/libs/com_google_android_datatransport_transport_backend_cct/transport-backend-cct-4.0.0.aar"
-      info_path = "libs/com_google_android_datatransport_transport_backend_cct/com_google_android_datatransport_transport_backend_cct.info"
-      enable_bytecode_checks = false
-      deps = [
-        ":google_android_datatransport_transport_api_java",
-        ":google_android_datatransport_transport_runtime_java",
-        "$google_play_services_package:google_firebase_firebase_encoders_java",
-        "$google_play_services_package:google_firebase_firebase_encoders_json_java",
-        "//third_party/androidx:androidx_annotation_annotation_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_cast_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_cast/play-services-cast-22.0.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_cast/com_google_android_gms_play_services_cast.info"
-      enable_bytecode_checks = false
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_flags_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-        "//third_party/androidx:androidx_core_core_java",
-        "//third_party/androidx:androidx_mediarouter_mediarouter_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_cast_framework_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_cast_framework/play-services-cast-framework-22.0.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_cast_framework/com_google_android_gms_play_services_cast_framework.info"
-      enable_bytecode_checks = false
-      deps = [
-        ":google_android_datatransport_transport_api_java",
-        ":google_android_datatransport_transport_backend_cct_java",
-        ":google_android_datatransport_transport_runtime_java",
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_cast_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-        "//third_party/android_deps:guava_android_java",
-        "//third_party/androidx:androidx_appcompat_appcompat_java",
-        "//third_party/androidx:androidx_collection_collection_java",
-        "//third_party/androidx:androidx_concurrent_concurrent_futures_java",
-        "//third_party/androidx:androidx_core_core_java",
-        "//third_party/androidx:androidx_fragment_fragment_java",
-        "//third_party/androidx:androidx_media_media_java",
-        "//third_party/androidx:androidx_mediarouter_mediarouter_java",
-        "//third_party/androidx:androidx_recyclerview_recyclerview_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_gcm_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_gcm/play-services-gcm-17.0.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_gcm/com_google_android_gms_play_services_gcm.info"
-      enable_bytecode_checks = false
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_iid_java",
-        "$google_play_services_package:google_play_services_stats_java",
-        "//third_party/androidx:androidx_collection_collection_java",
-        "//third_party/androidx:androidx_core_core_java",
-        "//third_party/androidx:androidx_legacy_legacy_support_core_utils_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_iid_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_iid/play-services-iid-17.0.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_iid/com_google_android_gms_play_services_iid.info"
-      enable_bytecode_checks = false
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_stats_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-        "//third_party/androidx:androidx_collection_collection_java",
-        "//third_party/androidx:androidx_core_core_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_instantapps_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_instantapps/play-services-instantapps-18.1.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_instantapps/com_google_android_gms_play_services_instantapps.info"
-      enable_bytecode_checks = false
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_location_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_location/play-services-location-21.3.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_location/com_google_android_gms_play_services_location.info"
-      enable_bytecode_checks = false
-      deps = [
-        ":org_jetbrains_kotlinx_kotlinx_coroutines_android_java",
-        ":org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-        "//third_party/kotlin_stdlib:kotlin_stdlib_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_stats_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_stats/play-services-stats-17.1.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_stats/com_google_android_gms_play_services_stats.info"
-      enable_bytecode_checks = false
-      deps = [
-        "$google_play_services_package:google_play_services_basement_java",
-        "//third_party/androidx:androidx_legacy_legacy_support_core_utils_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_vision_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_vision/play-services-vision-20.1.3.aar"
-      info_path = "libs/com_google_android_gms_play_services_vision/com_google_android_gms_play_services_vision.info"
-      enable_bytecode_checks = false
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_vision_common_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_vision_common_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_vision_common/play-services-vision-common-19.1.3.aar"
-      info_path = "libs/com_google_android_gms_play_services_vision_common/com_google_android_gms_play_services_vision_common.info"
-      enable_bytecode_checks = false
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_clearcut_java",
-        "$google_play_services_package:google_play_services_flags_java",
-        "$google_play_services_package:google_play_services_phenotype_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (!defined(playcore_target)) {
-    android_aar_prebuilt("com_google_android_play_feature_delivery_java") {
-      aar_path = "cipd/libs/com_google_android_play_feature_delivery/feature-delivery-2.1.0.aar"
-      info_path = "libs/com_google_android_play_feature_delivery/com_google_android_play_feature_delivery.info"
-      enable_bytecode_checks = false
-
-      # Target is swapped out when internal code is enabled.
-      # Please depend on //third_party/android_deps:playcore_java instead.
-      visibility = [ "//third_party/android_deps:*" ]
-      deps = [
-        ":com_google_android_play_core_common_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   android_aar_prebuilt("com_google_ar_impress_java") {
     aar_path = "cipd/libs/com_google_ar_impress/impress-0.0.2.aar"
     info_path = "libs/com_google_ar_impress/com_google_ar_impress.info"
@@ -628,20 +440,6 @@
   }
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  java_prebuilt("org_jetbrains_kotlinx_kotlinx_coroutines_play_services_java") {
-    jar_path = "cipd/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/kotlinx-coroutines-play-services-1.10.1.jar"
-    output_name = "org_jetbrains_kotlinx_kotlinx_coroutines_play_services"
-    supports_android = true
-    requires_android = true
-    enable_bytecode_checks = false
-    deps = [
-      ":org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
-      "$google_play_services_package:google_play_services_tasks_java",
-      "//third_party/kotlin_stdlib:kotlin_stdlib_java",
-    ]
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   java_prebuilt("org_jsoup_jsoup_java") {
     jar_path = "cipd/libs/org_jsoup_jsoup/jsoup-1.15.1.jar"
     output_name = "org_jsoup_jsoup"
@@ -705,70 +503,6 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_android_datatransport_transport_api_java") {
-      aar_path = "cipd/libs/com_google_android_datatransport_transport_api/transport-api-4.0.0.aar"
-      info_path = "libs/com_google_android_datatransport_transport_api/com_google_android_datatransport_transport_api.info"
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt(
-        "google_android_datatransport_transport_runtime_java") {
-      aar_path = "cipd/libs/com_google_android_datatransport_transport_runtime/transport-runtime-4.0.0.aar"
-      info_path = "libs/com_google_android_datatransport_transport_runtime/com_google_android_datatransport_transport_runtime.info"
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [
-        ":google_android_datatransport_transport_api_java",
-        ":javax_inject_javax_inject_java",
-        "$google_play_services_package:google_firebase_firebase_encoders_java",
-        "$google_play_services_package:google_firebase_firebase_encoders_proto_java",
-        "//third_party/androidx:androidx_annotation_annotation_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_clearcut_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_clearcut/play-services-clearcut-17.0.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_clearcut/com_google_android_gms_play_services_clearcut.info"
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_phenotype_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-        "//third_party/androidx:androidx_core_core_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
     android_aar_prebuilt("google_play_services_cloud_messaging_java") {
       aar_path = "cipd/libs/com_google_android_gms_play_services_cloud_messaging/play-services-cloud-messaging-17.2.0.aar"
       info_path = "libs/com_google_android_gms_play_services_cloud_messaging/com_google_android_gms_play_services_cloud_messaging.info"
@@ -789,63 +523,6 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_flags_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_flags/play-services-flags-18.1.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_flags/com_google_android_gms_play_services_flags.info"
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_play_services_phenotype_java") {
-      aar_path = "cipd/libs/com_google_android_gms_play_services_phenotype/play-services-phenotype-17.0.0.aar"
-      info_path = "libs/com_google_android_gms_play_services_phenotype/com_google_android_gms_play_services_phenotype.info"
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [
-        "$google_play_services_package:google_play_services_base_java",
-        "$google_play_services_package:google_play_services_basement_java",
-        "$google_play_services_package:google_play_services_tasks_java",
-        "//third_party/androidx:androidx_core_core_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  android_aar_prebuilt("com_google_android_play_core_common_java") {
-    aar_path =
-        "cipd/libs/com_google_android_play_core_common/core-common-2.0.3.aar"
-    info_path = "libs/com_google_android_play_core_common/com_google_android_play_core_common.info"
-    enable_bytecode_checks = false
-
-    # To remove visibility constraint, add this dependency to
-    # //third_party/android_deps/build.gradle.
-    visibility = [
-      ":*",
-      "//third_party/androidx:*",
-    ]
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
     java_prebuilt("google_firebase_firebase_annotations_java") {
       jar_path = "cipd/libs/com_google_firebase_firebase_annotations/firebase-annotations-16.2.0.jar"
       output_name = "com_google_firebase_firebase_annotations"
@@ -934,67 +611,6 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   if (google_play_services_package == "//third_party/android_deps") {
-    java_prebuilt("google_firebase_firebase_encoders_java") {
-      jar_path = "cipd/libs/com_google_firebase_firebase_encoders/firebase-encoders-17.0.0.jar"
-      output_name = "com_google_firebase_firebase_encoders"
-      supports_android = true
-      requires_android = true
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    android_aar_prebuilt("google_firebase_firebase_encoders_json_java") {
-      aar_path = "cipd/libs/com_google_firebase_firebase_encoders_json/firebase-encoders-json-18.0.0.aar"
-      info_path = "libs/com_google_firebase_firebase_encoders_json/com_google_firebase_firebase_encoders_json.info"
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [
-        "$google_play_services_package:google_firebase_firebase_encoders_java",
-        "//third_party/androidx:androidx_annotation_annotation_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
-    java_prebuilt("google_firebase_firebase_encoders_proto_java") {
-      jar_path = "cipd/libs/com_google_firebase_firebase_encoders_proto/firebase-encoders-proto-16.0.0.jar"
-      output_name = "com_google_firebase_firebase_encoders_proto"
-      supports_android = true
-      requires_android = true
-      enable_bytecode_checks = false
-
-      # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/build.gradle.
-      visibility = [
-        ":*",
-        "//third_party/androidx:*",
-      ]
-      deps = [
-        "$google_play_services_package:google_firebase_firebase_encoders_java",
-        "//third_party/androidx:androidx_annotation_annotation_java",
-      ]
-    }
-  }
-
-  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-  if (google_play_services_package == "//third_party/android_deps") {
     android_aar_prebuilt("google_firebase_firebase_iid_interop_java") {
       aar_path = "cipd/libs/com_google_firebase_firebase_iid_interop/firebase-iid-interop-17.1.0.aar"
       info_path = "libs/com_google_firebase_firebase_iid_interop/com_google_firebase_firebase_iid_interop.info"
diff --git a/third_party/android_deps/additional_readme_paths.json b/third_party/android_deps/additional_readme_paths.json
index f0e9496..b7641585 100644
--- a/third_party/android_deps/additional_readme_paths.json
+++ b/third_party/android_deps/additional_readme_paths.json
@@ -4,24 +4,7 @@
     "libs/com_android_tools_layoutlib_layoutlib_api",
     "libs/com_android_tools_sdk_common",
     "libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework",
-    "libs/com_google_android_datatransport_transport_api",
-    "libs/com_google_android_datatransport_transport_backend_cct",
-    "libs/com_google_android_datatransport_transport_runtime",
-    "libs/com_google_android_gms_play_services_cast",
-    "libs/com_google_android_gms_play_services_cast_framework",
-    "libs/com_google_android_gms_play_services_clearcut",
     "libs/com_google_android_gms_play_services_cloud_messaging",
-    "libs/com_google_android_gms_play_services_flags",
-    "libs/com_google_android_gms_play_services_gcm",
-    "libs/com_google_android_gms_play_services_iid",
-    "libs/com_google_android_gms_play_services_instantapps",
-    "libs/com_google_android_gms_play_services_location",
-    "libs/com_google_android_gms_play_services_phenotype",
-    "libs/com_google_android_gms_play_services_stats",
-    "libs/com_google_android_gms_play_services_vision",
-    "libs/com_google_android_gms_play_services_vision_common",
-    "libs/com_google_android_play_core_common",
-    "libs/com_google_android_play_feature_delivery",
     "libs/com_google_ar_impress",
     "libs/com_google_code_gson_gson",
     "libs/com_google_dagger_dagger",
@@ -30,9 +13,6 @@
     "libs/com_google_firebase_firebase_common_ktx",
     "libs/com_google_firebase_firebase_components",
     "libs/com_google_firebase_firebase_datatransport",
-    "libs/com_google_firebase_firebase_encoders",
-    "libs/com_google_firebase_firebase_encoders_json",
-    "libs/com_google_firebase_firebase_encoders_proto",
     "libs/com_google_firebase_firebase_iid",
     "libs/com_google_firebase_firebase_iid_interop",
     "libs/com_google_firebase_firebase_installations",
@@ -53,7 +33,6 @@
     "libs/org_jetbrains_kotlin_kotlin_parcelize_runtime",
     "libs/org_jetbrains_kotlinx_atomicfu_jvm",
     "libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava",
-    "libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services",
     "libs/org_jsoup_jsoup",
     "libs/org_mockito_mockito_android",
     "libs/org_mockito_mockito_core",
diff --git a/third_party/android_deps/autorolled/BUILD.gn b/third_party/android_deps/autorolled/BUILD.gn
index c9cdcaa3f..4e5b800 100644
--- a/third_party/android_deps/autorolled/BUILD.gn
+++ b/third_party/android_deps/autorolled/BUILD.gn
@@ -30,7 +30,7 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   java_prebuilt("com_google_errorprone_error_prone_annotations_java") {
-    jar_path = "autorolled/cipd/libs/com_google_errorprone_error_prone_annotations/error_prone_annotations-2.30.0.jar"
+    jar_path = "autorolled/cipd/libs/com_google_errorprone_error_prone_annotations/error_prone_annotations-2.36.0.jar"
     output_name = "com_google_errorprone_error_prone_annotations"
     supports_android = true
     enable_bytecode_checks = false
@@ -39,14 +39,13 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   java_prebuilt("com_google_guava_guava_java") {
     jar_path =
-        "autorolled/cipd/libs/com_google_guava_guava/guava-33.3.1-jre.jar"
+        "autorolled/cipd/libs/com_google_guava_guava/guava-33.4.8-android.jar"
     output_name = "com_google_guava_guava"
     enable_bytecode_checks = false
     deps = [
-      "//third_party/android_deps:com_google_code_findbugs_jsr305_java",
       "//third_party/android_deps:com_google_errorprone_error_prone_annotations_java",
       "//third_party/android_deps:com_google_j2objc_j2objc_annotations_java",
-      "//third_party/android_deps:org_checkerframework_checker_qual_java",
+      "//third_party/android_deps:org_jspecify_jspecify_java",
     ]
 
     # Dep needed to fix:
@@ -74,6 +73,14 @@
   }
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+  java_prebuilt("org_jspecify_jspecify_java") {
+    jar_path = "autorolled/cipd/libs/org_jspecify_jspecify/jspecify-1.0.0.jar"
+    output_name = "org_jspecify_jspecify"
+    supports_android = true
+    enable_bytecode_checks = false
+  }
+
+  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   java_prebuilt("org_ow2_asm_asm_java") {
     jar_path = "autorolled/cipd/libs/org_ow2_asm_asm/asm-9.7.1.jar"
     output_name = "org_ow2_asm_asm"
@@ -114,7 +121,7 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   java_prebuilt("com_google_guava_failureaccess_java") {
-    jar_path = "autorolled/cipd/libs/com_google_guava_failureaccess/failureaccess-1.0.2.jar"
+    jar_path = "autorolled/cipd/libs/com_google_guava_failureaccess/failureaccess-1.0.3.jar"
     output_name = "com_google_guava_failureaccess"
     supports_android = true
     enable_bytecode_checks = false
@@ -141,6 +148,23 @@
   if (!limit_android_deps) {
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt(
+          "google_android_datatransport_transport_backend_cct_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_datatransport_transport_backend_cct/transport-backend-cct-4.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_datatransport_transport_backend_cct/com_google_android_datatransport_transport_backend_cct.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_firebase_firebase_encoders_java",
+          "$google_play_services_package:google_firebase_firebase_encoders_json_java",
+          "//third_party/android_deps:google_android_datatransport_transport_api_java",
+          "//third_party/android_deps:google_android_datatransport_transport_runtime_java",
+          "//third_party/androidx:androidx_annotation_annotation_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
       android_aar_prebuilt("google_play_services_auth_java") {
         aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_auth/play-services-auth-21.3.0.aar"
         info_path = "autorolled/committed/libs/com_google_android_gms_play_services_auth/com_google_android_gms_play_services_auth.info"
@@ -161,13 +185,16 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (google_play_services_package == "//third_party/android_deps") {
       android_aar_prebuilt("google_play_services_auth_api_phone_java") {
-        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_auth_api_phone/play-services-auth-api-phone-18.1.0.aar"
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_auth_api_phone/play-services-auth-api-phone-18.2.0.aar"
         info_path = "autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/com_google_android_gms_play_services_auth_api_phone.info"
         enable_bytecode_checks = false
         deps = [
           "$google_play_services_package:google_play_services_base_java",
           "$google_play_services_package:google_play_services_basement_java",
           "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
+          "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_play_services_java",
+          "//third_party/kotlin_stdlib:kotlin_stdlib_java",
         ]
       }
     }
@@ -205,13 +232,14 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (google_play_services_package == "//third_party/android_deps") {
       android_aar_prebuilt("google_play_services_base_java") {
-        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_base/play-services-base-18.5.0.aar"
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_base/play-services-base-18.7.0.aar"
         info_path = "autorolled/committed/libs/com_google_android_gms_play_services_base/com_google_android_gms_play_services_base.info"
         enable_bytecode_checks = false
         deps = [
           "$google_play_services_package:google_play_services_basement_java",
           "$google_play_services_package:google_play_services_tasks_java",
           "//third_party/androidx:androidx_collection_collection_java",
+          "//third_party/androidx:androidx_core_core_java",
           "//third_party/androidx:androidx_fragment_fragment_java",
         ]
       }
@@ -220,11 +248,12 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (google_play_services_package == "//third_party/android_deps") {
       android_aar_prebuilt("google_play_services_basement_java") {
-        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_basement/play-services-basement-18.5.0.aar"
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_basement/play-services-basement-18.7.0.aar"
         info_path = "autorolled/committed/libs/com_google_android_gms_play_services_basement/com_google_android_gms_play_services_basement.info"
         enable_bytecode_checks = false
         deps = [
           "//third_party/androidx:androidx_collection_collection_java",
+          "//third_party/androidx:androidx_core_core_java",
           "//third_party/androidx:androidx_fragment_fragment_java",
         ]
 
@@ -245,8 +274,52 @@
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_cast_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_cast/play-services-cast-22.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_cast/com_google_android_gms_play_services_cast.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_flags_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/androidx:androidx_core_core_java",
+          "//third_party/androidx:androidx_mediarouter_mediarouter_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_cast_framework_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_cast_framework/play-services-cast-framework-22.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_cast_framework/com_google_android_gms_play_services_cast_framework.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_cast_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/android_deps:google_android_datatransport_transport_api_java",
+          "//third_party/android_deps:google_android_datatransport_transport_backend_cct_java",
+          "//third_party/android_deps:google_android_datatransport_transport_runtime_java",
+          "//third_party/android_deps:guava_android_java",
+          "//third_party/androidx:androidx_appcompat_appcompat_java",
+          "//third_party/androidx:androidx_collection_collection_java",
+          "//third_party/androidx:androidx_concurrent_concurrent_futures_java",
+          "//third_party/androidx:androidx_core_core_java",
+          "//third_party/androidx:androidx_fragment_fragment_java",
+          "//third_party/androidx:androidx_media_media_java",
+          "//third_party/androidx:androidx_mediarouter_mediarouter_java",
+          "//third_party/androidx:androidx_recyclerview_recyclerview_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
       android_aar_prebuilt("google_play_services_fido_java") {
-        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_fido/play-services-fido-21.1.0.aar"
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_fido/play-services-fido-21.2.0.aar"
         info_path = "autorolled/committed/libs/com_google_android_gms_play_services_fido/com_google_android_gms_play_services_fido.info"
         enable_bytecode_checks = false
         deps = [
@@ -261,6 +334,24 @@
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_gcm_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_gcm/play-services-gcm-17.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_gcm/com_google_android_gms_play_services_gcm.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_iid_java",
+          "$google_play_services_package:google_play_services_stats_java",
+          "//third_party/androidx:androidx_collection_collection_java",
+          "//third_party/androidx:androidx_core_core_java",
+          "//third_party/androidx:androidx_legacy_legacy_support_core_utils_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
       android_aar_prebuilt("google_play_services_identity_credentials_java") {
         aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_identity_credentials/play-services-identity-credentials-16.0.0-alpha06.aar"
         info_path = "autorolled/committed/libs/com_google_android_gms_play_services_identity_credentials/com_google_android_gms_play_services_identity_credentials.info"
@@ -276,8 +367,69 @@
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_iid_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_iid/play-services-iid-17.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_iid/com_google_android_gms_play_services_iid.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_stats_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/androidx:androidx_collection_collection_java",
+          "//third_party/androidx:androidx_core_core_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_instantapps_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_instantapps/play-services-instantapps-18.1.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_instantapps/com_google_android_gms_play_services_instantapps.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_location_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_location/play-services-location-21.3.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_location/com_google_android_gms_play_services_location.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_android_java",
+          "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
+          "//third_party/kotlin_stdlib:kotlin_stdlib_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_stats_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_stats/play-services-stats-17.1.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_stats/com_google_android_gms_play_services_stats.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_basement_java",
+          "//third_party/androidx:androidx_legacy_legacy_support_core_utils_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
       android_aar_prebuilt("google_play_services_tasks_java") {
-        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_tasks/play-services-tasks-18.2.0.aar"
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_tasks/play-services-tasks-18.3.0.aar"
         info_path = "autorolled/committed/libs/com_google_android_gms_play_services_tasks/com_google_android_gms_play_services_tasks.info"
         enable_bytecode_checks = false
         deps = [
@@ -287,6 +439,36 @@
     }
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_vision_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_vision/play-services-vision-20.1.3.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_vision/com_google_android_gms_play_services_vision.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_vision_common_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_vision_common_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_vision_common/play-services-vision-common-19.1.3.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_vision_common/com_google_android_gms_play_services_vision_common.info"
+        enable_bytecode_checks = false
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_clearcut_java",
+          "$google_play_services_package:google_play_services_flags_java",
+          "$google_play_services_package:google_play_services_phenotype_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     android_aar_prebuilt(
         "com_google_android_libraries_identity_googleid_googleid_java") {
       aar_path = "autorolled/cipd/libs/com_google_android_libraries_identity_googleid_googleid/googleid-1.1.1.aar"
@@ -301,7 +483,7 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (!defined(material_design_target)) {
       android_aar_prebuilt("com_google_android_material_material_java") {
-        aar_path = "autorolled/cipd/libs/com_google_android_material_material/material-1.13.0-alpha05.aar"
+        aar_path = "autorolled/cipd/libs/com_google_android_material_material/material-1.13.0-alpha13.aar"
         info_path = "autorolled/committed/libs/com_google_android_material_material/com_google_android_material_material.info"
         enable_bytecode_checks = false
 
@@ -321,6 +503,7 @@
           "//third_party/androidx:androidx_drawerlayout_drawerlayout_java",
           "//third_party/androidx:androidx_dynamicanimation_dynamicanimation_java",
           "//third_party/androidx:androidx_fragment_fragment_java",
+          "//third_party/androidx:androidx_graphics_graphics_shapes_java",
           "//third_party/androidx:androidx_lifecycle_lifecycle_runtime_java",
           "//third_party/androidx:androidx_recyclerview_recyclerview_java",
           "//third_party/androidx:androidx_resourceinspection_resourceinspection_annotation_java",
@@ -346,6 +529,24 @@
     }
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (!defined(playcore_target)) {
+      android_aar_prebuilt("com_google_android_play_feature_delivery_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_play_feature_delivery/feature-delivery-2.1.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_play_feature_delivery/com_google_android_play_feature_delivery.info"
+        enable_bytecode_checks = false
+
+        # Target is swapped out when internal code is enabled.
+        # Please depend on //third_party/android_deps:playcore_java instead.
+        visibility = [ "//third_party/android_deps:*" ]
+        deps = [
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/android_deps:com_google_android_play_core_common_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (!defined(guava_android_target)) {
       java_prebuilt("com_google_guava_guava_android_java") {
         jar_path = "autorolled/cipd/libs/com_google_guava_guava_android/guava-33.3.1-android.jar"
@@ -384,7 +585,7 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     if (!defined(android_proto_runtime)) {
       java_prebuilt("com_google_protobuf_protobuf_javalite_java") {
-        jar_path = "autorolled/cipd/libs/com_google_protobuf_protobuf_javalite/protobuf-javalite-4.31.0-RC1.jar"
+        jar_path = "autorolled/cipd/libs/com_google_protobuf_protobuf_javalite/protobuf-javalite-4.31.0-RC2.jar"
         output_name = "com_google_protobuf_protobuf_javalite"
         supports_android = true
         requires_android = true
@@ -465,6 +666,21 @@
     }
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    java_prebuilt(
+        "org_jetbrains_kotlinx_kotlinx_coroutines_play_services_java") {
+      jar_path = "autorolled/cipd/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/kotlinx-coroutines-play-services-1.10.1.jar"
+      output_name = "org_jetbrains_kotlinx_kotlinx_coroutines_play_services"
+      supports_android = true
+      requires_android = true
+      enable_bytecode_checks = false
+      deps = [
+        "$google_play_services_package:google_play_services_tasks_java",
+        "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
+        "//third_party/kotlin_stdlib:kotlin_stdlib_java",
+      ]
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_prebuilt("org_jetbrains_kotlinx_kotlinx_serialization_core_jvm_java") {
       jar_path = "autorolled/cipd/libs/org_jetbrains_kotlinx_kotlinx_serialization_core_jvm/kotlinx-serialization-core-jvm-1.7.2.jar"
       output_name = "org_jetbrains_kotlinx_kotlinx_serialization_core_jvm"
@@ -475,15 +691,6 @@
     }
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-    java_prebuilt("org_jspecify_jspecify_java") {
-      jar_path = "autorolled/cipd/libs/org_jspecify_jspecify/jspecify-1.0.0.jar"
-      output_name = "org_jspecify_jspecify"
-      supports_android = true
-      requires_android = true
-      enable_bytecode_checks = false
-    }
-
-    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_prebuilt("org_robolectric_robolectric_java") {
       jar_path = "autorolled/cipd/libs/org_robolectric_robolectric/robolectric-4.14.1.jar"
       output_name = "org_robolectric_robolectric"
@@ -512,6 +719,126 @@
     }
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_android_datatransport_transport_api_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_datatransport_transport_api/transport-api-4.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_datatransport_transport_api/com_google_android_datatransport_transport_api.info"
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt(
+          "google_android_datatransport_transport_runtime_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_datatransport_transport_runtime/transport-runtime-4.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_datatransport_transport_runtime/com_google_android_datatransport_transport_runtime.info"
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [
+          "$google_play_services_package:google_firebase_firebase_encoders_java",
+          "$google_play_services_package:google_firebase_firebase_encoders_proto_java",
+          "//third_party/android_deps:google_android_datatransport_transport_api_java",
+          "//third_party/android_deps:javax_inject_javax_inject_java",
+          "//third_party/androidx:androidx_annotation_annotation_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_clearcut_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_clearcut/play-services-clearcut-17.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_clearcut/com_google_android_gms_play_services_clearcut.info"
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_phenotype_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/androidx:androidx_core_core_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_flags_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_flags/play-services-flags-18.1.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_flags/com_google_android_gms_play_services_flags.info"
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_play_services_phenotype_java") {
+        aar_path = "autorolled/cipd/libs/com_google_android_gms_play_services_phenotype/play-services-phenotype-17.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_android_gms_play_services_phenotype/com_google_android_gms_play_services_phenotype.info"
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [
+          "$google_play_services_package:google_play_services_base_java",
+          "$google_play_services_package:google_play_services_basement_java",
+          "$google_play_services_package:google_play_services_tasks_java",
+          "//third_party/androidx:androidx_core_core_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    android_aar_prebuilt("com_google_android_play_core_common_java") {
+      aar_path = "autorolled/cipd/libs/com_google_android_play_core_common/core-common-2.0.3.aar"
+      info_path = "autorolled/committed/libs/com_google_android_play_core_common/com_google_android_play_core_common.info"
+      enable_bytecode_checks = false
+
+      # To remove visibility constraint, add this dependency to
+      # //third_party/android_deps/autorolled/build.gradle.
+      visibility = [
+        ":*",
+        "//third_party/androidx:*",
+      ]
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_prebuilt("com_google_auto_value_auto_value_annotations_java") {
       jar_path = "autorolled/cipd/libs/com_google_auto_value_auto_value_annotations/auto-value-annotations-1.11.0.jar"
       output_name = "com_google_auto_value_auto_value_annotations"
@@ -528,6 +855,67 @@
     }
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      java_prebuilt("google_firebase_firebase_encoders_java") {
+        jar_path = "autorolled/cipd/libs/com_google_firebase_firebase_encoders/firebase-encoders-17.0.0.jar"
+        output_name = "com_google_firebase_firebase_encoders"
+        supports_android = true
+        requires_android = true
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      android_aar_prebuilt("google_firebase_firebase_encoders_json_java") {
+        aar_path = "autorolled/cipd/libs/com_google_firebase_firebase_encoders_json/firebase-encoders-json-18.0.0.aar"
+        info_path = "autorolled/committed/libs/com_google_firebase_firebase_encoders_json/com_google_firebase_firebase_encoders_json.info"
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [
+          "$google_play_services_package:google_firebase_firebase_encoders_java",
+          "//third_party/androidx:androidx_annotation_annotation_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    if (google_play_services_package == "//third_party/android_deps") {
+      java_prebuilt("google_firebase_firebase_encoders_proto_java") {
+        jar_path = "autorolled/cipd/libs/com_google_firebase_firebase_encoders_proto/firebase-encoders-proto-16.0.0.jar"
+        output_name = "com_google_firebase_firebase_encoders_proto"
+        supports_android = true
+        requires_android = true
+        enable_bytecode_checks = false
+
+        # To remove visibility constraint, add this dependency to
+        # //third_party/android_deps/autorolled/build.gradle.
+        visibility = [
+          ":*",
+          "//third_party/androidx:*",
+        ]
+        deps = [
+          "$google_play_services_package:google_firebase_firebase_encoders_java",
+          "//third_party/androidx:androidx_annotation_annotation_java",
+        ]
+      }
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_prebuilt(
         "com_google_testparameterinjector_test_parameter_injector_java") {
       jar_path = "autorolled/cipd/libs/com_google_testparameterinjector_test_parameter_injector/test-parameter-injector-1.18.jar"
diff --git a/third_party/android_deps/autorolled/VERSION.txt b/third_party/android_deps/autorolled/VERSION.txt
index a16f71a657..e6dce81b 100644
--- a/third_party/android_deps/autorolled/VERSION.txt
+++ b/third_party/android_deps/autorolled/VERSION.txt
@@ -1 +1 @@
-b672fbe7e107e60.63051e069cf4be9
\ No newline at end of file
+1f0a52ba7527fa6.3e4dc5798c68d46
\ No newline at end of file
diff --git a/third_party/android_deps/autorolled/additional_readme_paths.json b/third_party/android_deps/autorolled/additional_readme_paths.json
index b4b3c076..886aa974 100644
--- a/third_party/android_deps/autorolled/additional_readme_paths.json
+++ b/third_party/android_deps/autorolled/additional_readme_paths.json
@@ -1,19 +1,39 @@
 [
+    "committed/libs/com_google_android_datatransport_transport_api",
+    "committed/libs/com_google_android_datatransport_transport_backend_cct",
+    "committed/libs/com_google_android_datatransport_transport_runtime",
     "committed/libs/com_google_android_gms_play_services_auth",
     "committed/libs/com_google_android_gms_play_services_auth_api_phone",
     "committed/libs/com_google_android_gms_play_services_auth_base",
     "committed/libs/com_google_android_gms_play_services_auth_blockstore",
     "committed/libs/com_google_android_gms_play_services_base",
     "committed/libs/com_google_android_gms_play_services_basement",
+    "committed/libs/com_google_android_gms_play_services_cast",
+    "committed/libs/com_google_android_gms_play_services_cast_framework",
+    "committed/libs/com_google_android_gms_play_services_clearcut",
     "committed/libs/com_google_android_gms_play_services_fido",
+    "committed/libs/com_google_android_gms_play_services_flags",
+    "committed/libs/com_google_android_gms_play_services_gcm",
     "committed/libs/com_google_android_gms_play_services_identity_credentials",
+    "committed/libs/com_google_android_gms_play_services_iid",
+    "committed/libs/com_google_android_gms_play_services_instantapps",
+    "committed/libs/com_google_android_gms_play_services_location",
+    "committed/libs/com_google_android_gms_play_services_phenotype",
+    "committed/libs/com_google_android_gms_play_services_stats",
     "committed/libs/com_google_android_gms_play_services_tasks",
+    "committed/libs/com_google_android_gms_play_services_vision",
+    "committed/libs/com_google_android_gms_play_services_vision_common",
     "committed/libs/com_google_android_libraries_identity_googleid_googleid",
     "committed/libs/com_google_android_material_material",
+    "committed/libs/com_google_android_play_core_common",
+    "committed/libs/com_google_android_play_feature_delivery",
     "committed/libs/com_google_auto_service_auto_service_annotations",
     "committed/libs/com_google_auto_value_auto_value_annotations",
     "committed/libs/com_google_code_findbugs_jsr305",
     "committed/libs/com_google_errorprone_error_prone_annotations",
+    "committed/libs/com_google_firebase_firebase_encoders",
+    "committed/libs/com_google_firebase_firebase_encoders_json",
+    "committed/libs/com_google_firebase_firebase_encoders_proto",
     "committed/libs/com_google_guava_failureaccess",
     "committed/libs/com_google_guava_guava",
     "committed/libs/com_google_guava_guava_android",
@@ -30,6 +50,7 @@
     "committed/libs/org_conscrypt_conscrypt_openjdk_uber",
     "committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_android",
     "committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm",
+    "committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services",
     "committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_test_jvm",
     "committed/libs/org_jetbrains_kotlinx_kotlinx_serialization_core_jvm",
     "committed/libs/org_jspecify_jspecify",
diff --git a/third_party/android_deps/autorolled/bill_of_materials.json b/third_party/android_deps/autorolled/bill_of_materials.json
index babe422..b2ed15bf 100644
--- a/third_party/android_deps/autorolled/bill_of_materials.json
+++ b/third_party/android_deps/autorolled/bill_of_materials.json
@@ -22,7 +22,7 @@
     {
         "name": "annotation-experimental",
         "group": "androidx.annotation",
-        "version": "1.5.0-SNAPSHOT"
+        "version": "1.5.0-rc01"
     },
     {
         "name": "annotation-jvm",
@@ -112,7 +112,7 @@
     {
         "name": "biometric",
         "group": "androidx.biometric",
-        "version": "1.4.0-SNAPSHOT"
+        "version": "1.4.0-alpha03"
     },
     {
         "name": "browser",
@@ -322,7 +322,7 @@
     {
         "name": "concurrent-futures",
         "group": "androidx.concurrent",
-        "version": "1.3.0-SNAPSHOT"
+        "version": "1.3.0-alpha01"
     },
     {
         "name": "concurrent-futures-ktx",
@@ -432,7 +432,7 @@
     {
         "name": "documentfile",
         "group": "androidx.documentfile",
-        "version": "1.1.0-SNAPSHOT"
+        "version": "1.1.0-rc01"
     },
     {
         "name": "drawerlayout",
@@ -497,12 +497,12 @@
     {
         "name": "graphics-shapes",
         "group": "androidx.graphics",
-        "version": "1.1.0-SNAPSHOT"
+        "version": "1.1.0-alpha01"
     },
     {
         "name": "graphics-shapes-android",
         "group": "androidx.graphics",
-        "version": "1.1.0-SNAPSHOT"
+        "version": "1.1.0-alpha01"
     },
     {
         "name": "gridlayout",
@@ -605,11 +605,6 @@
         "version": "2.10.0-SNAPSHOT"
     },
     {
-        "name": "lifecycle-runtime-desktop",
-        "group": "androidx.lifecycle",
-        "version": "2.8.7"
-    },
-    {
         "name": "lifecycle-runtime-ktx",
         "group": "androidx.lifecycle",
         "version": "2.10.0-SNAPSHOT"
@@ -645,11 +640,6 @@
         "version": "2.10.0-SNAPSHOT"
     },
     {
-        "name": "lifecycle-viewmodel-desktop",
-        "group": "androidx.lifecycle",
-        "version": "2.8.7"
-    },
-    {
         "name": "lifecycle-viewmodel-ktx",
         "group": "androidx.lifecycle",
         "version": "2.10.0-SNAPSHOT"
@@ -672,7 +662,7 @@
     {
         "name": "localbroadcastmanager",
         "group": "androidx.localbroadcastmanager",
-        "version": "1.0.0"
+        "version": "1.1.0"
     },
     {
         "name": "media3-common",
@@ -727,7 +717,7 @@
     {
         "name": "mediarouter",
         "group": "androidx.mediarouter",
-        "version": "1.8.0-SNAPSHOT"
+        "version": "1.8.0-alpha04"
     },
     {
         "name": "multidex",
@@ -797,7 +787,7 @@
     {
         "name": "palette",
         "group": "androidx.palette",
-        "version": "1.1.0-SNAPSHOT"
+        "version": "1.0.0"
     },
     {
         "name": "pdf-document-service",
@@ -1162,7 +1152,7 @@
     {
         "name": "play-services-auth-api-phone",
         "group": "com.google.android.gms",
-        "version": "18.1.0"
+        "version": "18.2.0"
     },
     {
         "name": "play-services-auth-base",
@@ -1177,12 +1167,12 @@
     {
         "name": "play-services-base",
         "group": "com.google.android.gms",
-        "version": "18.5.0"
+        "version": "18.7.0"
     },
     {
         "name": "play-services-basement",
         "group": "com.google.android.gms",
-        "version": "18.5.0"
+        "version": "18.7.0"
     },
     {
         "name": "play-services-cast",
@@ -1207,7 +1197,7 @@
     {
         "name": "play-services-fido",
         "group": "com.google.android.gms",
-        "version": "21.1.0"
+        "version": "21.2.0"
     },
     {
         "name": "play-services-flags",
@@ -1252,7 +1242,7 @@
     {
         "name": "play-services-tasks",
         "group": "com.google.android.gms",
-        "version": "18.2.0"
+        "version": "18.3.0"
     },
     {
         "name": "play-services-vision",
@@ -1272,7 +1262,7 @@
     {
         "name": "material",
         "group": "com.google.android.material",
-        "version": "1.13.0-alpha05"
+        "version": "1.13.0-alpha13"
     },
     {
         "name": "core-common",
@@ -1322,7 +1312,7 @@
     {
         "name": "error_prone_annotations",
         "group": "com.google.errorprone",
-        "version": "2.30.0"
+        "version": "2.36.0"
     },
     {
         "name": "firebase-annotations",
@@ -1397,7 +1387,7 @@
     {
         "name": "failureaccess",
         "group": "com.google.guava",
-        "version": "1.0.2"
+        "version": "1.0.3"
     },
     {
         "name": "guava",
@@ -1407,7 +1397,7 @@
     {
         "name": "guava",
         "group": "com.google.guava",
-        "version": "33.3.1-jre"
+        "version": "33.4.8-jre"
     },
     {
         "name": "listenablefuture",
@@ -1422,7 +1412,7 @@
     {
         "name": "protobuf-javalite",
         "group": "com.google.protobuf",
-        "version": "4.31.0-RC1"
+        "version": "4.31.0-RC2"
     },
     {
         "name": "protobuf-lite",
diff --git a/third_party/android_deps/autorolled/build.gradle b/third_party/android_deps/autorolled/build.gradle
index 0d47f52..c4bd0e8 100644
--- a/third_party/android_deps/autorolled/build.gradle
+++ b/third_party/android_deps/autorolled/build.gradle
@@ -18,7 +18,7 @@
 versionCache['androidx.activity:activity-compose'] = '1.12.0-SNAPSHOT'
 versionCache['androidx.activity:activity-ktx'] = '1.12.0-SNAPSHOT'
 versionCache['androidx.annotation:annotation'] = '1.10.0-SNAPSHOT'
-versionCache['androidx.annotation:annotation-experimental'] = '1.5.0-SNAPSHOT'
+versionCache['androidx.annotation:annotation-experimental'] = '1.5.0-rc01'
 versionCache['androidx.annotation:annotation-jvm'] = '1.10.0-SNAPSHOT'
 versionCache['androidx.appcompat:appcompat'] = '1.8.0-SNAPSHOT'
 versionCache['androidx.appcompat:appcompat-resources'] = '1.8.0-SNAPSHOT'
@@ -36,7 +36,7 @@
 versionCache['androidx.benchmark:benchmark-macro-junit4'] = '1.4.0-SNAPSHOT'
 versionCache['androidx.benchmark:benchmark-traceprocessor'] = '1.4.0-SNAPSHOT'
 versionCache['androidx.benchmark:benchmark-traceprocessor-android'] = '1.4.0-SNAPSHOT'
-versionCache['androidx.biometric:biometric'] = '1.4.0-SNAPSHOT'
+versionCache['androidx.biometric:biometric'] = '1.4.0-alpha03'
 versionCache['androidx.browser:browser'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.cardview:cardview'] = '1.1.0-SNAPSHOT'
 versionCache['androidx.collection:collection'] = '1.5.0'
@@ -78,7 +78,7 @@
 versionCache['androidx.compose.ui:ui-unit-android'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.compose.ui:ui-util'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.compose.ui:ui-util-android'] = '1.9.0-SNAPSHOT'
-versionCache['androidx.concurrent:concurrent-futures'] = '1.3.0-SNAPSHOT'
+versionCache['androidx.concurrent:concurrent-futures'] = '1.3.0-alpha01'
 versionCache['androidx.concurrent:concurrent-futures-ktx'] = '1.3.0-SNAPSHOT'
 versionCache['androidx.constraintlayout:constraintlayout'] = '2.3.0-SNAPSHOT'
 versionCache['androidx.constraintlayout:constraintlayout-core'] = '1.2.0-SNAPSHOT'
@@ -100,7 +100,7 @@
 versionCache['androidx.datastore:datastore-core-android'] = '1.2.0-SNAPSHOT'
 versionCache['androidx.datastore:datastore-core-okio'] = '1.2.0-SNAPSHOT'
 versionCache['androidx.datastore:datastore-core-okio-jvm'] = '1.2.0-SNAPSHOT'
-versionCache['androidx.documentfile:documentfile'] = '1.1.0-SNAPSHOT'
+versionCache['androidx.documentfile:documentfile'] = '1.1.0-rc01'
 versionCache['androidx.drawerlayout:drawerlayout'] = '1.3.0-SNAPSHOT'
 versionCache['androidx.dynamicanimation:dynamicanimation'] = '1.1.0'
 versionCache['androidx.emoji2:emoji2'] = '1.6.0-SNAPSHOT'
@@ -113,8 +113,8 @@
 versionCache['androidx.fragment:fragment-testing'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.fragment:fragment-testing-manifest'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.graphics:graphics-path'] = '1.0.1'
-versionCache['androidx.graphics:graphics-shapes'] = '1.1.0-SNAPSHOT'
-versionCache['androidx.graphics:graphics-shapes-android'] = '1.1.0-SNAPSHOT'
+versionCache['androidx.graphics:graphics-shapes'] = '1.1.0-alpha01'
+versionCache['androidx.graphics:graphics-shapes-android'] = '1.1.0-alpha01'
 versionCache['androidx.gridlayout:gridlayout'] = '1.1.0'
 versionCache['androidx.interpolator:interpolator'] = '1.1.0-SNAPSHOT'
 versionCache['androidx.leanback:leanback'] = '1.2.0'
@@ -135,7 +135,6 @@
 versionCache['androidx.lifecycle:lifecycle-runtime-android'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-runtime-compose'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-runtime-compose-android'] = '2.10.0-SNAPSHOT'
-versionCache['androidx.lifecycle:lifecycle-runtime-desktop'] = '2.8.7'
 versionCache['androidx.lifecycle:lifecycle-runtime-ktx'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-runtime-ktx-android'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-service'] = '2.10.0-SNAPSHOT'
@@ -143,12 +142,11 @@
 versionCache['androidx.lifecycle:lifecycle-viewmodel-android'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-viewmodel-compose'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-viewmodel-compose-android'] = '2.10.0-SNAPSHOT'
-versionCache['androidx.lifecycle:lifecycle-viewmodel-desktop'] = '2.8.7'
 versionCache['androidx.lifecycle:lifecycle-viewmodel-ktx'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-viewmodel-savedstate'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.lifecycle:lifecycle-viewmodel-savedstate-android'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.loader:loader'] = '1.2.0-SNAPSHOT'
-versionCache['androidx.localbroadcastmanager:localbroadcastmanager'] = '1.0.0'
+versionCache['androidx.localbroadcastmanager:localbroadcastmanager'] = '1.1.0'
 versionCache['androidx.media3:media3-common'] = '1.2.0'
 versionCache['androidx.media3:media3-container'] = '1.2.0'
 versionCache['androidx.media3:media3-database'] = '1.2.0'
@@ -159,7 +157,7 @@
 versionCache['androidx.media3:media3-session'] = '1.2.0'
 versionCache['androidx.media3:media3-ui'] = '1.2.0'
 versionCache['androidx.media:media'] = '1.8.0-SNAPSHOT'
-versionCache['androidx.mediarouter:mediarouter'] = '1.8.0-SNAPSHOT'
+versionCache['androidx.mediarouter:mediarouter'] = '1.8.0-alpha04'
 versionCache['androidx.multidex:multidex'] = '2.0.0'
 versionCache['androidx.navigation:navigation-common'] = '2.10.0-SNAPSHOT'
 versionCache['androidx.navigation:navigation-common-android'] = '2.10.0-SNAPSHOT'
@@ -173,7 +171,7 @@
 versionCache['androidx.paging:paging-compose'] = '3.4.0-SNAPSHOT'
 versionCache['androidx.paging:paging-compose-android'] = '3.4.0-SNAPSHOT'
 versionCache['androidx.paging:paging-runtime'] = '3.4.0-SNAPSHOT'
-versionCache['androidx.palette:palette'] = '1.1.0-SNAPSHOT'
+versionCache['androidx.palette:palette'] = '1.0.0'
 versionCache['androidx.pdf:pdf-document-service'] = '1.0.0-SNAPSHOT'
 versionCache['androidx.pdf:pdf-viewer'] = '1.0.0-SNAPSHOT'
 versionCache['androidx.pdf:pdf-viewer-fragment'] = '1.0.0-SNAPSHOT'
@@ -246,16 +244,16 @@
 versionCache['com.google.android.datatransport:transport-backend-cct'] = '4.0.0'
 versionCache['com.google.android.datatransport:transport-runtime'] = '4.0.0'
 versionCache['com.google.android.gms:play-services-auth'] = '21.3.0'
-versionCache['com.google.android.gms:play-services-auth-api-phone'] = '18.1.0'
+versionCache['com.google.android.gms:play-services-auth-api-phone'] = '18.2.0'
 versionCache['com.google.android.gms:play-services-auth-base'] = '18.1.0'
 versionCache['com.google.android.gms:play-services-auth-blockstore'] = '16.4.0'
-versionCache['com.google.android.gms:play-services-base'] = '18.5.0'
-versionCache['com.google.android.gms:play-services-basement'] = '18.5.0'
+versionCache['com.google.android.gms:play-services-base'] = '18.7.0'
+versionCache['com.google.android.gms:play-services-basement'] = '18.7.0'
 versionCache['com.google.android.gms:play-services-cast'] = '22.0.0'
 versionCache['com.google.android.gms:play-services-cast-framework'] = '22.0.0'
 versionCache['com.google.android.gms:play-services-clearcut'] = '17.0.0'
 versionCache['com.google.android.gms:play-services-cloud-messaging'] = '17.2.0'
-versionCache['com.google.android.gms:play-services-fido'] = '21.1.0'
+versionCache['com.google.android.gms:play-services-fido'] = '21.2.0'
 versionCache['com.google.android.gms:play-services-flags'] = '18.1.0'
 versionCache['com.google.android.gms:play-services-gcm'] = '17.0.0'
 versionCache['com.google.android.gms:play-services-identity-credentials'] = '16.0.0-alpha06'
@@ -264,11 +262,11 @@
 versionCache['com.google.android.gms:play-services-location'] = '21.3.0'
 versionCache['com.google.android.gms:play-services-phenotype'] = '17.0.0'
 versionCache['com.google.android.gms:play-services-stats'] = '17.1.0'
-versionCache['com.google.android.gms:play-services-tasks'] = '18.2.0'
+versionCache['com.google.android.gms:play-services-tasks'] = '18.3.0'
 versionCache['com.google.android.gms:play-services-vision'] = '20.1.3'
 versionCache['com.google.android.gms:play-services-vision-common'] = '19.1.3'
 versionCache['com.google.android.libraries.identity.googleid:googleid'] = '1.1.1'
-versionCache['com.google.android.material:material'] = '1.13.0-alpha05'
+versionCache['com.google.android.material:material'] = '1.13.0-alpha13'
 versionCache['com.google.android.play:core-common'] = '2.0.3'
 versionCache['com.google.android.play:feature-delivery'] = '2.1.0'
 versionCache['com.google.ar:impress'] = '0.0.2'
@@ -278,7 +276,7 @@
 versionCache['com.google.code.gson:gson'] = '2.8.0'
 versionCache['com.google.dagger:dagger'] = '2.52'
 versionCache['com.google.errorprone:error_prone_annotation'] = '2.34.0'
-versionCache['com.google.errorprone:error_prone_annotations'] = '2.30.0'
+versionCache['com.google.errorprone:error_prone_annotations'] = '2.36.0'
 versionCache['com.google.firebase:firebase-annotations'] = '16.2.0'
 versionCache['com.google.firebase:firebase-common'] = '21.0.0'
 versionCache['com.google.firebase:firebase-common-ktx'] = '21.0.0'
@@ -293,12 +291,12 @@
 versionCache['com.google.firebase:firebase-installations-interop'] = '17.1.1'
 versionCache['com.google.firebase:firebase-measurement-connector'] = '20.0.1'
 versionCache['com.google.firebase:firebase-messaging'] = '24.1.0'
-versionCache['com.google.guava:failureaccess'] = '1.0.2'
+versionCache['com.google.guava:failureaccess'] = '1.0.3'
 versionCache['com.google.guava:guava'] = '33.3.1-android'
-versionCache['com.google.guava:guava'] = '33.3.1-jre'
+versionCache['com.google.guava:guava'] = '33.4.8-jre'
 versionCache['com.google.guava:listenablefuture'] = '9999.0-empty-to-avoid-conflict-with-guava'
 versionCache['com.google.j2objc:j2objc-annotations'] = '3.0.0'
-versionCache['com.google.protobuf:protobuf-javalite'] = '4.31.0-RC1'
+versionCache['com.google.protobuf:protobuf-javalite'] = '4.31.0-RC2'
 versionCache['com.google.protobuf:protobuf-lite'] = '3.0.1'
 versionCache['com.google.testparameterinjector:test-parameter-injector'] = '1.18'
 versionCache['com.googlecode.java-diff-utils:diffutils'] = '1.3.0'
@@ -385,6 +383,7 @@
 repositories {
     google()
     mavenCentral()
+    // {{ANDROIDX_REPO}}
 }
 
 dependencies {
@@ -392,6 +391,32 @@
     testCompileLatest "org.robolectric:robolectric:+"
 
     compileLatest 'com.google.protobuf:protobuf-javalite:+'
+
+    compileLatest "com.google.guava:guava:+"
+    buildCompileLatest "com.google.guava:guava:+"
+
+    compileLatest 'com.google.android.libraries.identity.googleid:googleid:+'
+    compileLatest 'com.google.android.material:material:+'
+    compileLatest 'com.google.android.play:feature-delivery:+'
+
+    // Play services libraries
+    compileLatest "com.google.android.gms:play-services-auth-api-phone:+"
+    compileLatest "com.google.android.gms:play-services-auth-base:+"
+    compileLatest "com.google.android.gms:play-services-auth-blockstore:+"
+    compileLatest "com.google.android.gms:play-services-auth:+"
+    compileLatest "com.google.android.gms:play-services-base:+"
+    compileLatest "com.google.android.gms:play-services-basement:+"
+    compileLatest "com.google.android.gms:play-services-cast-framework:+"
+    compileLatest "com.google.android.gms:play-services-cast:+"
+    compileLatest "com.google.android.gms:play-services-fido:+"
+    compileLatest "com.google.android.gms:play-services-gcm:+"
+    compileLatest "com.google.android.gms:play-services-identity-credentials:+"
+    compileLatest "com.google.android.gms:play-services-iid:+"
+    compileLatest "com.google.android.gms:play-services-instantapps:+"
+    compileLatest "com.google.android.gms:play-services-location:+"
+    compileLatest "com.google.android.gms:play-services-tasks:+"
+    compileLatest "com.google.android.gms:play-services-vision-common:+"
+    compileLatest "com.google.android.gms:play-services-vision:+"
 }
 
 task setUpRepository(type: BuildConfigGenerator) {
@@ -400,4 +425,4 @@
     internalTargetVisibility = [ '//third_party/androidx:*', ':*' ]
     ignoreDEPS true
     writeBoM true
-}
\ No newline at end of file
+}
diff --git a/third_party/android_deps/autorolled/build.gradle.template b/third_party/android_deps/autorolled/build.gradle.template
index 58707654..cd8939be 100644
--- a/third_party/android_deps/autorolled/build.gradle.template
+++ b/third_party/android_deps/autorolled/build.gradle.template
@@ -18,6 +18,7 @@
 repositories {
     google()
     mavenCentral()
+    // {{ANDROIDX_REPO}}
 }
 
 dependencies {
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_api/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_api/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_api/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_api/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_api/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_api/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/com_google_android_datatransport_transport_api.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_api/com_google_android_datatransport_transport_api.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_api/com_google_android_datatransport_transport_api.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_api/com_google_android_datatransport_transport_api.info
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_backend_cct/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_backend_cct/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_backend_cct/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_backend_cct/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/com_google_android_datatransport_transport_backend_cct.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_backend_cct/com_google_android_datatransport_transport_backend_cct.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/com_google_android_datatransport_transport_backend_cct.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_backend_cct/com_google_android_datatransport_transport_backend_cct.info
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_runtime/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_runtime/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_runtime/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_runtime/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/com_google_android_datatransport_transport_runtime.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_runtime/com_google_android_datatransport_transport_runtime.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/com_google_android_datatransport_transport_runtime.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_datatransport_transport_runtime/com_google_android_datatransport_transport_runtime.info
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/LICENSE
index 11707fdf9..48881b26 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/LICENSE
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/LICENSE
@@ -4778,6 +4778,95 @@
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
+------------------
+
+Creative Commons CC0 1.0 Universal
+
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
+SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT
+RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
+CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE
+INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES
+RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 
+
+i. the right to reproduce, adapt, distribute, perform, display, communicate,
+and translate a Work;
+
+ii. moral rights retained by the original author(s) and/or performer(s);
+
+iii. publicity and privacy rights pertaining to a person&apos;s image or
+likeness depicted in a Work;
+
+iv. rights protecting against unfair competition in regards to a Work, subject
+to the limitations in paragraph 4(a), below;
+
+v. rights protecting the extraction, dissemination, use and reuse of data in a
+Work;
+
+vi. database rights (such as those arising under Directive 96/9/EC of the
+European Parliament and of the Council of 11 March 1996 on the legal
+protection of databases, and under any national implementation thereof,
+including any amended or successor version of such directive); and
+
+vii. other similar, equivalent or corresponding rights throughout the world
+based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer&apos;s Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer&apos;s heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer&apos;s express Statement of Purpose. 
+
+3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer&apos;s express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer&apos;s Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer&apos;s express Statement of Purpose. 
+
+4. Limitations and Disclaimers. 
+
+a. No trademark or patent rights held by Affirmer are waived, abandoned,
+surrendered, licensed or otherwise affected by this document.
+
+b. Affirmer offers the Work as-is and makes no representations or warranties
+of any kind concerning the Work, express, implied, statutory or otherwise,
+including without limitation warranties of title, merchantability, fitness for
+a particular purpose, non infringement, or the absence of latent or other
+defects, accuracy, or the present or absence of errors, whether or not
+discoverable, all to the greatest extent permissible under applicable law.
+
+c. Affirmer disclaims responsibility for clearing rights of other persons that
+may apply to the Work or any use thereof, including without limitation any
+person&apos;s Copyright and Related Rights in the Work. Further, Affirmer
+disclaims responsibility for obtaining any necessary consents, permissions or
+other rights required for any use of the Work.
+
+d. Affirmer understands and acknowledges that Creative Commons is not a party
+to this document and has no duty or obligation with respect to this CC0 or use
+of the Work.
+
+
 Kotlin coroutines:
 
                                  Apache License
@@ -5961,4 +6050,208 @@
    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.
+
+kotlinx_serialization:
+
+                                 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.
\ No newline at end of file
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/README.chromium
index 637c2c9..12e23fa 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/README.chromium
@@ -1,7 +1,7 @@
 Name: play-services-auth-api-phone
 Short Name: play-services-auth-api-phone
 URL: https://developers.google.com/android/guides/setup
-Version: 18.1.0
+Version: 18.2.0
 License: Android Software Development Kit License
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/LICENSE
index 11707fdf9..48881b26 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/LICENSE
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/LICENSE
@@ -4778,6 +4778,95 @@
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
+------------------
+
+Creative Commons CC0 1.0 Universal
+
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
+SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT
+RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
+CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE
+INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES
+RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 
+
+i. the right to reproduce, adapt, distribute, perform, display, communicate,
+and translate a Work;
+
+ii. moral rights retained by the original author(s) and/or performer(s);
+
+iii. publicity and privacy rights pertaining to a person&apos;s image or
+likeness depicted in a Work;
+
+iv. rights protecting against unfair competition in regards to a Work, subject
+to the limitations in paragraph 4(a), below;
+
+v. rights protecting the extraction, dissemination, use and reuse of data in a
+Work;
+
+vi. database rights (such as those arising under Directive 96/9/EC of the
+European Parliament and of the Council of 11 March 1996 on the legal
+protection of databases, and under any national implementation thereof,
+including any amended or successor version of such directive); and
+
+vii. other similar, equivalent or corresponding rights throughout the world
+based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer&apos;s Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer&apos;s heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer&apos;s express Statement of Purpose. 
+
+3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer&apos;s express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer&apos;s Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer&apos;s express Statement of Purpose. 
+
+4. Limitations and Disclaimers. 
+
+a. No trademark or patent rights held by Affirmer are waived, abandoned,
+surrendered, licensed or otherwise affected by this document.
+
+b. Affirmer offers the Work as-is and makes no representations or warranties
+of any kind concerning the Work, express, implied, statutory or otherwise,
+including without limitation warranties of title, merchantability, fitness for
+a particular purpose, non infringement, or the absence of latent or other
+defects, accuracy, or the present or absence of errors, whether or not
+discoverable, all to the greatest extent permissible under applicable law.
+
+c. Affirmer disclaims responsibility for clearing rights of other persons that
+may apply to the Work or any use thereof, including without limitation any
+person&apos;s Copyright and Related Rights in the Work. Further, Affirmer
+disclaims responsibility for obtaining any necessary consents, permissions or
+other rights required for any use of the Work.
+
+d. Affirmer understands and acknowledges that Creative Commons is not a party
+to this document and has no duty or obligation with respect to this CC0 or use
+of the Work.
+
+
 Kotlin coroutines:
 
                                  Apache License
@@ -5961,4 +6050,208 @@
    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.
+
+kotlinx_serialization:
+
+                                 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.
\ No newline at end of file
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/README.chromium
index b7d499b..14ddb17 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/README.chromium
@@ -1,7 +1,7 @@
 Name: play-services-base
 Short Name: play-services-base
 URL: https://developers.google.com/android/guides/setup
-Version: 18.5.0
+Version: 18.7.0
 License: Android Software Development Kit License
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_basement/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_basement/README.chromium
index 7eb14d11..0009ff9f 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_basement/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_basement/README.chromium
@@ -1,7 +1,7 @@
 Name: play-services-basement
 Short Name: play-services-basement
 URL: https://developers.google.com/android/guides/setup
-Version: 18.5.0
+Version: 18.7.0
 License: Android Software Development Kit License
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_cast/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_cast/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/com_google_android_gms_play_services_cast.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast/com_google_android_gms_play_services_cast.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_cast/com_google_android_gms_play_services_cast.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast/com_google_android_gms_play_services_cast.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast_framework/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast_framework/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast_framework/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast_framework/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/com_google_android_gms_play_services_cast_framework.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast_framework/com_google_android_gms_play_services_cast_framework.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/com_google_android_gms_play_services_cast_framework.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_cast_framework/com_google_android_gms_play_services_cast_framework.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_clearcut/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_clearcut/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_clearcut/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_clearcut/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/com_google_android_gms_play_services_clearcut.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_clearcut/com_google_android_gms_play_services_clearcut.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/com_google_android_gms_play_services_clearcut.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_clearcut/com_google_android_gms_play_services_clearcut.info
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/LICENSE
index 6b4de76..9737fd5 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/LICENSE
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/LICENSE
@@ -3551,6 +3551,211 @@
    limitations under the License.
 
 
+Jakarta Inject:
+
+
+                                 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.
+
 JsInterop Annotations:
 
 Apache License
@@ -6345,6 +6550,212 @@
    limitations under the License.
 
 
+Tink:
+
+
+                                 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.
+
+
 apksig:
 
 
@@ -6967,6 +7378,42 @@
 accepting any such warranty or additional liability.
 
 
+kotlin:
+
+Copyright 2008 Google Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Code generated by the Protocol Buffer compiler is owned by the owner
+of the input file used when generating it.  This code is not
+standalone and requires a support library to be linked with it.  This
+support library is itself covered by the above license.
+
+
 kotlinx_atomicfu:
 
                                  Apache License
@@ -7171,6 +7618,210 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 
+kotlinx_serialization:
+
+                                 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.
+
 mobiledatadownload:
 
 
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/README.chromium
index 1ee3ae1..fa61e298 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/README.chromium
@@ -1,7 +1,7 @@
 Name: play-services-fido
 Short Name: play-services-fido
 URL: https://developers.google.com/android/guides/setup
-Version: 21.1.0
+Version: 21.2.0
 License: Android Software Development Kit License
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_flags/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_flags/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_flags/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_flags/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_flags/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_flags/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/com_google_android_gms_play_services_flags.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_flags/com_google_android_gms_play_services_flags.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_flags/com_google_android_gms_play_services_flags.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_flags/com_google_android_gms_play_services_flags.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_gcm/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_gcm/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_gcm/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_gcm/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_gcm/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_gcm/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/com_google_android_gms_play_services_gcm.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_gcm/com_google_android_gms_play_services_gcm.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_gcm/com_google_android_gms_play_services_gcm.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_gcm/com_google_android_gms_play_services_gcm.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_iid/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_iid/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_iid/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_iid/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_iid/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_iid/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/com_google_android_gms_play_services_iid.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_iid/com_google_android_gms_play_services_iid.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_iid/com_google_android_gms_play_services_iid.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_iid/com_google_android_gms_play_services_iid.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_instantapps/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_instantapps/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_instantapps/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_instantapps/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/com_google_android_gms_play_services_instantapps.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_instantapps/com_google_android_gms_play_services_instantapps.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/com_google_android_gms_play_services_instantapps.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_instantapps/com_google_android_gms_play_services_instantapps.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_location/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_location/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_location/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_location/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_location/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_location/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/com_google_android_gms_play_services_location.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_location/com_google_android_gms_play_services_location.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_location/com_google_android_gms_play_services_location.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_location/com_google_android_gms_play_services_location.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_phenotype/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_phenotype/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_phenotype/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_phenotype/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/com_google_android_gms_play_services_phenotype.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_phenotype/com_google_android_gms_play_services_phenotype.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/com_google_android_gms_play_services_phenotype.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_phenotype/com_google_android_gms_play_services_phenotype.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_stats/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_stats/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_stats/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_stats/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_stats/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_stats/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/com_google_android_gms_play_services_stats.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_stats/com_google_android_gms_play_services_stats.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_stats/com_google_android_gms_play_services_stats.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_stats/com_google_android_gms_play_services_stats.info
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/LICENSE
index 11707fdf9..48881b26 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/LICENSE
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/LICENSE
@@ -4778,6 +4778,95 @@
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
+------------------
+
+Creative Commons CC0 1.0 Universal
+
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
+SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT
+RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
+CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE
+INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES
+RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 
+
+i. the right to reproduce, adapt, distribute, perform, display, communicate,
+and translate a Work;
+
+ii. moral rights retained by the original author(s) and/or performer(s);
+
+iii. publicity and privacy rights pertaining to a person&apos;s image or
+likeness depicted in a Work;
+
+iv. rights protecting against unfair competition in regards to a Work, subject
+to the limitations in paragraph 4(a), below;
+
+v. rights protecting the extraction, dissemination, use and reuse of data in a
+Work;
+
+vi. database rights (such as those arising under Directive 96/9/EC of the
+European Parliament and of the Council of 11 March 1996 on the legal
+protection of databases, and under any national implementation thereof,
+including any amended or successor version of such directive); and
+
+vii. other similar, equivalent or corresponding rights throughout the world
+based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer&apos;s Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer&apos;s heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer&apos;s express Statement of Purpose. 
+
+3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer&apos;s express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer&apos;s Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer&apos;s express Statement of Purpose. 
+
+4. Limitations and Disclaimers. 
+
+a. No trademark or patent rights held by Affirmer are waived, abandoned,
+surrendered, licensed or otherwise affected by this document.
+
+b. Affirmer offers the Work as-is and makes no representations or warranties
+of any kind concerning the Work, express, implied, statutory or otherwise,
+including without limitation warranties of title, merchantability, fitness for
+a particular purpose, non infringement, or the absence of latent or other
+defects, accuracy, or the present or absence of errors, whether or not
+discoverable, all to the greatest extent permissible under applicable law.
+
+c. Affirmer disclaims responsibility for clearing rights of other persons that
+may apply to the Work or any use thereof, including without limitation any
+person&apos;s Copyright and Related Rights in the Work. Further, Affirmer
+disclaims responsibility for obtaining any necessary consents, permissions or
+other rights required for any use of the Work.
+
+d. Affirmer understands and acknowledges that Creative Commons is not a party
+to this document and has no duty or obligation with respect to this CC0 or use
+of the Work.
+
+
 Kotlin coroutines:
 
                                  Apache License
@@ -5961,4 +6050,208 @@
    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.
+
+kotlinx_serialization:
+
+                                 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.
\ No newline at end of file
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/README.chromium
index 4da1da7b..10983266 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/README.chromium
@@ -1,7 +1,7 @@
 Name: play-services-tasks
 Short Name: play-services-tasks
 URL: https://developers.google.com/android/guides/setup
-Version: 18.2.0
+Version: 18.3.0
 License: Android Software Development Kit License
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_vision/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_vision/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/com_google_android_gms_play_services_vision.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision/com_google_android_gms_play_services_vision.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_vision/com_google_android_gms_play_services_vision.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision/com_google_android_gms_play_services_vision.info
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision_common/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision_common/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision_common/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision_common/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/com_google_android_gms_play_services_vision_common.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision_common/com_google_android_gms_play_services_vision_common.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/com_google_android_gms_play_services_vision_common.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_vision_common/com_google_android_gms_play_services_vision_common.info
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/README.chromium
index bb7d39c..b34f38d 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/README.chromium
@@ -1,7 +1,7 @@
 Name: Material Components for Android
 Short Name: material
 URL: https://github.com/material-components/material-components-android
-Version: 1.13.0-alpha05
+Version: 1.13.0-alpha13
 License: Android Software Development Kit License
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/com_google_android_material_material.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/com_google_android_material_material.info
index 981567c..53e876dc 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/com_google_android_material_material.info
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_android_material_material/com_google_android_material_material.info
@@ -10,27 +10,31 @@
 is_manifest_empty = true
 manifest_package = "com.google.android.material"
 resources = [
+  "res/anim/design_bottom_sheet_slide_in.xml",
+  "res/anim/design_bottom_sheet_slide_out.xml",
   "res/anim/design_snackbar_in.xml",
   "res/anim/design_snackbar_out.xml",
   "res/anim/linear_indeterminate_line1_head_interpolator.xml",
   "res/anim/linear_indeterminate_line1_tail_interpolator.xml",
   "res/anim/linear_indeterminate_line2_head_interpolator.xml",
   "res/anim/linear_indeterminate_line2_tail_interpolator.xml",
+  "res/anim/m3_bottom_sheet_slide_in.xml",
+  "res/anim/m3_bottom_sheet_slide_out.xml",
   "res/anim/m3_motion_fade_enter.xml",
   "res/anim/m3_motion_fade_exit.xml",
+  "res/anim/m3_side_sheet_enter_from_left.xml",
+  "res/anim/m3_side_sheet_enter_from_right.xml",
+  "res/anim/m3_side_sheet_exit_to_left.xml",
+  "res/anim/m3_side_sheet_exit_to_right.xml",
+  "res/anim/mtrl_bottom_sheet_slide_in.xml",
+  "res/anim/mtrl_bottom_sheet_slide_out.xml",
   "res/anim/mtrl_card_lowers_interpolator.xml",
-  "res/anim-v21/design_bottom_sheet_slide_in.xml",
-  "res/anim-v21/design_bottom_sheet_slide_out.xml",
-  "res/anim-v21/m3_bottom_sheet_slide_in.xml",
-  "res/anim-v21/m3_bottom_sheet_slide_out.xml",
-  "res/anim-v21/m3_side_sheet_enter_from_left.xml",
-  "res/anim-v21/m3_side_sheet_enter_from_right.xml",
-  "res/anim-v21/m3_side_sheet_exit_to_left.xml",
-  "res/anim-v21/m3_side_sheet_exit_to_right.xml",
-  "res/anim-v21/mtrl_bottom_sheet_slide_in.xml",
-  "res/anim-v21/mtrl_bottom_sheet_slide_out.xml",
+  "res/animator/chevron_checked_unchecked.xml",
+  "res/animator/chevron_unchecked_checked.xml",
+  "res/animator/design_appbar_state_list_animator.xml",
   "res/animator/design_fab_hide_motion_spec.xml",
   "res/animator/design_fab_show_motion_spec.xml",
+  "res/animator/m3_appbar_state_list_animator.xml",
   "res/animator/m3_btn_elevated_btn_state_list_anim.xml",
   "res/animator/m3_btn_state_list_anim.xml",
   "res/animator/m3_card_elevated_state_list_anim.xml",
@@ -42,6 +46,10 @@
   "res/animator/m3_extended_fab_hide_motion_spec.xml",
   "res/animator/m3_extended_fab_show_motion_spec.xml",
   "res/animator/m3_extended_fab_state_list_animator.xml",
+  "res/animator/m3_fab_state_list_animator.xml",
+  "res/animator/m3_split_button_chevron_overshoot_interpolator.xml",
+  "res/animator/m3_split_button_chevron_reverse_rotation.xml",
+  "res/animator/m3_split_button_chevron_rotation.xml",
   "res/animator/mtrl_btn_state_list_anim.xml",
   "res/animator/mtrl_btn_unelevated_state_list_anim.xml",
   "res/animator/mtrl_card_state_list_anim.xml",
@@ -55,8 +63,6 @@
   "res/animator/mtrl_fab_show_motion_spec.xml",
   "res/animator/mtrl_fab_transformation_sheet_collapse_spec.xml",
   "res/animator/mtrl_fab_transformation_sheet_expand_spec.xml",
-  "res/animator-v21/design_appbar_state_list_animator.xml",
-  "res/animator-v21/m3_appbar_state_list_animator.xml",
   "res/color/design_box_stroke_color.xml",
   "res/color/design_error.xml",
   "res/color/design_icon_tint.xml",
@@ -94,6 +100,8 @@
   "res/color/m3_fab_efab_foreground_color_selector.xml",
   "res/color/m3_fab_ripple_color_selector.xml",
   "res/color/m3_filled_icon_button_container_color_selector.xml",
+  "res/color/m3_floating_toolbar_vibrant_icon_button_container_color_selector.xml",
+  "res/color/m3_floating_toolbar_vibrant_icon_button_text_color_selector.xml",
   "res/color/m3_highlighted_text.xml",
   "res/color/m3_hint_foreground.xml",
   "res/color/m3_icon_button_icon_color_selector.xml",
@@ -122,6 +130,10 @@
   "res/color/m3_slider_inactive_track_color_legacy.xml",
   "res/color/m3_slider_thumb_color.xml",
   "res/color/m3_slider_thumb_color_legacy.xml",
+  "res/color/m3_standard_toolbar_button_text_color_selector.xml",
+  "res/color/m3_standard_toolbar_icon_button_container_color_selector.xml",
+  "res/color/m3_standard_toolbar_icon_button_icon_color_selector.xml",
+  "res/color/m3_standard_toolbar_icon_button_ripple_color_selector.xml",
   "res/color/m3_switch_thumb_tint.xml",
   "res/color/m3_switch_track_tint.xml",
   "res/color/m3_tabs_icon_color.xml",
@@ -149,6 +161,18 @@
   "res/color/m3_timepicker_secondary_text_button_text_color.xml",
   "res/color/m3_timepicker_time_input_stroke_color.xml",
   "res/color/m3_tonal_button_ripple_color_selector.xml",
+  "res/color/m3_vibrant_toolbar_button_text_color_selector.xml",
+  "res/color/m3_vibrant_toolbar_icon_button_container_color_selector.xml",
+  "res/color/m3_vibrant_toolbar_icon_button_icon_color_selector.xml",
+  "res/color/m3_vibrant_toolbar_icon_button_ripple_color_selector.xml",
+  "res/color/m3expressive_bottom_nav_item_icon_tint.xml",
+  "res/color/m3expressive_bottom_nav_item_label_tint.xml",
+  "res/color/m3expressive_bottom_nav_item_ripple_tint.xml",
+  "res/color/m3expressive_button_outline_color_selector.xml",
+  "res/color/m3expressive_button_outlined_background_color_selector.xml",
+  "res/color/m3expressive_nav_rail_item_icon_tint.xml",
+  "res/color/m3expressive_nav_rail_item_label_tint.xml",
+  "res/color/m3expressive_nav_rail_item_ripple_tint.xml",
   "res/color/material_cursor_color.xml",
   "res/color/material_divider_color.xml",
   "res/color/material_on_background_disabled.xml",
@@ -264,6 +288,9 @@
   "res/color-v31/m3_ref_palette_dynamic_neutral_variant94.xml",
   "res/color-v31/m3_ref_palette_dynamic_neutral_variant96.xml",
   "res/color-v31/m3_ref_palette_dynamic_neutral_variant98.xml",
+  "res/color-v31/m3_ref_palette_dynamic_primary98.xml",
+  "res/color-v31/m3_ref_palette_dynamic_secondary98.xml",
+  "res/color-v31/m3_ref_palette_dynamic_tertiary98.xml",
   "res/drawable/avd_hide_password.xml",
   "res/drawable/avd_show_password.xml",
   "res/drawable/design_fab_background.xml",
@@ -274,6 +301,8 @@
   "res/drawable/ic_arrow_back_black_24.xml",
   "res/drawable/ic_clear_black_24.xml",
   "res/drawable/ic_clock_black_24dp.xml",
+  "res/drawable/ic_expand_less_22px.xml",
+  "res/drawable/ic_expand_more_22px.xml",
   "res/drawable/ic_keyboard_black_24dp.xml",
   "res/drawable/ic_m3_chip_check.xml",
   "res/drawable/ic_m3_chip_checked_circle.xml",
@@ -289,8 +318,11 @@
   "res/drawable/m3_bottom_sheet_drag_handle.xml",
   "res/drawable/m3_password_eye.xml",
   "res/drawable/m3_popupmenu_background_overlay.xml",
+  "res/drawable/m3_split_button_chevron_avd.xml",
+  "res/drawable/m3_tabs_background.xml",
   "res/drawable/m3_tabs_line_indicator.xml",
   "res/drawable/m3_tabs_rounded_line_indicator.xml",
+  "res/drawable/material_cursor_drawable.xml",
   "res/drawable/material_ic_calendar_black_24dp.xml",
   "res/drawable/material_ic_clear_black_24dp.xml",
   "res/drawable/material_ic_edit_black_24dp.xml",
@@ -319,6 +351,7 @@
   "res/drawable/mtrl_ic_checkbox_unchecked.xml",
   "res/drawable/mtrl_ic_error.xml",
   "res/drawable/mtrl_ic_indeterminate.xml",
+  "res/drawable/mtrl_navigation_bar_item_background.xml",
   "res/drawable/mtrl_popupmenu_background.xml",
   "res/drawable/mtrl_popupmenu_background_overlay.xml",
   "res/drawable/mtrl_switch_thumb.xml",
@@ -335,25 +368,22 @@
   "res/drawable/mtrl_switch_track_decoration.xml",
   "res/drawable/mtrl_tabs_default_indicator.xml",
   "res/drawable/navigation_empty_icon.xml",
-  "res/drawable-v21/m3_tabs_background.xml",
-  "res/drawable-v21/material_cursor_drawable.xml",
-  "res/drawable-v21/mtrl_navigation_bar_item_background.xml",
   "res/drawable-v23/m3_radiobutton_ripple.xml",
   "res/drawable-v23/m3_selection_control_ripple.xml",
   "res/drawable-v23/m3_tabs_background.xml",
   "res/drawable-v23/m3_tabs_transparent_background.xml",
   "res/drawable-v23/mtrl_popupmenu_background_overlay.xml",
+  "res/interpolator/m3_sys_motion_easing_emphasized.xml",
+  "res/interpolator/m3_sys_motion_easing_emphasized_accelerate.xml",
+  "res/interpolator/m3_sys_motion_easing_emphasized_decelerate.xml",
+  "res/interpolator/m3_sys_motion_easing_linear.xml",
+  "res/interpolator/m3_sys_motion_easing_standard.xml",
+  "res/interpolator/m3_sys_motion_easing_standard_accelerate.xml",
+  "res/interpolator/m3_sys_motion_easing_standard_decelerate.xml",
+  "res/interpolator/mtrl_fast_out_linear_in.xml",
+  "res/interpolator/mtrl_fast_out_slow_in.xml",
   "res/interpolator/mtrl_linear.xml",
-  "res/interpolator-v21/m3_sys_motion_easing_emphasized.xml",
-  "res/interpolator-v21/m3_sys_motion_easing_emphasized_accelerate.xml",
-  "res/interpolator-v21/m3_sys_motion_easing_emphasized_decelerate.xml",
-  "res/interpolator-v21/m3_sys_motion_easing_linear.xml",
-  "res/interpolator-v21/m3_sys_motion_easing_standard.xml",
-  "res/interpolator-v21/m3_sys_motion_easing_standard_accelerate.xml",
-  "res/interpolator-v21/m3_sys_motion_easing_standard_decelerate.xml",
-  "res/interpolator-v21/mtrl_fast_out_linear_in.xml",
-  "res/interpolator-v21/mtrl_fast_out_slow_in.xml",
-  "res/interpolator-v21/mtrl_linear_out_slow_in.xml",
+  "res/interpolator/mtrl_linear_out_slow_in.xml",
   "res/layout/design_bottom_navigation_item.xml",
   "res/layout/design_bottom_sheet_dialog.xml",
   "res/layout/design_layout_snackbar.xml",
@@ -373,6 +403,8 @@
   "res/layout/m3_alert_dialog_actions.xml",
   "res/layout/m3_alert_dialog_title.xml",
   "res/layout/m3_auto_complete_simple_item.xml",
+  "res/layout/m3_navigation_menu_divider.xml",
+  "res/layout/m3_navigation_menu_subheader.xml",
   "res/layout/m3_side_sheet_dialog.xml",
   "res/layout/material_radial_view_group.xml",
   "res/layout/mtrl_alert_dialog.xml",
@@ -420,6 +452,7 @@
   "res/values-h320dp-port-v13/values-h320dp-port-v13.xml",
   "res/values-h360dp-land-v13/values-h360dp-land-v13.xml",
   "res/values-h480dp-land-v13/values-h480dp-land-v13.xml",
+  "res/values-h480dp-v13/values-h480dp-v13.xml",
   "res/values-h550dp-port-v13/values-h550dp-port-v13.xml",
   "res/values-hi/values-hi.xml",
   "res/values-hr/values-hr.xml",
@@ -462,7 +495,6 @@
   "res/values-si/values-si.xml",
   "res/values-sk/values-sk.xml",
   "res/values-sl/values-sl.xml",
-  "res/values-small-v4/values-small-v4.xml",
   "res/values-sq/values-sq.xml",
   "res/values-sr/values-sr.xml",
   "res/values-sv/values-sv.xml",
@@ -491,7 +523,11 @@
   "res/values-zh-rCN/values-zh-rCN.xml",
   "res/values-zh-rHK/values-zh-rHK.xml",
   "res/values-zh-rTW/values-zh-rTW.xml",
-  "res/values-zu/values-zu.xml"
+  "res/values-zu/values-zu.xml",
+  "res/xml/m3_button_group_child_size_change.xml",
+  "res/xml/m3_split_button_inner_corner_size_state_list.xml",
+  "res/xml/m3expressive_button_shape_state_list.xml",
+  "res/xml/m3expressive_connected_buttons_inner_corner_size_state_list.xml"
 ]
 subjar_tuples = []
 subjars = []
diff --git a/third_party/android_deps/libs/com_google_android_play_core_common/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_play_core_common/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_play_core_common/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_play_core_common/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_play_core_common/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_play_core_common/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_play_core_common/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_play_core_common/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_play_core_common/com_google_android_play_core_common.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_play_core_common/com_google_android_play_core_common.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_play_core_common/com_google_android_play_core_common.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_play_core_common/com_google_android_play_core_common.info
diff --git a/third_party/android_deps/libs/com_google_android_play_feature_delivery/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_android_play_feature_delivery/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_play_feature_delivery/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_play_feature_delivery/LICENSE
diff --git a/third_party/android_deps/libs/com_google_android_play_feature_delivery/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_android_play_feature_delivery/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_play_feature_delivery/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_play_feature_delivery/README.chromium
diff --git a/third_party/android_deps/libs/com_google_android_play_feature_delivery/com_google_android_play_feature_delivery.info b/third_party/android_deps/autorolled/committed/libs/com_google_android_play_feature_delivery/com_google_android_play_feature_delivery.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_android_play_feature_delivery/com_google_android_play_feature_delivery.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_android_play_feature_delivery/com_google_android_play_feature_delivery.info
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_errorprone_error_prone_annotations/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_errorprone_error_prone_annotations/README.chromium
index aa674c08..815ef07 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_errorprone_error_prone_annotations/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_errorprone_error_prone_annotations/README.chromium
@@ -1,7 +1,7 @@
 Name: error-prone annotations
 Short Name: error_prone_annotations
 URL: https://github.com/google/error-prone/tree/master/annotations
-Version: 2.30.0
+Version: 2.36.0
 License: Apache-2.0
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_firebase_firebase_encoders/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders/LICENSE
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_firebase_firebase_encoders/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders/README.chromium
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_json/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_json/LICENSE
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_json/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_json/README.chromium
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/com_google_firebase_firebase_encoders_json.info b/third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_json/com_google_firebase_firebase_encoders_json.info
similarity index 100%
rename from third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/com_google_firebase_firebase_encoders_json.info
rename to third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_json/com_google_firebase_firebase_encoders_json.info
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/LICENSE b/third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_proto/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_proto/LICENSE
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_proto/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/com_google_firebase_firebase_encoders_proto/README.chromium
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_guava_failureaccess/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_guava_failureaccess/README.chromium
index d056d9d..1c8673a 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_guava_failureaccess/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_guava_failureaccess/README.chromium
@@ -1,7 +1,7 @@
 Name: Guava InternalFutureFailureAccess and InternalFutures
 Short Name: failureaccess
 URL: https://github.com/google/guava
-Version: 1.0.2
+Version: 1.0.3
 License: Apache-2.0
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_guava_guava/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_guava_guava/README.chromium
index 26426843..f843481 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_guava_guava/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_guava_guava/README.chromium
@@ -1,12 +1,12 @@
 Name: Guava: Google Core Libraries for Java
 Short Name: guava
 URL: https://github.com/google/guava
-Version: 33.3.1-jre
+Version: 33.4.8-jre
 License: Apache-2.0
 License File: LICENSE
 CPEPrefix: unknown
 Security Critical: no
-Shipped: no
+Shipped: yes
 
 Description:
 Guava is a suite of core and expanded libraries that include utility classes, Google's collections, I/O classes, and much more.
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium
index 9617a51..2e42659 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium
@@ -1,7 +1,7 @@
 Name: Protocol Buffers [Lite]
 Short Name: protobuf-javalite
 URL: https://github.com/protocolbuffers/protobuf/blob/master/java/lite.md
-Version: 4.31.0-RC1
+Version: 4.31.0-RC2
 License: BSD-3-Clause
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/LICENSE b/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/LICENSE
similarity index 100%
rename from third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/LICENSE
rename to third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/LICENSE
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/README.chromium
similarity index 100%
rename from third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/README.chromium
rename to third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/README.chromium
diff --git a/third_party/android_deps/autorolled/subprojects.txt b/third_party/android_deps/autorolled/subprojects.txt
index f94f699..6d3f5d2 100644
--- a/third_party/android_deps/autorolled/subprojects.txt
+++ b/third_party/android_deps/autorolled/subprojects.txt
@@ -20,4 +20,4 @@
 
 # *** START OF LIST ***
 ../build.gradle:main
-../../../third_party/androidx/build.gradle:androidx
+../../androidx/build.gradle:androidx
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle
index 185c0278..87b2f64 100644
--- a/third_party/android_deps/build.gradle
+++ b/third_party/android_deps/build.gradle
@@ -12,29 +12,6 @@
 dependencies {
     // Note about the configuration names: they are defined in buildSrc/ChromiumPlugin
 
-    compile 'com.google.android.libraries.identity.googleid:googleid:1.1.1'
-    compile 'com.google.android.material:material:1.13.0-alpha05'
-    compile 'com.google.android.play:feature-delivery:2.1.0'
-
-    // Play services libraries
-    compile "com.google.android.gms:play-services-auth-api-phone:18.1.0"
-    compile "com.google.android.gms:play-services-auth-base:18.1.0"
-    compile "com.google.android.gms:play-services-auth-blockstore:16.4.0"
-    compile "com.google.android.gms:play-services-auth:21.3.0"
-    compile "com.google.android.gms:play-services-base:18.5.0"
-    compile "com.google.android.gms:play-services-basement:18.5.0"
-    compile "com.google.android.gms:play-services-cast-framework:22.0.0"
-    compile "com.google.android.gms:play-services-cast:22.0.0"
-    compile "com.google.android.gms:play-services-fido:21.1.0"
-    compile "com.google.android.gms:play-services-gcm:17.0.0"
-    compile "com.google.android.gms:play-services-identity-credentials:16.0.0-alpha06"
-    compile "com.google.android.gms:play-services-iid:17.0.0"
-    compile "com.google.android.gms:play-services-instantapps:18.1.0"
-    compile "com.google.android.gms:play-services-location:21.3.0"
-    compile "com.google.android.gms:play-services-tasks:18.2.0"
-    compile "com.google.android.gms:play-services-vision-common:19.1.3"
-    compile "com.google.android.gms:play-services-vision:20.1.3"
-
     // Needed only by internal targets:
     compile 'com.android.support:support-annotations:28.0.0'
     buildCompile 'com.google.auto.service:auto-service-annotations:1.0-rc6'
@@ -69,13 +46,6 @@
     // Needed by androidx.benchmark
     androidTestCompile "com.squareup.moshi:moshi-adapters:1.15.0"
 
-    // There is an -jre flavor of guava as well, but it requires Android O+ (for MethodHandle).
-    // The -android version is missing symbols (e.g. ImmutableList stream APIs).
-    // Thus, we need both for now, but we should be able to consolidate once O is our minSdkVersion.
-    // https://github.com/google/guava/wiki/Compatibility
-    compile "com.google.guava:guava:33.3.1-android"
-    buildCompile "com.google.guava:guava:33.3.1-jre"
-
     String daggerVersion = '2.52'
     compile "com.google.dagger:dagger:${daggerVersion}"
 
@@ -135,9 +105,6 @@
 
     // Used by //third_party/byte_buddy
     androidTestCompile "net.bytebuddy:byte-buddy:1.14.5"
-
-    // Use testCompile to have requires_robolectric = true set on targets.
-    testCompile "org.robolectric:robolectric:4.14.1"
 }
 
 task setUpRepository(type: BuildConfigGenerator) {
diff --git a/third_party/android_deps/fetch_all.py b/third_party/android_deps/fetch_all.py
index a6e7614..6cae972 100755
--- a/third_party/android_deps/fetch_all.py
+++ b/third_party/android_deps/fetch_all.py
@@ -21,9 +21,11 @@
 import fnmatch
 import logging
 import os
+import pathlib
 import re
 import shutil
 import subprocess
+import sys
 import tempfile
 import textwrap
 import urllib.request
@@ -34,6 +36,9 @@
 # Assume this script is stored under third_party/android_deps/
 _CHROMIUM_SRC = os.path.normpath(os.path.join(__file__, '..', '..', '..'))
 
+sys.path.insert(1, os.path.join(_CHROMIUM_SRC, 'build/autoroll'))
+import fetch_util
+
 # Default android_deps directory.
 _PRIMARY_ANDROID_DEPS_DIR = os.path.join(_CHROMIUM_SRC, 'third_party',
                                          'android_deps')
@@ -353,6 +358,29 @@
         f.write(template_content)
 
 
+def _InitSubprojects(android_deps_dir, build_android_deps_dir):
+    subprojects = _ParseSubprojects(
+        os.path.join(android_deps_dir, 'subprojects.txt'))
+    subdirs = {name: f'subproject_{name}' for name in subprojects}
+    for name, original_path in subprojects.items():
+        subdir = subdirs[name]
+        build_gradle = os.path.join(subdir, _BUILD_GRADLE)
+        src_path = pathlib.Path(android_deps_dir) / original_path
+        data = src_path.read_text()
+        if '// {{ANDROIDX_REPO}}' in data:
+            version = fetch_util.get_current_androidx_version()
+            repo_url = fetch_util.make_androidx_maven_url(version)
+            data = data.replace('// {{ANDROIDX_REPO}}',
+                                f'maven {{ url "{repo_url}" }}')
+        dst_path = pathlib.Path(build_android_deps_dir) / build_gradle
+        dst_path.parent.mkdir()
+        dst_path.write_text(data)
+
+    _GenerateSettingsGradle(
+        subdirs,
+        os.path.join(_PRIMARY_ANDROID_DEPS_DIR, 'settings.gradle.template'),
+        os.path.join(build_android_deps_dir, 'settings.gradle'))
+
 def _BuildGradleCmd(build_android_deps_dir, task):
     return [
         _GRADLEW, '-p', build_android_deps_dir, '--stacktrace',
@@ -516,9 +544,6 @@
     parser.add_argument('--override-artifact',
                         action='append',
                         help='lib_subpath:url of .aar / .jar to override.')
-    parser.add_argument('--no-subprojects',
-                        action='store_true',
-                        help='Ignore subprojects.txt for faster runs.')
     parser.add_argument('--local',
                         help='Move .jar and .aar files to cipd/ directory '
                         'after running (3pp bot requires this to not '
@@ -576,25 +601,7 @@
         CopyFileOrDirectory(os.path.join(_CHROMIUM_SRC, _DEPS),
                             os.path.join(build_dir, _DEPS))
 
-        if args.no_subprojects:
-            subprojects = None
-        else:
-            subprojects = _ParseSubprojects(
-                os.path.join(args.android_deps_dir, 'subprojects.txt'))
-        subproject_subdirs = {}
-        if subprojects:
-            for subproject_name, original_path in subprojects.items():
-                subproject_subdir = f'subproject_{subproject_name}'
-                Copy(args.android_deps_dir, [original_path],
-                     build_android_deps_dir,
-                     [os.path.join(subproject_subdir, _BUILD_GRADLE)])
-                subproject_subdirs[subproject_name] = subproject_subdir
-
-        _GenerateSettingsGradle(
-            subproject_subdirs,
-            os.path.join(_PRIMARY_ANDROID_DEPS_DIR,
-                         'settings.gradle.template'),
-            os.path.join(build_android_deps_dir, 'settings.gradle'))
+        _InitSubprojects(args.android_deps_dir, build_android_deps_dir)
 
         logging.info('Running Gradle.')
 
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_datatransport_transport_api/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_datatransport_transport_api/3pp/fetch.py
deleted file mode 100755
index 55c7b8d..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/datatransport',
-                         module_name='transport-api',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/OWNERS b/third_party/android_deps/libs/com_google_android_datatransport_transport_api/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/cipd.yaml b/third_party/android_deps/libs/com_google_android_datatransport_transport_api/cipd.yaml
deleted file mode 100644
index 856e5048..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_api/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@4.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_datatransport_transport_api
-description: "transport-api"
-data:
-- file: transport-api-4.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/3pp/fetch.py
deleted file mode 100755
index ce7156e..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/datatransport',
-                         module_name='transport-backend-cct',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/OWNERS b/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/cipd.yaml b/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/cipd.yaml
deleted file mode 100644
index f236231..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@4.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct
-description: "transport-backend-cct"
-data:
-- file: transport-backend-cct-4.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/3pp/fetch.py
deleted file mode 100755
index 5f21a01..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/datatransport',
-                         module_name='transport-runtime',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/OWNERS b/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/cipd.yaml b/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/cipd.yaml
deleted file mode 100644
index 0e97d77..0000000
--- a/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@4.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime
-description: "transport-runtime"
-data:
-- file: transport-runtime-4.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_cast/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_cast/3pp/fetch.py
deleted file mode 100755
index fa17135..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-cast',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_cast/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_cast/cipd.yaml
deleted file mode 100644
index 52f1929..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@22.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_cast
-description: "play-services-cast"
-data:
-- file: play-services-cast-22.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/3pp/fetch.py
deleted file mode 100755
index 9371925..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-cast-framework',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/cipd.yaml
deleted file mode 100644
index 3b00d4b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@22.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework
-description: "play-services-cast-framework"
-data:
-- file: play-services-cast-framework-22.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/3pp/fetch.py
deleted file mode 100755
index 54f432d..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-clearcut',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/cipd.yaml
deleted file mode 100644
index 38080ba..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@17.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut
-description: "play-services-clearcut"
-data:
-- file: play-services-clearcut-17.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_flags/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_flags/3pp/fetch.py
deleted file mode 100755
index e597319..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-flags',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_flags/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_flags/cipd.yaml
deleted file mode 100644
index 7e8372a3..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_flags/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@18.1.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_flags
-description: "play-services-flags"
-data:
-- file: play-services-flags-18.1.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/3pp/fetch.py
deleted file mode 100755
index 4bfb456..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-gcm',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/cipd.yaml
deleted file mode 100644
index 4a79264..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@17.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_gcm
-description: "play-services-gcm"
-data:
-- file: play-services-gcm-17.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_iid/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_iid/3pp/fetch.py
deleted file mode 100755
index 90d3704..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-iid',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_iid/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_iid/cipd.yaml
deleted file mode 100644
index 36f86d2..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_iid/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@17.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_iid
-description: "play-services-iid"
-data:
-- file: play-services-iid-17.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/3pp/fetch.py
deleted file mode 100755
index e294e641d..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-instantapps',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/cipd.yaml
deleted file mode 100644
index 327f9e0..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@18.1.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps
-description: "play-services-instantapps"
-data:
-- file: play-services-instantapps-18.1.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_location/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_location/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_location/3pp/fetch.py
deleted file mode 100755
index ac3c5794..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_location/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-location',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_location/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_location/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_location/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_location/cipd.yaml
deleted file mode 100644
index d6eebee..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_location/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@21.3.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_location
-description: "play-services-location"
-data:
-- file: play-services-location-21.3.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/3pp/fetch.py
deleted file mode 100755
index 0ab0558c..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-phenotype',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/cipd.yaml
deleted file mode 100644
index 252d524e..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@17.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype
-description: "play-services-phenotype"
-data:
-- file: play-services-phenotype-17.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_stats/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_stats/3pp/fetch.py
deleted file mode 100755
index ea0f48b2..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-stats',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_stats/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_stats/cipd.yaml
deleted file mode 100644
index 6d10fba..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_stats/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@17.1.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_stats
-description: "play-services-stats"
-data:
-- file: play-services-stats-17.1.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_vision/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_vision/3pp/fetch.py
deleted file mode 100755
index df9cfbc..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-vision',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_vision/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_vision/cipd.yaml
deleted file mode 100644
index b2d1f716..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@20.1.3.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_vision
-description: "play-services-vision"
-data:
-- file: play-services-vision-20.1.3.aar
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/3pp/fetch.py
deleted file mode 100755
index 5fd94264..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/gms',
-                         module_name='play-services-vision-common',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/OWNERS b/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/cipd.yaml b/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/cipd.yaml
deleted file mode 100644
index 490446b..0000000
--- a/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@19.1.3.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common
-description: "play-services-vision-common"
-data:
-- file: play-services-vision-common-19.1.3.aar
diff --git a/third_party/android_deps/libs/com_google_android_play_core_common/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_play_core_common/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_play_core_common/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_play_core_common/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_play_core_common/3pp/fetch.py
deleted file mode 100755
index f0edf1c7..0000000
--- a/third_party/android_deps/libs/com_google_android_play_core_common/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/play',
-                         module_name='core-common',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_play_core_common/OWNERS b/third_party/android_deps/libs/com_google_android_play_core_common/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_play_core_common/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_play_core_common/cipd.yaml b/third_party/android_deps/libs/com_google_android_play_core_common/cipd.yaml
deleted file mode 100644
index 0f0d4e6..0000000
--- a/third_party/android_deps/libs/com_google_android_play_core_common/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@2.0.3.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_play_core_common
-description: "core-common"
-data:
-- file: core-common-2.0.3.aar
diff --git a/third_party/android_deps/libs/com_google_android_play_feature_delivery/3pp/3pp.pb b/third_party/android_deps/libs/com_google_android_play_feature_delivery/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_android_play_feature_delivery/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_android_play_feature_delivery/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_play_feature_delivery/3pp/fetch.py
deleted file mode 100755
index 9d5d4890..0000000
--- a/third_party/android_deps/libs/com_google_android_play_feature_delivery/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/android/play',
-                         module_name='feature-delivery',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_android_play_feature_delivery/OWNERS b/third_party/android_deps/libs/com_google_android_play_feature_delivery/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_android_play_feature_delivery/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_android_play_feature_delivery/cipd.yaml b/third_party/android_deps/libs/com_google_android_play_feature_delivery/cipd.yaml
deleted file mode 100644
index 72d265f..0000000
--- a/third_party/android_deps/libs/com_google_android_play_feature_delivery/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@2.1.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_android_play_feature_delivery
-description: "feature-delivery"
-data:
-- file: feature-delivery-2.1.0.aar
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/3pp/3pp.pb b/third_party/android_deps/libs/com_google_firebase_firebase_encoders/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/3pp/fetch.py b/third_party/android_deps/libs/com_google_firebase_firebase_encoders/3pp/fetch.py
deleted file mode 100755
index e63aefa..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/firebase',
-                         module_name='firebase-encoders',
-                         file_ext='jar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/OWNERS b/third_party/android_deps/libs/com_google_firebase_firebase_encoders/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/cipd.yaml b/third_party/android_deps/libs/com_google_firebase_firebase_encoders/cipd.yaml
deleted file mode 100644
index 06800d92..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@17.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_firebase_firebase_encoders
-description: "firebase-encoders"
-data:
-- file: firebase-encoders-17.0.0.jar
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/3pp/3pp.pb b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/3pp/fetch.py b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/3pp/fetch.py
deleted file mode 100755
index ee0832d..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/firebase',
-                         module_name='firebase-encoders-json',
-                         file_ext='aar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/OWNERS b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/cipd.yaml b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/cipd.yaml
deleted file mode 100644
index fb23789..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@18.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json
-description: "firebase-encoders-json"
-data:
-- file: firebase-encoders-json-18.0.0.aar
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/3pp/3pp.pb b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/3pp/fetch.py b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/3pp/fetch.py
deleted file mode 100755
index b351b4a2..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://dl.google.com/dl/android/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='com/google/firebase',
-                         module_name='firebase-encoders-proto',
-                         file_ext='jar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/OWNERS b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/cipd.yaml b/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/cipd.yaml
deleted file mode 100644
index d528831..0000000
--- a/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@16.0.0.cr1
-package: chromium/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto
-description: "firebase-encoders-proto"
-data:
-- file: firebase-encoders-proto-16.0.0.jar
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/3pp/3pp.pb b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/3pp/3pp.pb
deleted file mode 100644
index d743b51b..0000000
--- a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/3pp/3pp.pb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
-
-create {
-  source {
-    script { name: "fetch.py" }
-  }
-}
-
-upload {
-  pkg_prefix: "chromium/third_party/android_deps/libs"
-  universal: true
-}
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/3pp/fetch.py
deleted file mode 100755
index 8b754fa..0000000
--- a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/3pp/fetch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is generated, do not edit. Update BuildConfigGenerator.groovy and
-# 3ppFetch.template instead.
-
-import pathlib
-import sys
-
-_3PP_DIR = pathlib.Path(__file__).resolve().parent
-sys.path.insert(0, str(_3PP_DIR.parents[2]))
-import fetch_common
-
-_REPO_URL = 'https://repo.maven.apache.org/maven2'
-SPEC = fetch_common.Spec(repo_url=_REPO_URL,
-                         group_name='org/jetbrains/kotlinx',
-                         module_name='kotlinx-coroutines-play-services',
-                         file_ext='jar',
-                         patch_version='cr1',
-                         version_override=None,
-                         version_filter=None)
-
-if __name__ == '__main__':
-    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/OWNERS b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/OWNERS
deleted file mode 100644
index aea47a05..0000000
--- a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/cipd.yaml b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/cipd.yaml
deleted file mode 100644
index ea39e70c..0000000
--- a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/cipd.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:2@1.10.1.cr1
-package: chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services
-description: "kotlinx-coroutines-play-services"
-data:
-- file: kotlinx-coroutines-play-services-1.10.1.jar
diff --git a/third_party/android_deps/subprojects.txt b/third_party/android_deps/subprojects.txt
index d465aec..85f01b5 100644
--- a/third_party/android_deps/subprojects.txt
+++ b/third_party/android_deps/subprojects.txt
@@ -20,5 +20,4 @@
 
 # *** START OF LIST ***
 ../androidx/build.gradle:androidx
-# Commented out until the first roll is done.
-./autorolled/build.gradle:autorolled
+autorolled/build.gradle:autorolled
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index fcd810e..89d73ef 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -302,7 +302,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/13449807/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/13452791/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/androidx/fetch_all_androidx.py b/third_party/androidx/fetch_all_androidx.py
index 1482f4e..88342a0 100755
--- a/third_party/androidx/fetch_all_androidx.py
+++ b/third_party/androidx/fetch_all_androidx.py
@@ -35,23 +35,12 @@
 _BOM_NAME = 'bill_of_materials.json'
 _EXTRACT_SCRIPT_PATH = _ANDROIDX_PATH / 'extract_and_commit_extras.py'
 
-sys.path.insert(1, str(_SRC_PATH / 'third_party/depot_tools'))
-import gclient_eval
-
 sys.path.insert(1, str(_SRC_PATH / 'build/autoroll'))
 import fetch_util
 
 # URL to artifacts in latest androidx snapshot.
 _ANDROIDX_LATEST_SNAPSHOT_ARTIFACTS_URL = 'https://androidx.dev/snapshots/latest/artifacts'
 
-# Path to package listed in //DEPS
-_DEPS_PACKAGE = 'src/third_party/androidx/cipd'
-# CIPD package name
-_CIPD_PACKAGE = 'chromium/third_party/androidx'
-
-# Snapshot repository URL with {{version}} placeholder.
-_SNAPSHOT_REPOSITORY_URL = 'https://androidx.dev/snapshots/builds/{{version}}/artifacts/repository'
-
 # When androidx roller is breaking, and a fix is not imminent, use this to pin a
 # broken library to an old known-working version.
 # * The first element of each tuple is the path to the artifact of the latest
@@ -75,10 +64,6 @@
 ]
 
 
-def _build_snapshot_repository_url(version):
-    return _SNAPSHOT_REPOSITORY_URL.replace('{{version}}', version)
-
-
 def _get_latest_androidx_version():
     androidx_artifacts_response = request.urlopen(
         _ANDROIDX_LATEST_SNAPSHOT_ARTIFACTS_URL)
@@ -93,49 +78,7 @@
                      androidx_artifacts_url)
     assert match is not None
     version = match.group(1)
-    return version
-
-
-def _query_cipd_tags(version):
-    cipd_output = subprocess.check_output(
-        ['cipd', 'describe', _CIPD_PACKAGE, '-version', version],
-        encoding='utf-8')
-    # Output looks like:
-    # Package:       chromium/third_party/androidx
-    # Instance ID:   gUjEawxv5mQO8yfbuC8W-rx4V3zYE-4LTWggXpZHI4sC
-    # Registered by: user:chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com
-    # Registered at: 2025-01-06 17:54:48.034135 +0000 UTC
-    # Refs:
-    #   latest
-    # Tags:
-    #   details0:version-cr-012873390
-    #   version:cr-012873390
-    lines = cipd_output.split('\n')
-    tags = {}
-    parsing_tags = False
-    for line in lines:
-        if not line.strip():
-            continue
-        if line.startswith('Tags:'):
-            parsing_tags = True
-            continue
-        if parsing_tags:
-            tag, value = line.strip().split(':', 1)
-            tags[tag] = value
-    return tags
-
-
-def _get_current_cipd_instance():
-    with open(os.path.join(_SRC_PATH, 'DEPS'), 'rt') as f:
-        gclient_dict = gclient_eval.Exec(f.read())
-        return gclient_eval.GetCIPD(gclient_dict, _DEPS_PACKAGE, _CIPD_PACKAGE)
-
-
-def _get_current_androidx_version():
-    cipd_instance = _get_current_cipd_instance()
-    cipd_tags = _query_cipd_tags(cipd_instance)
-    version_string = cipd_tags['version']
-    version = version_string[len('cr-0'):]
+    logging.info('Resolved latest androidx version to %s', version)
     return version
 
 
@@ -174,14 +117,12 @@
                                             os.path.abspath(args.local_repo))
     else:
         if args.local:
-            version = _get_current_androidx_version()
-            logging.info('Resolved current androidx version to %s', version)
+            version = fetch_util.get_current_androidx_version()
         else:
             version = _get_latest_androidx_version()
-            logging.info('Resolved latest androidx version to %s', version)
 
-        androidx_snapshot_repository_url = _build_snapshot_repository_url(
-            version)
+        androidx_snapshot_repository_url = (
+            fetch_util.make_androidx_maven_url(version))
         # Prepend '0' to version to avoid conflicts with previous version format.
         version = 'cr-0' + version
 
@@ -241,7 +182,7 @@
                        check=True)
 
     fetch_util.write_cipd_yaml(package_root=_CIPD_PATH,
-                               package_name=_CIPD_PACKAGE,
+                               package_name=fetch_util.ANDROIDX_CIPD_PACKAGE,
                                version=version,
                                output_path=_CIPD_PATH / 'cipd.yaml')
 
diff --git a/third_party/angle b/third_party/angle
index f5e2a67..1c7fa5f 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit f5e2a67a3136b51586f4e2009551cf5b3116b3c7
+Subproject commit 1c7fa5f847f236cc758f58838a9f5f958c1de0de
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 7a4c3ba91..0ef7b52 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -6223,6 +6223,7 @@
       mixed-content
       origin
       inspector
+      integrity
       subresource-filter
       content-type
       coep-frame-resource-needs-coep-header
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 543c11e..41cbf30 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -296,6 +296,7 @@
     "//services/device/public/mojom",
     "//services/device/public/mojom:generic_sensor",
     "//services/network/public/mojom",
+    "//services/network/public/mojom:mojom_integrity_policy",
     "//services/network/public/mojom:mojom_ip_address",
     "//services/network/public/mojom:mojom_permissions_policy",
     "//services/network/public/mojom:mojom_proxy_config",
@@ -341,6 +342,7 @@
       "//services/network/public/mojom:mojom_content_security_policy",
       "//services/network/public/mojom:mojom_cors_origin_pattern",
       "//services/network/public/mojom:mojom_integrity_algorithm",
+      "//services/network/public/mojom:mojom_integrity_policy",
       "//services/network/public/mojom:mojom_network_param",
       "//services/network/public/mojom:mojom_schemeful_site",
       "//services/network/public/mojom:mojom_source_location",
@@ -1193,6 +1195,7 @@
       "//services/network/public/mojom:mojom_content_security_policy",
       "//services/network/public/mojom:mojom_cors_origin_pattern",
       "//services/network/public/mojom:mojom_integrity_algorithm",
+      "//services/network/public/mojom:mojom_integrity_policy",
       "//services/network/public/mojom:mojom_source_location",
       "//services/network/public/mojom:mojom_web_sandbox_flags",
       "//services/network/public/mojom:url_loader_base",
@@ -1444,6 +1447,7 @@
       "//services/network/public/mojom:mojom_content_security_policy",
       "//services/network/public/mojom:mojom_cors_origin_pattern",
       "//services/network/public/mojom:mojom_integrity_algorithm",
+      "//services/network/public/mojom:mojom_integrity_policy",
       "//services/network/public/mojom:mojom_source_location",
       "//services/network/public/mojom:mojom_storage_access_api",
       "//services/network/public/mojom:mojom_web_sandbox_flags",
diff --git a/third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom b/third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom
index 55fbf06..d8ed16e8 100644
--- a/third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom
+++ b/third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom
@@ -9,21 +9,6 @@
 // These types are used in/for constructing AggregatableReports, see
 // //content/browser/aggregation_service/aggregatable_report.h.
 
-// Corresponds to the 'alternative aggregation mode' optional setting, but
-// also includes the default option (if no alternative is set).
-enum AggregationServiceMode {
-  // Uses a server-side Trusted Execution Environment (TEE) to process the
-  // encrypted payloads, see
-  // https://github.com/WICG/attribution-reporting-api/blob/main/AGGREGATION_SERVICE_TEE.md.
-  kTeeBased,
-
-  // Implements a protocol similar to poplar VDAF in the PPM Framework, see
-  // https://github.com/WICG/attribution-reporting-api/blob/main/AGGREGATE.md#choosing-among-aggregation-services.
-  kExperimentalPoplar,
-
-  kDefault = kTeeBased,
-};
-
 struct AggregatableReportHistogramContribution {
   mojo_base.mojom.Uint128 bucket;
   int32 value;
diff --git a/third_party/blink/public/mojom/frame/policy_container.mojom b/third_party/blink/public/mojom/frame/policy_container.mojom
index 2b4886a..c0df8e6 100644
--- a/third_party/blink/public/mojom/frame/policy_container.mojom
+++ b/third_party/blink/public/mojom/frame/policy_container.mojom
@@ -6,6 +6,7 @@
 
 import "services/network/public/mojom/content_security_policy.mojom";
 import "services/network/public/mojom/cross_origin_embedder_policy.mojom";
+import "services/network/public/mojom/integrity_policy.mojom";
 import "services/network/public/mojom/ip_address_space.mojom";
 import "services/network/public/mojom/referrer_policy.mojom";
 import "services/network/public/mojom/web_sandbox_flags.mojom";
@@ -16,6 +17,8 @@
 // updated through meta tags (see PolicyContainerHost).
 struct PolicyContainerPolicies {
   network.mojom.CrossOriginEmbedderPolicy cross_origin_embedder_policy;
+  network.mojom.IntegrityPolicy integrity_policy;
+  network.mojom.IntegrityPolicy integrity_policy_report_only;
   network.mojom.ReferrerPolicy referrer_policy =
     network.mojom.ReferrerPolicy.kDefault;
   array<network.mojom.ContentSecurityPolicy> content_security_policies;
diff --git a/third_party/blink/public/mojom/reporting/reporting.mojom b/third_party/blink/public/mojom/reporting/reporting.mojom
index cb2b55f..a616a779 100644
--- a/third_party/blink/public/mojom/reporting/reporting.mojom
+++ b/third_party/blink/public/mojom/reporting/reporting.mojom
@@ -49,6 +49,16 @@
                           int32 line_number,
                           int32 column_number);
 
+  // Attempts to queue an Integrity Violation report using the Reporting API.
+  //
+  // (See //third_party/blink/renderer/core/frame/integrity_violation_report_body.h.)
+  QueueIntegrityViolationReport(url.mojom.Url url,
+                          string endpoint,
+                          string document_url,
+                          string blocked_url,
+                          string destination,
+                          bool report_only);
+
   // Attempts to queue a Permissions Policy violation report using the Reporting API.
   //
   // (See //third_party/blink/renderer/core/frame/permissions_policy_violation_report_body.h.)
diff --git a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
index 3cb4e761..1b3e0e5 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
@@ -389,6 +389,7 @@
   kTextUnderlineOffset = 331,
   kWindowManagement = 332,
   kRequestclose = 333,
+  kDRAFT_Uint8ArrayToFromBase64AndHex = 334,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/DEPS b/third_party/blink/public/platform/DEPS
index e67ff64..638457c6 100644
--- a/third_party/blink/public/platform/DEPS
+++ b/third_party/blink/public/platform/DEPS
@@ -56,6 +56,7 @@
     "+net/url_request/redirect_info.h",
     "+services/network/public/cpp/cors/cors_error_status.h",
     "+services/network/public/cpp/cors/preflight_result.h",
+    "+services/network/public/cpp/integrity_policy.h",
     "+services/network/public/cpp/resource_request_body.h",
     "+services/network/public/cpp/shared_url_loader_factory.h",
 
@@ -71,6 +72,7 @@
     "+services/network/public/mojom/fetch_api.mojom-forward.h",
     "+services/network/public/mojom/fetch_api.mojom-shared.h",
     "+services/network/public/mojom/integrity_algorithm.mojom-shared.h",
+    "+services/network/public/mojom/integrity_policy.mojom-forward.h",
     "+services/network/public/mojom/ip_address_space.mojom-shared.h",
     "+services/network/public/mojom/referrer_policy.mojom-shared.h",
     "+services/network/public/mojom/trust_tokens.mojom-shared.h",
diff --git a/third_party/blink/public/platform/resource_request_blocked_reason.h b/third_party/blink/public/platform/resource_request_blocked_reason.h
index 9af02e36..0163610 100644
--- a/third_party/blink/public/platform/resource_request_blocked_reason.h
+++ b/third_party/blink/public/platform/resource_request_blocked_reason.h
@@ -14,6 +14,7 @@
   kMixedContent,
   kOrigin,
   kInspector,
+  kIntegrity,
   kSubresourceFilter,
   kContentType,
   kCoepFrameResourceNeedsCoepHeader,
diff --git a/third_party/blink/public/platform/web_policy_container.h b/third_party/blink/public/platform/web_policy_container.h
index b30040d3..dedeae2 100644
--- a/third_party/blink/public/platform/web_policy_container.h
+++ b/third_party/blink/public/platform/web_policy_container.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "services/network/public/cpp/integrity_policy.h"
 #include "services/network/public/mojom/cross_origin_embedder_policy.mojom-shared.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
@@ -22,6 +23,8 @@
 struct WebPolicyContainerPolicies {
   network::mojom::CrossOriginEmbedderPolicyValue cross_origin_embedder_policy =
       network::mojom::CrossOriginEmbedderPolicyValue::kNone;
+  network::IntegrityPolicy integrity_policy;
+  network::IntegrityPolicy integrity_policy_report_only;
   network::mojom::ReferrerPolicy referrer_policy =
       network::mojom::ReferrerPolicy::kDefault;
   std::vector<WebContentSecurityPolicy> content_security_policies;
diff --git a/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc b/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
index a777b8ae8..80990ef 100644
--- a/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
+++ b/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
@@ -466,6 +466,9 @@
     case v8::Isolate::kExplicitResourceManagement:
       webdx_feature = WebDXFeature::kDRAFT_ExplicitResourceManagement;
       break;
+    case v8::Isolate::kUint8ArrayToFromBase64AndHex:
+      webdx_feature = WebDXFeature::kDRAFT_Uint8ArrayToFromBase64AndHex;
+      break;
     default:
       // This can happen if V8 has added counters that this version of Blink
       // does not know about. It's harmless.
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni
index 64787df..fb18143b 100644
--- a/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -1176,6 +1176,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_input_device_capabilities.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_input_event.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_input_event.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_integrity_violation_report_body.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_integrity_violation_report_body.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_interest_event.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_interest_event.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_inspector_overlay_host.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni
index 9775aca..be1c11899 100644
--- a/third_party/blink/renderer/bindings/idl_in_core.gni
+++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -297,6 +297,7 @@
   "//third_party/blink/renderer/core/frame/document_policy_violation_report_body.idl",
   "//third_party/blink/renderer/core/frame/external.idl",
   "//third_party/blink/renderer/core/frame/history.idl",
+  "//third_party/blink/renderer/core/frame/integrity_violation_report_body.idl",
   "//third_party/blink/renderer/core/frame/intervention_report_body.idl",
   "//third_party/blink/renderer/core/frame/is_input_pending_options.idl",
   "//third_party/blink/renderer/core/frame/location.idl",
diff --git a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_initial_values.h.tmpl b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_initial_values.h.tmpl
index 0387c15..1185a8b1 100644
--- a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_initial_values.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_initial_values.h.tmpl
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COMPUTED_STYLE_INITIAL_VALUES_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COMPUTED_STYLE_INITIAL_VALUES_H_
 
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
@@ -130,7 +131,7 @@
 {% endfor %}
 
  private:
-  static const FilterOperations& InitialFilterInternal() {
+  CORE_EXPORT static const FilterOperations& InitialFilterInternal() {
     DEFINE_STATIC_LOCAL(const Persistent<FilterOperationsWrapper>, ops,
         (MakeGarbageCollected<FilterOperationsWrapper>()));
     return ops->Operations();
diff --git a/third_party/blink/renderer/core/DEPS b/third_party/blink/renderer/core/DEPS
index 752af99..101a20ff 100644
--- a/third_party/blink/renderer/core/DEPS
+++ b/third_party/blink/renderer/core/DEPS
@@ -85,6 +85,7 @@
     "+services/network/public/cpp/cross_origin_embedder_policy.h",
     "+services/network/public/cpp/features.h",
     "+services/network/public/cpp/header_util.h",
+    "+services/network/public/cpp/integrity_policy.h",
     "+services/network/public/cpp/is_potentially_trustworthy.h",
     "+services/network/public/cpp/ip_address_space_util.h",
     "+services/network/public/cpp/request_destination.h",
diff --git a/third_party/blink/renderer/core/animation/BUILD.gn b/third_party/blink/renderer/core/animation/BUILD.gn
index 890c1a99..2d3b681 100644
--- a/third_party/blink/renderer/core/animation/BUILD.gn
+++ b/third_party/blink/renderer/core/animation/BUILD.gn
@@ -294,6 +294,8 @@
     "transition_interpolation.h",
     "transition_keyframe.cc",
     "transition_keyframe.h",
+    "tree_counting_checker.cc",
+    "tree_counting_checker.h",
     "typed_interpolation_value.h",
     "underlying_length_checker.h",
     "underlying_value.h",
diff --git a/third_party/blink/renderer/core/animation/css_number_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_number_interpolation_type.cc
index b4fd1e3f..57fae90 100644
--- a/third_party/blink/renderer/core/animation/css_number_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_number_interpolation_type.cc
@@ -9,6 +9,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/core/animation/number_property_functions.h"
+#include "third_party/blink/renderer/core/animation/tree_counting_checker.h"
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
 #include "third_party/blink/renderer/core/css/resolver/style_builder.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
@@ -85,13 +86,17 @@
 
 InterpolationValue CSSNumberInterpolationType::MaybeConvertValue(
     const CSSValue& value,
-    const StyleResolverState&,
-    ConversionCheckers&) const {
-  auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value);
+    const StyleResolverState& state,
+    ConversionCheckers& conversion_checkers) const {
+  const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value);
   if (!primitive_value || !primitive_value->IsNumber()) {
     return nullptr;
   }
-  return CreateNumberValue(primitive_value->GetDoubleValue());
+  if (primitive_value->IsElementDependent()) {
+    conversion_checkers.push_back(TreeCountingChecker::Create(state));
+  }
+  return CreateNumberValue(
+      primitive_value->ComputeNumber(state.CssToLengthConversionData()));
 }
 
 InterpolationValue
diff --git a/third_party/blink/renderer/core/animation/tree_counting_checker.cc b/third_party/blink/renderer/core/animation/tree_counting_checker.cc
new file mode 100644
index 0000000..c24c10f
--- /dev/null
+++ b/third_party/blink/renderer/core/animation/tree_counting_checker.cc
@@ -0,0 +1,46 @@
+// Copyright 2025 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/core/animation/tree_counting_checker.h"
+
+#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+#include "third_party/blink/renderer/core/dom/nth_index_cache.h"
+
+namespace blink {
+
+TreeCountingChecker* TreeCountingChecker::Create(
+    const StyleResolverState& state) {
+  const Element* element = state.CssToLengthConversionData().GetElement();
+  CHECK(element);
+  unsigned nth_child_index =
+      NthIndexCache::NthChildIndex(const_cast<Element&>(*element),
+                                   /*filter=*/nullptr,
+                                   /*selector_checker=*/nullptr,
+                                   /*context=*/nullptr);
+  unsigned nth_last_child_index =
+      NthIndexCache::NthLastChildIndex(const_cast<Element&>(*element),
+                                       /*filter=*/nullptr,
+                                       /*selector_checker=*/nullptr,
+                                       /*context=*/nullptr);
+  return MakeGarbageCollected<TreeCountingChecker>(nth_child_index,
+                                                   nth_last_child_index);
+}
+
+bool TreeCountingChecker::IsValid(const StyleResolverState& state,
+                                  const InterpolationValue& underlying) const {
+  const Element* element = state.CssToLengthConversionData().GetElement();
+  CHECK(element);
+  return nth_child_index_ ==
+             NthIndexCache::NthChildIndex(const_cast<Element&>(*element),
+                                          /*filter=*/nullptr,
+                                          /*selector_checker=*/nullptr,
+                                          /*context=*/nullptr) &&
+         nth_last_child_index_ ==
+             NthIndexCache::NthLastChildIndex(const_cast<Element&>(*element),
+                                              /*filter=*/nullptr,
+                                              /*selector_checker=*/nullptr,
+                                              /*context=*/nullptr);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/tree_counting_checker.h b/third_party/blink/renderer/core/animation/tree_counting_checker.h
new file mode 100644
index 0000000..67a77091
--- /dev/null
+++ b/third_party/blink/renderer/core/animation/tree_counting_checker.h
@@ -0,0 +1,37 @@
+// Copyright 2025 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_CORE_ANIMATION_TREE_COUNTING_CHECKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_TREE_COUNTING_CHECKER_H_
+
+#include "third_party/blink/renderer/core/animation/css_interpolation_type.h"
+
+namespace blink {
+
+// Conversion checker used to track whether an interpolation rely on tree
+// counting functions like sibling-index() and sibling-count(). Such functions
+// resolve in MaybeConvertValue() and inserting/removing siblings of the
+// animated element may need re-resolving of keyframe property values.
+class TreeCountingChecker : public CSSInterpolationType::CSSConversionChecker {
+ public:
+  TreeCountingChecker(unsigned nth_child_index, unsigned nth_last_child_index)
+      : nth_child_index_(nth_child_index),
+        nth_last_child_index_(nth_last_child_index) {}
+
+  static TreeCountingChecker* Create(const StyleResolverState& state);
+
+  bool IsValid(const StyleResolverState& state,
+               const InterpolationValue& underlying) const final;
+
+ private:
+  // The value currently used for sibling-index().
+  unsigned nth_child_index_;
+  // In combination with nth_child_index_, the nth_last_child_index_ is used to
+  // detect any changes in sibling-count().
+  unsigned nth_last_child_index_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_TREE_COUNTING_CHECKER_H_
diff --git a/third_party/blink/renderer/core/css/invalidation/invalidation_tracing_flag.h b/third_party/blink/renderer/core/css/invalidation/invalidation_tracing_flag.h
index 50430d9e..0e96ff7 100644
--- a/third_party/blink/renderer/core/css/invalidation/invalidation_tracing_flag.h
+++ b/third_party/blink/renderer/core/css/invalidation/invalidation_tracing_flag.h
@@ -16,7 +16,8 @@
 class InvalidationTracingFlag {
  public:
   ALWAYS_INLINE static bool IsEnabled() {
-    static const unsigned char* is_tracing_enabled = GetCategoryGroupEnabled();
+    static const unsigned char* const is_tracing_enabled =
+        GetCategoryGroupEnabled();
     return *is_tracing_enabled;
   }
 
diff --git a/third_party/blink/renderer/core/css/selector_statistics_flag.h b/third_party/blink/renderer/core/css/selector_statistics_flag.h
index 82a821ea..316a4f8 100644
--- a/third_party/blink/renderer/core/css/selector_statistics_flag.h
+++ b/third_party/blink/renderer/core/css/selector_statistics_flag.h
@@ -17,7 +17,8 @@
 class SelectorStatisticsFlag {
  public:
   ALWAYS_INLINE static bool IsEnabled() {
-    static const unsigned char* is_tracing_enabled = GetCategoryGroupEnabled();
+    static const unsigned char* const is_tracing_enabled =
+        GetCategoryGroupEnabled();
     return *is_tracing_enabled;
   }
 
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc
index ead61f6..45a2f31 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -46,6 +46,7 @@
 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h"
+#include "third_party/blink/renderer/core/frame/integrity_policy.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -520,8 +521,13 @@
 void ExecutionContext::SetPolicyContainer(
     std::unique_ptr<PolicyContainer> container) {
   policy_container_ = std::move(container);
-  security_context_.SetSandboxFlags(
-      policy_container_->GetPolicies().sandbox_flags);
+  const mojom::blink::PolicyContainerPolicies& policies =
+      policy_container_->GetPolicies();
+  security_context_.SetSandboxFlags(policies.sandbox_flags);
+
+  IntegrityPolicy::LogParsingErrorsIfAny(this, policies.integrity_policy);
+  IntegrityPolicy::LogParsingErrorsIfAny(this,
+                                         policies.integrity_policy_report_only);
 }
 
 std::unique_ptr<PolicyContainer> ExecutionContext::TakePolicyContainer() {
diff --git a/third_party/blink/renderer/core/frame/build.gni b/third_party/blink/renderer/core/frame/build.gni
index 83d6b1a..ab1f6161 100644
--- a/third_party/blink/renderer/core/frame/build.gni
+++ b/third_party/blink/renderer/core/frame/build.gni
@@ -101,6 +101,10 @@
   "history.h",
   "history_util.cc",
   "history_util.h",
+  "integrity_policy.cc",
+  "integrity_policy.h",
+  "integrity_violation_report_body.cc",
+  "integrity_violation_report_body.h",
   "intervention.cc",
   "intervention.h",
   "intervention_report_body.cc",
@@ -283,6 +287,7 @@
   "frame_overlay_test.cc",
   "frame_serializer_test.cc",
   "frame_test.cc",
+  "integrity_policy_test.cc",
   "history_util_test.cc",
   "local_dom_window_test.cc",
   "local_frame_back_forward_cache_test.cc",
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 8fe2d35..8fbe8a7b 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -59,6 +59,7 @@
 #include "third_party/blink/renderer/core/frame/csp/csp_hash_report_body.h"
 #include "third_party/blink/renderer/core/frame/csp/csp_source.h"
 #include "third_party/blink/renderer/core/frame/frame_client.h"
+#include "third_party/blink/renderer/core/frame/integrity_policy.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -170,10 +171,20 @@
   return false;
 }
 
+bool HasScriptUnsafeHashes(
+    const network::mojom::blink::ContentSecurityPolicy& policy) {
+  CSPOperativeDirective directive = CSPDirectiveListOperativeDirective(
+      policy, network::mojom::CSPDirectiveName::ScriptSrc);
+  return directive.source_list && directive.source_list->allow_unsafe_hashes;
+}
+
+}  // namespace
+
 // https://www.w3.org/TR/CSP3/#strip-url-for-use-in-reports
-static String StripURLForUseInReport(const SecurityOrigin* security_origin,
-                                     const KURL& url,
-                                     CSPDirectiveName effective_type) {
+String ContentSecurityPolicy::StripURLForUseInReport(
+    const SecurityOrigin* security_origin,
+    const KURL& url,
+    CSPDirectiveName effective_type) {
   if (!url.IsValid()) {
     return String();
   }
@@ -213,15 +224,6 @@
   return stripped_url.GetString();
 }
 
-bool HasScriptUnsafeHashes(
-    const network::mojom::blink::ContentSecurityPolicy& policy) {
-  CSPOperativeDirective directive = CSPDirectiveListOperativeDirective(
-      policy, network::mojom::CSPDirectiveName::ScriptSrc);
-  return directive.source_list && directive.source_list->allow_unsafe_hashes;
-}
-
-}  // namespace
-
 bool ContentSecurityPolicy::IsNonceableElement(const Element* element) {
   if (element->nonce().IsNull())
     return false;
@@ -861,7 +863,7 @@
 
 // https://w3c.github.io/webappsec-csp/#does-request-violate-policy
 bool ContentSecurityPolicy::AllowRequest(
-    mojom::blink::RequestContextType context,
+    mojom::blink::RequestContextType request_context,
     network::mojom::RequestDestination request_destination,
     network::mojom::RequestMode request_mode,
     const KURL& url,
@@ -876,7 +878,7 @@
   // 1. If request’s initiator is "prefetch", then return the result of
   // executing "Does resource hint request violate policy?" on request and
   // policy.
-  if (context == mojom::blink::RequestContextType::PREFETCH) {
+  if (request_context == mojom::blink::RequestContextType::PREFETCH) {
     return std::ranges::all_of(policies_, [&](const auto& policy) {
       return !CheckHeaderTypeMatches(check_header_type, reporting_disposition,
                                      policy->header->type) ||
@@ -888,7 +890,7 @@
   }
 
   std::optional<CSPDirectiveName> type =
-      GetDirectiveTypeFromRequestContextType(context);
+      GetDirectiveTypeFromRequestContextType(request_context);
 
   if (!type)
     return true;
@@ -1124,15 +1126,15 @@
     // If this load was blocked via 'frame-ancestors', then the URL of
     // |document| has not yet been initialized. In this case, we'll set both
     // 'documentURI' and 'blockedURI' to the blocked document's URL.
-    String stripped_url =
-        StripURLForUseInReport(delegate->GetSecurityOrigin(), blocked_url,
-                               CSPDirectiveName::DefaultSrc);
+    String stripped_url = ContentSecurityPolicy::StripURLForUseInReport(
+        delegate->GetSecurityOrigin(), blocked_url,
+        CSPDirectiveName::DefaultSrc);
     init->setDocumentURI(stripped_url);
     init->setBlockedURI(stripped_url);
   } else {
-    String stripped_url =
-        StripURLForUseInReport(delegate->GetSecurityOrigin(), delegate->Url(),
-                               CSPDirectiveName::DefaultSrc);
+    String stripped_url = ContentSecurityPolicy::StripURLForUseInReport(
+        delegate->GetSecurityOrigin(), delegate->Url(),
+        CSPDirectiveName::DefaultSrc);
     init->setDocumentURI(stripped_url);
     switch (violation_type) {
       case ContentSecurityPolicyViolationType::kInlineViolation:
@@ -1150,7 +1152,7 @@
         // does not strip path and query from the URL. This is safe since
         // blocked_url at this point is always the original url (before
         // redirects).
-        init->setBlockedURI(StripURLForUseInReport(
+        init->setBlockedURI(ContentSecurityPolicy::StripURLForUseInReport(
             delegate->GetSecurityOrigin(), blocked_url, effective_type));
         break;
       case ContentSecurityPolicyViolationType::kTrustedTypesSinkViolation:
@@ -1210,8 +1212,8 @@
     // violation. It is the URL pre-redirect. So it is safe to expose it in
     // reports without leaking any new informations to the document. See
     // https://crrev.com/c/2187792.
-    String source_file = StripURLForUseInReport(delegate->GetSecurityOrigin(),
-                                                source_url, effective_type);
+    String source_file = ContentSecurityPolicy::StripURLForUseInReport(
+        delegate->GetSecurityOrigin(), source_url, effective_type);
 
     init->setSourceFile(source_file);
     init->setLineNumber(source_location->LineNumber());
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index 8f2cfa8..5b50c33 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -33,6 +33,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/unguessable_token.h"
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
+#include "services/network/public/cpp/integrity_policy.h"
 #include "services/network/public/mojom/content_security_policy.mojom-blink.h"
 #include "services/network/public/mojom/web_sandbox_flags.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
@@ -326,6 +327,10 @@
       const String& source_prefix = g_empty_string,
       std::optional<base::UnguessableToken> issue_id = std::nullopt);
 
+  // Strip a URL to make it safe to report it.
+  static String StripURLForUseInReport(const SecurityOrigin* security_origin,
+                                       const KURL& url,
+                                       CSPDirectiveName effective_type);
   // Called when mixed content is detected on a page; will trigger a violation
   // report if the 'block-all-mixed-content' directive is specified for a
   // policy.
diff --git a/third_party/blink/renderer/core/frame/integrity_policy.cc b/third_party/blink/renderer/core/frame/integrity_policy.cc
new file mode 100644
index 0000000..06adeeb7
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/integrity_policy.cc
@@ -0,0 +1,112 @@
+// Copyright 2025 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/core/frame/integrity_policy.h"
+
+#include "base/containers/contains.h"
+#include "services/network/public/cpp/integrity_policy.h"
+#include "services/network/public/cpp/request_destination.h"
+#include "services/network/public/mojom/integrity_algorithm.mojom-blink.h"
+#include "services/network/public/mojom/integrity_policy.mojom-blink.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/integrity_violation_report_body.h"
+#include "third_party/blink/renderer/core/frame/policy_container.h"
+#include "third_party/blink/renderer/core/frame/report.h"
+#include "third_party/blink/renderer/core/frame/reporting_context.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+namespace {
+
+Vector<String> ConvertToBlink(const std::vector<std::string>& in) {
+  Vector<String> out;
+  for (const std::string& str : in) {
+    out.push_back(String::FromUTF8(str));
+  }
+  return out;
+}
+
+void SendReport(ExecutionContext* context,
+                Vector<String> report_endpoints,
+                const KURL& blocked_url,
+                const String& destination,
+                bool report_only) {
+  const SecurityOrigin* origin = context->GetSecurityOrigin();
+  const KURL& document_url = context->Url();
+  String safe_document_url = ContentSecurityPolicy::StripURLForUseInReport(
+      origin, document_url, CSPDirectiveName::Unknown);
+  String safe_blocked_url = ContentSecurityPolicy::StripURLForUseInReport(
+      origin, blocked_url, CSPDirectiveName::Unknown);
+
+  auto* body = MakeGarbageCollected<IntegrityViolationReportBody>(
+      safe_document_url, safe_blocked_url, destination, report_only);
+  Report* observed_report = MakeGarbageCollected<Report>(
+      ReportType::kIntegrityViolation, safe_document_url, body);
+  ReportingContext::From(context)->QueueReport(observed_report,
+                                               std::move(report_endpoints));
+}
+
+bool ShouldBlockOrReport(const network::IntegrityPolicy& integrity_policy) {
+  return (base::Contains(
+              integrity_policy.blocked_destinations,
+              ::network::mojom::blink::IntegrityPolicy::Destination::kScript) &&
+          base::Contains(
+              integrity_policy.sources,
+              ::network::mojom::blink::IntegrityPolicy::Source::kInline));
+}
+
+}  // namespace
+
+// static
+bool IntegrityPolicy::AllowRequest(
+    ExecutionContext* context,
+    network::mojom::RequestDestination request_destination,
+    network::mojom::RequestMode request_mode,
+    const IntegrityMetadataSet& integrity_metadata,
+    const KURL& url) {
+  if ((!integrity_metadata.empty() &&
+       request_mode != network::mojom::RequestMode::kNoCors) ||
+      url.ProtocolIsData() || url.ProtocolIs("blob")) {
+    return true;
+  }
+  PolicyContainer* policy_container = context->GetPolicyContainer();
+  const network::IntegrityPolicy& integrity_policy =
+      policy_container->GetPolicies().integrity_policy;
+  const network::IntegrityPolicy& integrity_policy_report_only =
+      policy_container->GetPolicies().integrity_policy_report_only;
+
+  bool allow = true;
+  if (request_destination == network::mojom::RequestDestination::kScript) {
+    if (ShouldBlockOrReport(integrity_policy)) {
+      allow = false;
+      SendReport(
+          context, ConvertToBlink(integrity_policy.endpoints), url,
+          String(network::RequestDestinationToString(request_destination)),
+          /*report_only=*/false);
+    }
+    if (ShouldBlockOrReport(integrity_policy_report_only)) {
+      SendReport(
+          context, ConvertToBlink(integrity_policy_report_only.endpoints), url,
+          String(network::RequestDestinationToString(request_destination)),
+          /*report_only=*/true);
+    }
+  }
+  return allow;
+}
+
+void IntegrityPolicy::LogParsingErrorsIfAny(
+    ExecutionContext* context,
+    const network::IntegrityPolicy& policy) {
+  for (const std::string& error : policy.parsing_errors) {
+    context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+        mojom::blink::ConsoleMessageSource::kSecurity,
+        mojom::blink::ConsoleMessageLevel::kError, String(error)));
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/integrity_policy.h b/third_party/blink/renderer/core/frame/integrity_policy.h
new file mode 100644
index 0000000..eb3ce0b
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/integrity_policy.h
@@ -0,0 +1,35 @@
+// Copyright 2025 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_CORE_FRAME_INTEGRITY_POLICY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_INTEGRITY_POLICY_H_
+
+#include "services/network/public/mojom/fetch_api.mojom-blink-forward.h"
+#include "third_party/blink/renderer/core/core_export.h"
+
+namespace network {
+struct IntegrityPolicy;
+}
+
+namespace blink {
+
+class KURL;
+class ExecutionContext;
+struct IntegrityMetadataSet;
+
+class IntegrityPolicy {
+ public:
+  CORE_EXPORT
+  static bool AllowRequest(
+      ExecutionContext* context,
+      network::mojom::RequestDestination request_destination,
+      network::mojom::RequestMode request_mode,
+      const IntegrityMetadataSet& integrity_metadata,
+      const KURL& url);
+  static void LogParsingErrorsIfAny(ExecutionContext* context,
+                                    const network::IntegrityPolicy& policy);
+};
+
+}  // namespace blink
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_INTEGRITY_POLICY_H_
diff --git a/third_party/blink/renderer/core/frame/integrity_policy_test.cc b/third_party/blink/renderer/core/frame/integrity_policy_test.cc
new file mode 100644
index 0000000..c90013a
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/integrity_policy_test.cc
@@ -0,0 +1,105 @@
+// Copyright 2025 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/core/frame/integrity_policy.h"
+
+#include "services/network/public/cpp/integrity_policy.h"
+#include "services/network/public/mojom/integrity_policy.mojom-blink.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/frame/policy_container.mojom-blink.h"
+#include "third_party/blink/renderer/core/frame/policy_container.h"
+#include "third_party/blink/renderer/core/testing/mock_policy_container_host.h"
+#include "third_party/blink/renderer/core/testing/null_execution_context.h"
+#include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
+#include "third_party/blink/renderer/platform/testing/main_thread_isolate.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+class IntegrityPolicyTest : public testing::Test {
+ public:
+  IntegrityPolicyTest()
+      : secure_url("https://example.test/index.html"),
+        secure_origin(SecurityOrigin::Create(secure_url)) {}
+  ~IntegrityPolicyTest() override {
+    execution_context->NotifyContextDestroyed();
+  }
+
+ protected:
+  void SetUp() override { CreateExecutionContext(); }
+
+  void CreateExecutionContext() {
+    execution_context = MakeGarbageCollected<NullExecutionContext>();
+    // Create a PolicyContainer with the right IntegrityPolicy
+    MockPolicyContainerHost policy_container_host;
+    mojom::blink::PolicyContainerPoliciesPtr policy_container_policies =
+        mojom::blink::PolicyContainerPolicies::New();
+    network::IntegrityPolicy integrity_policy;
+    integrity_policy.blocked_destinations.emplace_back(
+        network::mojom::IntegrityPolicy_Destination::kScript);
+    integrity_policy.sources.emplace_back(
+        network::mojom::IntegrityPolicy_Source::kInline);
+    policy_container_policies->integrity_policy = integrity_policy;
+    std::unique_ptr<PolicyContainer> policy_container =
+        std::make_unique<PolicyContainer>(
+            policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+            std::move(policy_container_policies));
+    execution_context->SetUpSecurityContextForTesting();
+    execution_context->GetSecurityContext().SetSecurityOriginForTesting(
+        secure_origin);
+    execution_context->SetPolicyContainer(std::move(policy_container));
+  }
+
+  test::TaskEnvironment task_environment;
+  KURL secure_url;
+  scoped_refptr<SecurityOrigin> secure_origin;
+  Persistent<NullExecutionContext> execution_context;
+};
+
+TEST_F(IntegrityPolicyTest, AllowRequestTest) {
+  IntegrityMetadataSet kNonEmptyIntegrityMetadata;
+  kNonEmptyIntegrityMetadata.Insert(IntegrityMetadata(
+      "foobar", network::mojom::blink::IntegrityAlgorithm::kSha256));
+  struct TestCase {
+    network::mojom::RequestDestination destination;
+    network::mojom::RequestMode mode;
+    const IntegrityMetadataSet& metadata;
+    const KURL& url;
+    bool allow;
+  } cases[] = {
+      {network::mojom::RequestDestination::kScript,
+       network::mojom::RequestMode::kCors, IntegrityMetadataSet(),
+       KURL("https://www.example.com"), false},
+      {network::mojom::RequestDestination::kStyle,
+       network::mojom::RequestMode::kCors, IntegrityMetadataSet(),
+       KURL("https://www.example.com"), true},
+      {network::mojom::RequestDestination::kScript,
+       network::mojom::RequestMode::kNoCors, kNonEmptyIntegrityMetadata,
+       KURL("https://www.example.com"), false},
+      {network::mojom::RequestDestination::kScript,
+       network::mojom::RequestMode::kCors, kNonEmptyIntegrityMetadata,
+       KURL("https://www.example.com"), true},
+      {network::mojom::RequestDestination::kScript,
+       network::mojom::RequestMode::kCors, IntegrityMetadataSet(),
+       KURL("data:text/html;charset=utf-8,Hello%20World"), true},
+      {network::mojom::RequestDestination::kScript,
+       network::mojom::RequestMode::kCors, IntegrityMetadataSet(),
+       KURL(
+           "blob:https://www.example.com/31de0587-36d7-4939-848f-8d13fdfd400c"),
+       true},
+  };
+
+  // Enforced
+  for (const auto& test : cases) {
+    SCOPED_TRACE(testing::Message() << "destination: " << test.destination
+                                    << ", mode: " << test.mode);
+    bool result =
+        IntegrityPolicy::AllowRequest(execution_context, test.destination,
+                                      test.mode, test.metadata, test.url);
+    EXPECT_EQ(test.allow, result);
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/integrity_violation_report_body.cc b/third_party/blink/renderer/core/frame/integrity_violation_report_body.cc
new file mode 100644
index 0000000..c22497d
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/integrity_violation_report_body.cc
@@ -0,0 +1,17 @@
+// Copyright 2025 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/core/frame/integrity_violation_report_body.h"
+
+namespace blink {
+
+void IntegrityViolationReportBody::BuildJSONValue(
+    V8ObjectBuilder& builder) const {
+  builder.AddString("documentURL", documentURL());
+  builder.AddStringOrNull("blockedURL", blockedURL());
+  builder.AddStringOrNull("destination", destination());
+  builder.AddBoolean("reportOnly", reportOnly());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/integrity_violation_report_body.h b/third_party/blink/renderer/core/frame/integrity_violation_report_body.h
new file mode 100644
index 0000000..35813a0
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/integrity_violation_report_body.h
@@ -0,0 +1,45 @@
+// Copyright 2025 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_CORE_FRAME_INTEGRITY_VIOLATION_REPORT_BODY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_INTEGRITY_VIOLATION_REPORT_BODY_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/frame/report_body.h"
+
+namespace blink {
+
+class CORE_EXPORT IntegrityViolationReportBody : public ReportBody {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  explicit IntegrityViolationReportBody(const String& document_url,
+                                        const String& blocked_url,
+                                        const String& destination,
+                                        bool report_only)
+      : document_url_(document_url),
+        blocked_url_(blocked_url),
+        destination_(destination),
+        report_only_(report_only) {}
+
+  ~IntegrityViolationReportBody() override = default;
+
+  const String& documentURL() const { return document_url_; }
+  const String& blockedURL() const { return blocked_url_; }
+  const String& destination() const { return destination_; }
+  bool reportOnly() const { return report_only_; }
+
+  void BuildJSONValue(V8ObjectBuilder& builder) const override;
+
+ private:
+  const String document_url_;
+  const String blocked_url_;
+  const String destination_;
+  bool report_only_ = false;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_INTEGRITY_VIOLATION_REPORT_BODY_H_
diff --git a/third_party/blink/renderer/core/frame/integrity_violation_report_body.idl b/third_party/blink/renderer/core/frame/integrity_violation_report_body.idl
new file mode 100644
index 0000000..e73a418
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/integrity_violation_report_body.idl
@@ -0,0 +1,16 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://www.w3.org/TR/CSP3/#cspviolationreportbody
+
+[
+    Exposed=Window,
+    RuntimeEnabled=IntegrityPolicyScript
+] interface IntegrityViolationReportBody : ReportBody {
+  readonly attribute USVString documentURL;
+  readonly attribute USVString? blockedURL;
+  readonly attribute USVString? destination;
+  readonly attribute boolean reportOnly;
+  [CallWith=ScriptState] object toJSON();
+};
diff --git a/third_party/blink/renderer/core/frame/policy_container.cc b/third_party/blink/renderer/core/frame/policy_container.cc
index 49e585e..79534c54 100644
--- a/third_party/blink/renderer/core/frame/policy_container.cc
+++ b/third_party/blink/renderer/core/frame/policy_container.cc
@@ -7,6 +7,7 @@
 #include <tuple>
 
 #include "services/network/public/cpp/web_sandbox_flags.h"
+#include "services/network/public/mojom/integrity_policy.mojom-blink.h"
 #include "third_party/blink/renderer/core/frame/csp/conversion_util.h"
 
 namespace blink {
@@ -38,7 +39,9 @@
       container->policies.cross_origin_embedder_policy;
   mojom::blink::PolicyContainerPoliciesPtr policies =
       mojom::blink::PolicyContainerPolicies::New(
-          cross_origin_embedder_policy, container->policies.referrer_policy,
+          cross_origin_embedder_policy, container->policies.integrity_policy,
+          container->policies.integrity_policy_report_only,
+          container->policies.referrer_policy,
           ConvertToMojoBlink(
               std::move(container->policies.content_security_policies)),
           container->policies.is_credentialless,
diff --git a/third_party/blink/renderer/core/frame/policy_container_test.cc b/third_party/blink/renderer/core/frame/policy_container_test.cc
index 325497a1..b8f3d322 100644
--- a/third_party/blink/renderer/core/frame/policy_container_test.cc
+++ b/third_party/blink/renderer/core/frame/policy_container_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/frame/policy_container.h"
 
+#include "services/network/public/cpp/integrity_policy.h"
 #include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
 #include "services/network/public/mojom/cross_origin_embedder_policy.mojom-blink-forward.h"
 #include "services/network/public/mojom/ip_address_space.mojom-blink-forward.h"
@@ -20,6 +21,7 @@
   auto policies = mojom::blink::PolicyContainerPolicies::New(
       network::CrossOriginEmbedderPolicy(
           network::mojom::blink::CrossOriginEmbedderPolicyValue::kNone),
+      network::IntegrityPolicy(), network::IntegrityPolicy(),
       network::mojom::blink::ReferrerPolicy::kNever,
       Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
       /*anonymous=*/false, network::mojom::WebSandboxFlags::kNone,
@@ -39,6 +41,7 @@
   auto policies = mojom::blink::PolicyContainerPolicies::New(
       network::CrossOriginEmbedderPolicy(
           network::mojom::blink::CrossOriginEmbedderPolicyValue::kNone),
+      network::IntegrityPolicy(), network::IntegrityPolicy(),
       network::mojom::blink::ReferrerPolicy::kAlways,
       Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
       /*anonymous=*/false, network::mojom::WebSandboxFlags::kNone,
diff --git a/third_party/blink/renderer/core/frame/report.h b/third_party/blink/renderer/core/frame/report.h
index 7ac563a..91bc688a 100644
--- a/third_party/blink/renderer/core/frame/report.h
+++ b/third_party/blink/renderer/core/frame/report.h
@@ -22,6 +22,7 @@
   static constexpr const char kDeprecation[] = "deprecation";
   static constexpr const char kDocumentPolicyViolation[] =
       "document-policy-violation";
+  static constexpr const char kIntegrityViolation[] = "integrity-violation";
   static constexpr const char kPermissionsPolicyViolation[] =
       "permissions-policy-violation";
   static constexpr const char kPotentialPermissionsPolicyViolation[] =
diff --git a/third_party/blink/renderer/core/frame/reporting_context.cc b/third_party/blink/renderer/core/frame/reporting_context.cc
index c745da2a..4a121f1 100644
--- a/third_party/blink/renderer/core/frame/reporting_context.cc
+++ b/third_party/blink/renderer/core/frame/reporting_context.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/frame/csp/csp_violation_report_body.h"
 #include "third_party/blink/renderer/core/frame/deprecation/deprecation_report_body.h"
 #include "third_party/blink/renderer/core/frame/document_policy_violation_report_body.h"
+#include "third_party/blink/renderer/core/frame/integrity_violation_report_body.h"
 #include "third_party/blink/renderer/core/frame/intervention_report_body.h"
 #include "third_party/blink/renderer/core/frame/permissions_policy_violation_report_body.h"
 #include "third_party/blink/renderer/core/frame/report.h"
@@ -188,6 +189,7 @@
         type == ReportType::kDeprecation ||
         type == ReportType::kPermissionsPolicyViolation ||
         type == ReportType::kPotentialPermissionsPolicyViolation ||
+        type == ReportType::kIntegrityViolation ||
         type == ReportType::kIntervention ||
         type == ReportType::kDocumentPolicyViolation)) {
     return;
@@ -224,6 +226,12 @@
         url, body->id(), body->AnticipatedRemoval(),
         body->message().IsNull() ? g_empty_string : body->message(),
         body->sourceFile(), line_number, column_number);
+  } else if (type == ReportType::kIntegrityViolation) {
+    const IntegrityViolationReportBody* body =
+        static_cast<IntegrityViolationReportBody*>(report->body());
+    GetReportingService()->QueueIntegrityViolationReport(
+        url, endpoint, body->documentURL(), body->blockedURL(),
+        body->destination(), body->reportOnly());
   } else if (type == ReportType::kPermissionsPolicyViolation) {
     // Send the permissions policy violation report.
     const PermissionsPolicyViolationReportBody* body =
diff --git a/third_party/blink/renderer/core/frame/reporting_context_test.cc b/third_party/blink/renderer/core/frame/reporting_context_test.cc
index 79304e5..a7cca49 100644
--- a/third_party/blink/renderer/core/frame/reporting_context_test.cc
+++ b/third_party/blink/renderer/core/frame/reporting_context_test.cc
@@ -101,6 +101,17 @@
       std::move(reached_callback_).Run();
   }
 
+  void QueueIntegrityViolationReport(const KURL& url,
+                                     const String& endpoint,
+                                     const String& document_url,
+                                     const String& blocked_url,
+                                     const String& destionation,
+                                     bool report_only) override {
+    if (reached_callback_) {
+      std::move(reached_callback_).Run();
+    }
+  }
+
   void QueuePermissionsPolicyViolationReport(const KURL& url,
                                              const String& endpoint,
                                              const String& policy_id,
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc
index 42b6e18..fbcd3a2 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -52,6 +52,7 @@
 #include "third_party/blink/renderer/core/dom/node_traversal.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element.h"
 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
 #include "third_party/blink/renderer/core/html/forms/form_data.h"
 #include "third_party/blink/renderer/core/html/forms/html_button_element.h"
@@ -337,7 +338,8 @@
   }
 
   SelectElementAccessibilityIssueReason CheckForIssue(const Node& descendant) {
-    if (descendant.getNodeType() == Node::kCommentNode) {
+    if (descendant.getNodeType() == Node::kCommentNode ||
+        IsAutonomousCustomElement(descendant)) {
       return SelectElementAccessibilityIssueReason::kValidChild;
     }
     // Get the parent of the descendant.
@@ -370,7 +372,8 @@
         (IsAllowedPhrasingContent(*parent) && !IsA<HTMLSpanElement>(*parent))) {
       return CheckDescedantOfOption(descendant);
     }
-    if (IsA<HTMLDivElement>(*parent) || IsA<HTMLSpanElement>(*parent)) {
+    if (IsA<HTMLDivElement>(*parent) || IsA<HTMLSpanElement>(*parent) ||
+        IsAutonomousCustomElement(*parent)) {
       return TraverseAncestorsAndCheckDescendant(descendant);
     }
     if ((IsA<HTMLNoScriptElement>(*parent) || IsA<HTMLScriptElement>(*parent) ||
@@ -432,7 +435,8 @@
   SelectElementAccessibilityIssueReason CheckDescedantOfOption(
       const Node& descendant) {
     if (!IsA<HTMLDivElement>(descendant) &&
-        !IsAllowedPhrasingContent(descendant)) {
+        !IsAllowedPhrasingContent(descendant) &&
+        !IsAutonomousCustomElement(descendant)) {
       return SelectElementAccessibilityIssueReason::
           kNonPhrasingContentOptionChild;
     }
@@ -546,6 +550,17 @@
     return false;
   }
 
+  bool IsAutonomousCustomElement(const Node& node) {
+    if (node.IsCustomElement()) {
+      if (auto* element = DynamicTo<Element>(node)) {
+        if (CustomElement::IsValidName(element->localName())) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   Member<HTMLSelectElement> select_;
   Member<MutationObserver> observer_;
 };
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_element.h b/third_party/blink/renderer/core/html/track/vtt/vtt_element.h
index 2e18601..cabd423 100644
--- a/third_party/blink/renderer/core/html/track/vtt/vtt_element.h
+++ b/third_party/blink/renderer/core/html/track/vtt/vtt_element.h
@@ -26,6 +26,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_VTT_VTT_ELEMENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_VTT_VTT_ELEMENT_H_
 
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/core/html/track/text_track.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -63,12 +64,12 @@
   AtomicString Language() const { return language_; }
   void SetLanguage(AtomicString value) { language_ = value; }
 
-  static const QualifiedName& VoiceAttributeName() {
+  CORE_EXPORT static const QualifiedName& VoiceAttributeName() {
     DEFINE_STATIC_LOCAL(QualifiedName, voice_attr, (AtomicString("voice")));
     return voice_attr;
   }
 
-  static const QualifiedName& LangAttributeName() {
+  CORE_EXPORT static const QualifiedName& LangAttributeName() {
     DEFINE_STATIC_LOCAL(QualifiedName, attr, (AtomicString("lang")));
     return attr;
   }
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 0d0da47a..a8d922cb 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -433,6 +433,8 @@
       return protocol::Network::BlockedReasonEnum::Origin;
     case ResourceRequestBlockedReason::kInspector:
       return protocol::Network::BlockedReasonEnum::Inspector;
+    case ResourceRequestBlockedReason::kIntegrity:
+      return protocol::Network::BlockedReasonEnum::Integrity;
     case ResourceRequestBlockedReason::kSubresourceFilter:
       return protocol::Network::BlockedReasonEnum::SubresourceFilter;
     case ResourceRequestBlockedReason::kContentType:
diff --git a/third_party/blink/renderer/core/layout/gap_fragment_data.cc b/third_party/blink/renderer/core/layout/gap_fragment_data.cc
index 8b2f414..7e8280a 100644
--- a/third_party/blink/renderer/core/layout/gap_fragment_data.cc
+++ b/third_party/blink/renderer/core/layout/gap_fragment_data.cc
@@ -70,4 +70,59 @@
   return result.ToString();
 }
 
+PhysicalRect GapGeometry::ComputeInkOverflowForGaps(
+    WritingDirectionMode writing_direction,
+    const PhysicalSize& container_size,
+    LayoutUnit inline_thickness,
+    LayoutUnit block_thickness) const {
+  // One of the two intersection lists must be non-empty. If both are empty,
+  // it means there are no gaps in the container, hence we wouldn't have a
+  // gap geometry.
+  CHECK(!row_intersections_.empty() || !column_intersections_.empty());
+
+  LayoutUnit inline_start;
+  LayoutUnit inline_size;
+  LayoutUnit block_start;
+  LayoutUnit block_size;
+
+  // To determine the inline bounds, we'd typically use the rows intersections
+  // but in the case where there are no row intersections (i.e. no row gaps) we
+  // fallback to using the column intersections.
+  if (row_intersections_.empty()) {
+    inline_start = column_intersections_.front().front().inline_offset;
+    inline_size = column_intersections_.back().back().inline_offset -
+                  column_intersections_.front().front().inline_offset;
+  } else {
+    inline_start = row_intersections_.front().front().inline_offset;
+    inline_size = row_intersections_.back().back().inline_offset -
+                  row_intersections_.front().front().inline_offset;
+  }
+
+  // Similarly, to determine the block bounds, we'd typically use the columns
+  // intersections but in the case where there are no column
+  // intersections (i.e. no column gaps) we fallback to using the row
+  // intersections.
+  if (column_intersections_.empty()) {
+    block_start = row_intersections_.front().front().block_offset;
+    block_size = row_intersections_.back().back().block_offset -
+                 row_intersections_.front().front().block_offset;
+  } else {
+    block_start = column_intersections_.front().front().block_offset;
+    block_size = column_intersections_.back().back().block_offset -
+                 column_intersections_.front().front().block_offset;
+  }
+
+  // Inflate the bounds to account for the gap decorations thickness.
+  inline_start -= inline_thickness / 2;
+  inline_size += inline_thickness;
+  block_start -= block_thickness / 2;
+  block_size += block_thickness;
+
+  LogicalRect logical_rect(inline_size, block_start, inline_size, block_size);
+  WritingModeConverter converter(writing_direction, container_size);
+  PhysicalRect physical_rect = converter.ToPhysical(logical_rect);
+
+  return physical_rect;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/gap_fragment_data.h b/third_party/blink/renderer/core/layout/gap_fragment_data.h
index 84b25ce..b1e1320 100644
--- a/third_party/blink/renderer/core/layout/gap_fragment_data.h
+++ b/third_party/blink/renderer/core/layout/gap_fragment_data.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GAP_FRAGMENT_DATA_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/geometry/writing_mode_converter.h"
 #include "third_party/blink/renderer/core/style/grid_enums.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -87,6 +88,12 @@
   const Vector<GapIntersectionList>& GetGapIntersections(
       GridTrackSizingDirection track_direction) const;
 
+  // Computes the physical bounding rect for gap decorations ink overflow.
+  PhysicalRect ComputeInkOverflowForGaps(WritingDirectionMode writing_direction,
+                                         const PhysicalSize& container_size,
+                                         LayoutUnit inline_thickness,
+                                         LayoutUnit block_thickness) const;
+
   ContainerType GetContainerType() const { return container_type_; }
 
   void SetInlineGapSize(LayoutUnit size) { inline_gap_size_ = size; }
diff --git a/third_party/blink/renderer/core/layout/physical_box_fragment.cc b/third_party/blink/renderer/core/layout/physical_box_fragment.cc
index d92a38a..8a3f38f2 100644
--- a/third_party/blink/renderer/core/layout/physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/physical_box_fragment.cc
@@ -115,6 +115,30 @@
   }
 }
 
+int MaxGapDecorationsWidth(const GapDataList<int>& width_value) {
+  const auto widths = width_value.GetGapDataList();
+  CHECK(!widths.empty());
+
+  const auto& first_width = widths[0];
+  int max_width =
+      !first_width.IsRepeaterData()
+          ? first_width.GetValue()
+          : first_width.GetValueRepeater()->RepeatedValues().front();
+
+  for (const auto& width : widths) {
+    if (!width.IsRepeaterData()) {
+      max_width = std::max(max_width, width.GetValue());
+    } else {
+      const auto& repeated_values = width.GetValueRepeater()->RepeatedValues();
+      for (const auto& value : repeated_values) {
+        max_width = std::max(max_width, value);
+      }
+    }
+  }
+
+  return max_width;
+}
+
 }  // namespace
 
 // static
@@ -1061,6 +1085,18 @@
     rect.Inflate(LayoutUnit(OutlinePainter::OutlineOutsetExtent(style, info)));
     ink_overflow.Unite(rect);
   }
+
+  if (const GapGeometry* gap_geometry = GetGapGeometry()) {
+    LayoutUnit inline_thickness =
+        LayoutUnit(MaxGapDecorationsWidth(style.ColumnRuleWidth()));
+    LayoutUnit block_thickness =
+        LayoutUnit(MaxGapDecorationsWidth(style.RowRuleWidth()));
+    PhysicalRect rect = gap_geometry->ComputeInkOverflowForGaps(
+        Style().GetWritingDirection(), Size(), inline_thickness,
+        block_thickness);
+    ink_overflow.Unite(rect);
+  }
+
   return ink_overflow;
 }
 
diff --git a/third_party/blink/renderer/core/layout/physical_box_fragment.h b/third_party/blink/renderer/core/layout/physical_box_fragment.h
index f774ae3e62..cf920d8 100644
--- a/third_party/blink/renderer/core/layout/physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/physical_box_fragment.h
@@ -167,7 +167,7 @@
            !Style().ShouldIgnoreOverflowPropertyForInlineBlockBaseline();
   }
 
-  const GapGeometry* GapGeometry() const {
+  const GapGeometry* GetGapGeometry() const {
     return rare_data_ ? rare_data_->gap_geometry_.Get() : nullptr;
   }
 
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index 56be385..de6b6b3 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
 #include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/integrity_policy.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -163,6 +164,7 @@
 
   ContentSecurityPolicy* csp =
       GetContentSecurityPolicyForWorld(options.world_for_csp.Get());
+
   if (csp &&
       !csp->AllowRequest(request_context, request_destination, request_mode,
                          url, options.content_security_policy_nonce,
@@ -171,6 +173,7 @@
                          reporting_disposition, check_header_type)) {
     return ResourceRequestBlockedReason::kCSP;
   }
+
   return std::nullopt;
 }
 
@@ -257,6 +260,12 @@
     return ResourceRequestBlockedReason::kCSP;
   }
 
+  if (!IntegrityPolicy::AllowRequest(GetExecutionContext(), request_destination,
+                                     request_mode, options.integrity_metadata,
+                                     url)) {
+    return ResourceRequestBlockedReason::kIntegrity;
+  }
+
   if (type == ResourceType::kScript) {
     if (!AllowScript()) {
       // TODO(estark): Use a different ResourceRequestBlockedReason here, since
diff --git a/third_party/blink/renderer/core/loader/frame_loader_test.cc b/third_party/blink/renderer/core/loader/frame_loader_test.cc
index 45b49bc0..13ebef0 100644
--- a/third_party/blink/renderer/core/loader/frame_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader_test.cc
@@ -258,6 +258,8 @@
   params->policy_container = std::make_unique<WebPolicyContainer>(
       WebPolicyContainerPolicies{
           network::mojom::CrossOriginEmbedderPolicyValue::kNone,
+          network::IntegrityPolicy(),
+          network::IntegrityPolicy(),
           network::mojom::ReferrerPolicy::kAlways,
           std::vector<WebContentSecurityPolicy>(),
       },
@@ -269,6 +271,7 @@
   EXPECT_EQ(*mojom::blink::PolicyContainerPolicies::New(
                 network::CrossOriginEmbedderPolicy(
                     network::mojom::CrossOriginEmbedderPolicyValue::kNone),
+                network::IntegrityPolicy(), network::IntegrityPolicy(),
                 network::mojom::ReferrerPolicy::kAlways,
                 Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
                 /*anonymous=*/false, network::mojom::WebSandboxFlags::kNone,
diff --git a/third_party/blink/renderer/core/paint/box_fragment_painter.cc b/third_party/blink/renderer/core/paint/box_fragment_painter.cc
index b87c36da..78c4e1c 100644
--- a/third_party/blink/renderer/core/paint/box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_fragment_painter.cc
@@ -1330,7 +1330,7 @@
 
 void BoxFragmentPainter::PaintGapDecorations(const PaintInfo& paint_info,
                                              const PhysicalRect& paint_rect) {
-  if (const GapGeometry* gap_geometry = box_fragment_.GapGeometry()) {
+  if (const GapGeometry* gap_geometry = box_fragment_.GetGapGeometry()) {
     EGapRulePaintOrder paint_order = box_fragment_.Style().GapRulePaintOrder();
     // `gap-rule-paint-order` dictates whether to paint the columns over the
     // rows, or the rows over the columns. The default is to paint the rows over
@@ -1699,7 +1699,7 @@
 // is implemented for multi-column.
 void BoxFragmentPainter::PaintColumnRules(const PaintInfo& paint_info,
                                           const PhysicalOffset& paint_offset) {
-  if (box_fragment_.GapGeometry()) {
+  if (box_fragment_.GetGapGeometry()) {
     return;
   }
 
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index b3f134d..b6b3fef1 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2135,7 +2135,7 @@
   // doesn't account for them.
   bool HasVisualOverflowingEffect() const {
     return BoxShadow() || HasBorderImageOutsets() || HasOutline() ||
-           HasMaskBoxImageOutsets();
+           HasMaskBoxImageOutsets() || HasGapRule();
   }
 
   bool IsStackedWithoutContainment() const {
diff --git a/third_party/blink/renderer/core/svg/svg_resource_document_content.cc b/third_party/blink/renderer/core/svg/svg_resource_document_content.cc
index 08cfe82..0b2cdb9 100644
--- a/third_party/blink/renderer/core/svg/svg_resource_document_content.cc
+++ b/third_party/blink/renderer/core/svg/svg_resource_document_content.cc
@@ -232,22 +232,11 @@
     return nullptr;
   }
   auto* svg_target =
-      DynamicTo<SVGElement>(document->getElementById(element_id));
-  if (!svg_target) {
-    return nullptr;
-  }
-  return &svg_target->EnsureResourceTarget();
-}
-
-// TODO(dmangal): incorporate the below function into `GetResourceTarget`.
-SVGResourceTarget* SVGResourceDocumentContent::GetResourceTargetForRoot()
-    const {
-  Document* document = GetDocument();
-  if (!document) {
-    return nullptr;
-  }
-  auto* svg_target = DynamicTo<SVGSVGElement>(document->documentElement());
-
+      element_id.empty() &&
+              RuntimeEnabledFeatures::
+                  AllowSvgUseToReferenceExternalDocumentRootEnabled()
+          ? DynamicTo<SVGSVGElement>(document->documentElement())
+          : DynamicTo<SVGElement>(document->getElementById(element_id));
   if (!svg_target) {
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/svg/svg_resource_document_content.h b/third_party/blink/renderer/core/svg/svg_resource_document_content.h
index 7d293ca..7044316 100644
--- a/third_party/blink/renderer/core/svg/svg_resource_document_content.h
+++ b/third_party/blink/renderer/core/svg/svg_resource_document_content.h
@@ -100,7 +100,6 @@
   void NotifyObservers();
 
   SVGResourceTarget* GetResourceTarget(const AtomicString& element_id);
-  SVGResourceTarget* GetResourceTargetForRoot() const;
   void Trace(Visitor*) const;
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.cc b/third_party/blink/renderer/core/svg/svg_use_element.cc
index 2881b328..7a15388 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -318,26 +318,14 @@
 }
 
 Element* SVGUseElement::ResolveTargetElement() {
-  if (!element_url_.HasFragmentIdentifier()) {
-    // TODO(dmangal): Cleanup the below code to integrate more with the rest of
-    // the logic in this function
-    if (RuntimeEnabledFeatures::
-            AllowSvgUseToReferenceExternalDocumentRootEnabled() &&
-        IsStructurallyExternal() && document_content_) {
-      // Take the root SVG element from the external document
-      external_resource_target_ = document_content_->GetResourceTargetForRoot();
-
-      return external_resource_target_ ? external_resource_target_->target
-                                       : nullptr;
-    }
-
-    return nullptr;
-  }
-
   AtomicString element_identifier(DecodeURLEscapeSequences(
       element_url_.FragmentIdentifier(), DecodeURLMode::kUTF8OrIsomorphic));
 
   if (!IsStructurallyExternal()) {
+    if (!element_url_.HasFragmentIdentifier()) {
+      return nullptr;
+    }
+
     // Only create observers for non-instance use elements.
     // Instances will be updated by their corresponding elements.
     if (InUseShadowTree()) {
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc
index 1fe0060..35e899d 100644
--- a/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -913,8 +913,7 @@
   InteractiveDetector* interactive_detector =
       InteractiveDetector::From(*(DomWindow()->document()));
 
-  bool tracing_enabled;
-  TRACE_EVENT_CATEGORY_GROUP_ENABLED("devtools.timeline", &tracing_enabled);
+  bool tracing_enabled = TRACE_EVENT_CATEGORY_ENABLED("latency");
 
   while (!event_timing_entries_.empty()) {
     // Find the range [first, last) of events with the same presentation_index
@@ -961,10 +960,10 @@
       auto scope = perfetto::Track::ThreadScoped(this);
       auto flowid = perfetto::Flow::ProcessScoped(presentation_index);
 
-      TRACE_EVENT_BEGIN("devtools.timeline", "EventsInAnimationFrame", scope,
+      TRACE_EVENT_BEGIN("latency", "EventsInAnimationFrame", scope,
                         first_event_processing_start, flowid);
 
-      TRACE_EVENT_INSTANT("devtools.timeline", "EventCreation", scope,
+      TRACE_EVENT_INSTANT("latency", "EventCreation", scope,
                           first_event_creation_time, flowid);
     }
 
@@ -989,10 +988,10 @@
       auto scope = perfetto::Track::ThreadScoped(this);
       auto flowid = perfetto::Flow::ProcessScoped(presentation_index);
 
-      TRACE_EVENT_END("devtools.timeline", scope, frame_end_time);
+      TRACE_EVENT_END("latency", scope, frame_end_time);
 
       if (!last_event_presentation_time.is_null()) {
-        TRACE_EVENT_INSTANT("devtools.timeline", "EventPresentation", scope,
+        TRACE_EVENT_INSTANT("latency", "EventPresentation", scope,
                             last_event_presentation_time, flowid);
       }
 
@@ -1003,7 +1002,7 @@
                                          ->fallback_time.is_null();
                            });
           first_entry_with_fallback != last) {
-        TRACE_EVENT_INSTANT("devtools.timeline", "EventFallbackTime", scope,
+        TRACE_EVENT_INSTANT("latency", "EventFallbackTime", scope,
                             first_entry_with_fallback->Get()
                                 ->GetEventTimingReportingInfo()
                                 ->fallback_time,
@@ -1199,10 +1198,11 @@
     AddToEventTimingBuffer(*entry);
   }
 
-  bool tracing_enabled;
-  TRACE_EVENT_CATEGORY_GROUP_ENABLED("devtools.timeline", &tracing_enabled);
+  bool latency_tracing_enabled = TRACE_EVENT_CATEGORY_ENABLED("latency");
+  bool devtools_tracing_enabled =
+      TRACE_EVENT_CATEGORY_ENABLED("devtools.timeline");
 
-  if (tracing_enabled) {
+  if (latency_tracing_enabled || devtools_tracing_enabled) {
     base::TimeTicks unsafe_start_time =
         entry->GetEventTimingReportingInfo()->creation_time;
     base::TimeTicks unsafe_end_time = entry->GetEndTime();
@@ -1210,18 +1210,18 @@
     WTF::AddFloatToHash(hash, entry->startTime());
     auto track_id = perfetto::Track::ThreadScoped(this);
     auto flow_id = perfetto::Flow::FromPointer(entry);
-    TRACE_EVENT_INSTANT("devtools.timeline", "EventCreation", track_id,
+    TRACE_EVENT_INSTANT("latency", "EventCreation", track_id,
                         entry->GetEventTimingReportingInfo()->creation_time,
                         flow_id);
     auto enqueued_to_main_thread_time =
         entry->GetEventTimingReportingInfo()->enqueued_to_main_thread_time;
     if (!enqueued_to_main_thread_time.is_null()) {
-      TRACE_EVENT_INSTANT("devtools.timeline", "EventEnqueuedToMainThread",
-                          track_id, enqueued_to_main_thread_time, flow_id);
+      TRACE_EVENT_INSTANT("latency", "EventEnqueuedToMainThread", track_id,
+                          enqueued_to_main_thread_time, flow_id);
     }
 
     TRACE_EVENT_BEGIN(
-        "devtools.timeline", "EventProcessing", track_id,
+        "latency", "EventProcessing", track_id,
         entry->GetEventTimingReportingInfo()->processing_start_time, flow_id,
         [&](perfetto::EventContext ctx) {
           auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
@@ -1229,9 +1229,8 @@
           entry->SetPerfettoData(DomWindow()->GetFrame(), data,
                                  GetTimeOriginInternal());
         });
-    TRACE_EVENT_END("devtools.timeline", track_id,
+    TRACE_EVENT_END("latency", track_id,
                     entry->GetEventTimingReportingInfo()->processing_end_time);
-
     // TODO(sullivan): Remove these events when DevTools migrates to the above
     // perfetto events.
     TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1(
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index b5a309c..3788f76b 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1977,7 +1977,10 @@
   ]
   testonly = true
 
+  defines = [ "BLINK_PLATFORM_TEST_IMPLEMENTATION" ]
+
   sources = [
+    "graphics/gpu/drawing_buffer_test_helpers.cc",
     "graphics/gpu/drawing_buffer_test_helpers.h",
     "graphics/paint/paint_controller_test.h",
     "graphics/test/fake_canvas_resource_host.h",
@@ -1990,6 +1993,7 @@
     "graphics/test/mock_compositor_frame_sink_client.h",
     "graphics/test/mock_embedded_frame_sink_provider.h",
     "graphics/test/mock_frame_sink_bundle.h",
+    "graphics/test/mock_image_decoder.cc",
     "graphics/test/mock_image_decoder.h",
     "graphics/test/mock_paint_canvas.h",
     "graphics/test/stub_image.h",
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.cc
new file mode 100644
index 0000000..36a4f9c
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.cc
@@ -0,0 +1,29 @@
+// Copyright 2025 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/351564777): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
+#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h"
+
+namespace blink {
+
+void GLES2InterfaceForTests::GenTextures(GLsizei n, GLuint* textures) {
+  static GLuint id = 1;
+  for (GLsizei i = 0; i < n; ++i) {
+    textures[i] = id++;
+  }
+}
+
+// ImplementationBase implementation
+void GLES2InterfaceForTests::GenSyncTokenCHROMIUM(GLbyte* sync_token) {
+  static gpu::CommandBufferId::Generator command_buffer_id_generator;
+  gpu::SyncToken source(gpu::GPU_IO,
+                        command_buffer_id_generator.GenerateNextId(), 2);
+  memcpy(sync_token, &source, sizeof(source));
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
index 831bf569..91889076 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
@@ -234,11 +234,10 @@
     }
   }
 
-  void GenTextures(GLsizei n, GLuint* textures) override {
-    static GLuint id = 1;
-    for (GLsizei i = 0; i < n; ++i)
-      textures[i] = id++;
-  }
+  void GenTextures(GLsizei n, GLuint* textures) override;
+
+  // ImplementationBase implementation
+  void GenSyncTokenCHROMIUM(GLbyte* sync_token) override;
 
   MOCK_METHOD1(CreateAndTexStorage2DSharedImageCHROMIUMMock,
                void(const GLbyte*));
@@ -253,14 +252,6 @@
     return texture_id;
   }
 
-  // ImplementationBase implementation
-  void GenSyncTokenCHROMIUM(GLbyte* sync_token) override {
-    static gpu::CommandBufferId::Generator command_buffer_id_generator;
-    gpu::SyncToken source(gpu::GPU_IO,
-                          command_buffer_id_generator.GenerateNextId(), 2);
-    memcpy(sync_token, &source, sizeof(source));
-  }
-
   MOCK_METHOD1(WaitSyncTokenCHROMIUMMock, void(const GLbyte* sync_token));
   void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override {
     memcpy(&most_recently_waited_sync_token_, sync_token,
diff --git a/third_party/blink/renderer/platform/graphics/test/mock_image_decoder.cc b/third_party/blink/renderer/platform/graphics/test/mock_image_decoder.cc
new file mode 100644
index 0000000..7c49da5
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/test/mock_image_decoder.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2025 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h"
+
+namespace blink {
+
+const AtomicString& MockImageDecoder::MimeType() const {
+  DEFINE_STATIC_LOCAL(const AtomicString, mock_mime_type, ("image/x-mock"));
+  return mock_mime_type;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h b/third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h
index ce83001..f96b862c 100644
--- a/third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h
+++ b/third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h
@@ -86,10 +86,7 @@
 
   String FilenameExtension() const override { return "mock"; }
 
-  const AtomicString& MimeType() const override {
-    DEFINE_STATIC_LOCAL(const AtomicString, mock_mime_type, ("image/x-mock"));
-    return mock_mime_type;
-  }
+  const AtomicString& MimeType() const override;
 
   int RepetitionCount() const override { return client_->RepetitionCount(); }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
index 6199246..c43b1e50 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
@@ -302,6 +302,9 @@
     case ResourceRequestBlockedReason::kInspector:
       detail = "Inspector";
       break;
+    case ResourceRequestBlockedReason::kIntegrity:
+      detail = "Integrity";
+      break;
     case ResourceRequestBlockedReason::kSubresourceFilter:
       detail = "SubresourceFilter";
       break;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index d656a6fe..3152c3b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1262,6 +1262,8 @@
       ResourceRequestBlockedReason::kCSP) {
     return ResourceRequestBlockedReason::kCSP;
   }
+  // Here we check for CSP but not for IntegrityPolicy, as IntegrityPolicy does
+  // not yet cover image destinations.
 
   return std::nullopt;
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index d2ddf9b..609cd47 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -664,6 +664,7 @@
 
     // CanRequest() checks only enforced CSP, so check report-only here to
     // ensure that violations are sent.
+    // CanRequest() will also perform IntegrityPolicy verifications if needed.
     Context().CheckCSPForRequest(
         request_context, request_destination, request_mode,
         new_url_prior_upgrade, options, reporting_disposition,
@@ -978,6 +979,7 @@
     //
     // CanRequest() below only checks enforced policies: check report-only
     // here to ensure violations are sent.
+    // CanRequest() will also perform IntegrityPolicy verifications if needed.
     const KURL& response_url = response.ResponseUrl();
     Context().CheckCSPForRequest(
         request_context, request_destination, request_mode, response_url,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request_utils.cc b/third_party/blink/renderer/platform/loader/fetch/resource_request_utils.cc
index 7558751..8225853e 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request_utils.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request_utils.cc
@@ -251,6 +251,8 @@
       options, reporting_disposition,
       MemoryCache::RemoveFragmentIdentifierIfNeeded(url_before_redirects),
       redirect_status);
+  // There's no need to add an integrity policy check here, as CanRequest() will
+  // do that below.
 
   context.PopulateResourceRequestBeforeCacheAccess(options, resource_request);
   if (!resource_request.Url().IsValid()) {
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc
index ef6a44b9..2164741 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -49,6 +49,7 @@
 #include "services/network/public/cpp/parsed_headers.h"
 #include "services/network/public/cpp/sri_message_signatures.h"
 #include "services/network/public/cpp/timing_allow_origin_parser.h"
+#include "services/network/public/mojom/integrity_policy.mojom-blink.h"
 #include "services/network/public/mojom/no_vary_search.mojom-blink-forward.h"
 #include "services/network/public/mojom/no_vary_search.mojom-blink.h"
 #include "services/network/public/mojom/parsed_headers.mojom-blink.h"
@@ -165,6 +166,16 @@
       ConvertToBlink(in->path), in->is_host_wildcard, in->is_port_wildcard);
 }
 
+blink::IntegrityPolicy::Destination ConvertToBlink(
+    const IntegrityPolicy::Destination& in) {
+  return blink::IntegrityPolicy::Destination(in);
+}
+
+blink::IntegrityPolicy::Source ConvertToBlink(
+    const IntegrityPolicy::Source& in) {
+  return blink::IntegrityPolicy::Source(in);
+}
+
 blink::CSPHashSourcePtr ConvertToBlink(const CSPHashSourcePtr& in) {
   CHECK(in);
   Vector<uint8_t> hash_value = ConvertToBlink(in->value);
@@ -198,6 +209,14 @@
       ConvertToBlink(in->header_value), in->type, in->source);
 }
 
+blink::IntegrityPolicyPtr ConvertToBlink(const IntegrityPolicyPtr& in) {
+  Vector<blink::IntegrityPolicy::Destination> blocked_destinations =
+      ConvertToBlink(in->blocked_destinations);
+  return blink::IntegrityPolicy::New(
+      std::move(blocked_destinations), ConvertToBlink(in->sources),
+      ConvertToBlink(in->endpoints), ConvertToBlink(in->parsing_errors));
+}
+
 blink::CSPTrustedTypesPtr ConvertToBlink(const CSPTrustedTypesPtr& in) {
   if (!in)
     return nullptr;
@@ -347,6 +366,7 @@
       ConvertToBlink(in->content_security_policy),
       ConvertToBlink(in->allow_csp_from), in->cross_origin_embedder_policy,
       in->cross_origin_opener_policy, in->document_isolation_policy,
+      in->integrity_policy, in->integrity_policy_report_only,
       in->origin_agent_cluster,
       in->accept_ch.has_value()
           ? std::make_optional(ConvertToBlink(in->accept_ch.value()))
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 2b3bfc0..7d2ae929 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2666,6 +2666,12 @@
       status: "experimental",
     },
     {
+      name: "IntegrityPolicyScript",
+      status: "experimental",
+      base_feature: "none",
+      public: true,
+    },
+    {
       name: "InterestGroupsInSharedStorageWorklet",
       public: true,
       status: "stable",
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 8b83765..ab5841f 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
@@ -1357,6 +1357,14 @@
     },
     {
         'paths': [
+            'third_party/blink/public/platform/web_policy_container.h',
+        ],
+        'allowed': [
+            'network::IntegrityPolicy',
+        ],
+    },
+    {
+        'paths': [
             'third_party/blink/public/platform/web_audio_device.h',
             'third_party/blink/public/web/web_local_frame_client.h',
             'third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc',
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 172e772..80c0a73f 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6319,10 +6319,6 @@
 crbug.com/357648037 virtual/css-gap-decorations/external/wpt/css/css-multicol/column-height-009.html [ Failure ]
 # These tests are failing due to not handling OOF in multicol, will be addressed in follow up CL.
 crbug.com/357648037 virtual/css-gap-decorations/external/wpt/css/css-multicol/multicol-nested-column-rule-002.html [ Failure ]
-# These tests are failing due to a known paint issue on overflow cases:
-crbug.com/357648037 virtual/css-gap-decorations/fast/multicol/many-lines-overflow-in-single-row-inner.html [ Failure ]
-crbug.com/357648037 virtual/css-gap-decorations/external/wpt/css/css-gaps/tentative/multicol/multicol-gap-decorations-013.html [ Failure ]
-crbug.com/357648037 virtual/css-gap-decorations/external/wpt/css/css-gaps/flex/flex-gap-decorations-008.html [ Failure ]
 # This test is failing due to known issue with the scrollability of when we paint the gaps:
 crbug.com/357648037 virtual/css-gap-decorations/external/wpt/css/css-multicol/column-rule-001.html [ Failure ]
 ### End of tests failing with CSSGapDecorations Enabled
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index d8d8bcb..8d2f75a 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -131,6 +131,19 @@
     "expires": "July 31, 2025"
   },
 
+  {
+    "prefix": "lna",
+    "platforms": ["Linux", "Mac", "Win"],
+    "bases": ["external/wpt/fetch/local-network-access"],
+    "args": ["--enable-features=LocalNetworkAccessChecks:LocalNetworkAccessChecksWarn/false"],
+    "exclusive_tests": "ALL",
+    "owners": [
+      "cthomp@chromium.org",
+      "hchao@chromium.org",
+      "chrome-secure-web-and-net@chromium.org"],
+    "expires": "Oct 2, 2025"
+  },
+
   "This never expires because it tests a shipping configuration",
   {
     "prefix": "gpu",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 252a913..8f74d0c 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -492815,7 +492815,7 @@
       ]
      ],
      "anchor-position-grid-001.html": [
-      "92fb4d275b8988641ed0736969e918703e4d649d",
+      "7bd389b39d8d6642f02181e475bbc5eaa7322f2d",
       [
        null,
        {}
@@ -492857,7 +492857,7 @@
       ]
      ],
      "anchor-position-multicol-002.html": [
-      "7b2691a2b904ffb7fdc3d720b07ca454e1df7fe1",
+      "1e1f0a5c95b1b5f1d86efc5f22ffc87afbbab453",
       [
        null,
        {}
@@ -492871,7 +492871,7 @@
       ]
      ],
      "anchor-position-multicol-004.html": [
-      "399494120ea0ea5da5534a0a14a9b99e598222d5",
+      "8f7a3dad12915ddbea9bd88077694434d0a17b48",
       [
        null,
        {}
@@ -492913,7 +492913,7 @@
       ]
      ],
      "anchor-position-multicol-nested-001.html": [
-      "35ab2cfc15cea1fa1788f9b4cb09f9af39d079ec",
+      "c5ce41299af29008356b7a049a3d479038379fae",
       [
        null,
        {}
@@ -496846,7 +496846,7 @@
      ],
      "table": {
       "border-spacing.html": [
-       "fc5e87e35dde4b4cb2ed5c457f5cd22ec73d96b0",
+       "9fd94760681f0186f86f9a55da300250499f2a50",
        [
         null,
         {}
@@ -496890,7 +496890,7 @@
        ]
       ],
       "table-parts-offsets-vertical-rl.tentative.html": [
-       "9d4a472d4382825c13af35114acc48a3b5face2a",
+       "1eb751032ca4b7598ee3a413408c61c5a592b3e4",
        [
         null,
         {}
@@ -510186,8 +510186,8 @@
        {}
       ]
      ],
-     "dashed-function-cycles.tentative.html": [
-      "11e653e9b7d02d944e4bd74bda6e08e838c4ea42",
+     "dashed-function-cycles.html": [
+      "15305be2b287ca3e4fbfad928f8d101ed8463104",
       [
        null,
        {}
@@ -510421,6 +510421,34 @@
        {}
       ]
      ],
+     "getclientrects-005.html": [
+      "ee60a607dccb3fdba2ed7dc99cb344071f5bb34a",
+      [
+       null,
+       {}
+      ]
+     ],
+     "getclientrects-006.html": [
+      "9f07a7de7444de7a2f91f97ff0a4fe44b7e177af",
+      [
+       null,
+       {}
+      ]
+     ],
+     "getclientrects-007.html": [
+      "0791c5b931fe3fade4c7b4483ef2469435ffbd77",
+      [
+       null,
+       {}
+      ]
+     ],
+     "getclientrects-008.html": [
+      "21505a7e48a2d2f9947342329de19dfde974d8e5",
+      [
+       null,
+       {}
+      ]
+     ],
      "going-out-of-flow-after-spanner.html": [
       "2fe0e42a7522647b7eca4db1e6f710a9975faaa4",
       [
@@ -526644,7 +526672,7 @@
         ]
        ],
        "transform.html": [
-        "7a852545a74a494348d90d727fc7266140033d2f",
+        "d12714a499c75ecbae8c4586f452d335594240fb",
         [
          null,
          {}
@@ -529822,6 +529850,13 @@
        ]
       ]
      },
+     "start-skip-start.html": [
+      "e04979472f1725b0225cdb98bbbd5222ed98c16c",
+      [
+       null,
+       {}
+      ]
+     ],
      "start-view-transtion-skips-active.html": [
       "971c7b38d4c816489caab9c611adc800b3638971",
       [
@@ -539318,7 +539353,7 @@
         }
        ]
       ],
-      "overscroll-deltas.html": [
+      "overscroll-deltas.tentative.html": [
        "e13e9f1cce5949da74227a1f069f64baad1f517c",
        [
         null,
@@ -539327,7 +539362,7 @@
         }
        ]
       ],
-      "overscroll-event-fired-to-document.html": [
+      "overscroll-event-fired-to-document.tentative.html": [
        "c054ffca9c471f78ce5d1cbaa210fa7aad3aee3b",
        [
         null,
@@ -539336,7 +539371,7 @@
         }
        ]
       ],
-      "overscroll-event-fired-to-element-with-overscroll-behavior.html": [
+      "overscroll-event-fired-to-element-with-overscroll-behavior.tentative.html": [
        "750080e6568e863a9249bc62e52971d9459f8418",
        [
         null,
@@ -539345,7 +539380,7 @@
         }
        ]
       ],
-      "overscroll-event-fired-to-scrolled-element.html": [
+      "overscroll-event-fired-to-scrolled-element.tentative.html": [
        "be4176df59d6a1d59d90beee839bc5ca6a72f1c5",
        [
         null,
@@ -539354,7 +539389,7 @@
         }
        ]
       ],
-      "overscroll-event-fired-to-window.html": [
+      "overscroll-event-fired-to-window.tentative.html": [
        "ef5ae3daef8158c9424cf07ad091c6a945456d0a",
        [
         null,
@@ -543001,7 +543036,7 @@
      ]
     ],
     "XMLSerializer-serializeToString.html": [
-     "6c294e464a5dc787abd4d10281ab2fe0555a0a3c",
+     "352a62c7d5db0710da6819bbc094ebfae46f4099",
      [
       null,
       {}
@@ -834213,7 +834248,7 @@
          ]
         ],
         "invalid.py": [
-         "49d7de8d517a11cc715eb2b0c8d11d3c6e0fb545",
+         "2334d37517df00cde8f845e7ec6412d1570e405b",
          [
           null,
           {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-029-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-029-ref.html
new file mode 100644
index 0000000..35450e07
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-029-ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-columns: 100px 100px 100px;
+    grid-template-rows: 100px 100px 100px;
+    width: 120px;
+    height: 120px;
+  }
+
+  .item {
+    background: gray;
+    opacity: 0.5;
+  }
+
+  .row-gap {
+    position: absolute;
+    width: 320px;
+    height: 0px;
+    border-bottom: solid 5px red;
+  }
+
+  .row-gap1 {
+    top: 102.5px;
+  }
+
+  .row-gap2 {
+    top: 212.5px;
+  }
+
+  .col-gap {
+    position: absolute;
+    top: 0px;
+    width: 0px;
+    height: 320px;
+    border-left: solid 5px blue;
+  }
+
+  .col-gap1 {
+    left: 102.5px;
+  }
+
+  .col-gap2 {
+    left: 212.5px;
+  }
+</style>
+<div class="grid-container">
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+</div>
+
+<div class="col-gap col-gap1"> </div>
+<div class="col-gap col-gap2"> </div>
+
+<div class="row-gap row-gap1"> </div>
+<div class="row-gap row-gap2"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-029.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-029.html
new file mode 100644
index 0000000..6da75548
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-029.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>
+  CSS Gap Decorations: Gaps are painted when items overflow container.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-029-ref.html">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-columns: 100px 100px 100px;
+    grid-template-rows: 100px 100px 100px;
+    width: 120px;
+    height: 120px;
+
+    column-rule-color: blue;
+    column-rule-style: solid;
+    column-rule-width: 5px;
+
+    row-rule-color: red;
+    row-rule-style: solid;
+    row-rule-width: 5px;
+  }
+
+  .item {
+    background: gray;
+    opacity: 0.5;
+  }
+</style>
+
+<body>
+  <div class="grid-container">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+  </div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-030-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-030-ref.html
new file mode 100644
index 0000000..d4953ae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-030-ref.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-columns: 100px 100px 100px;
+    width: 120px;
+    height: 120px;
+  }
+
+  .item {
+    background: gray;
+    opacity: 0.5;
+  }
+
+  .col-gap {
+    position: absolute;
+    top: 0px;
+    width: 0px;
+    height: 120px;
+    border-left: solid 5px blue;
+  }
+
+  .col-gap1 {
+    left: 102.5px;
+  }
+
+  .col-gap2 {
+    left: 212.5px;
+  }
+</style>
+<div class="grid-container">
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+</div>
+
+<div class="col-gap col-gap1"> </div>
+<div class="col-gap col-gap2"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-030.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-030.html
new file mode 100644
index 0000000..ef4507e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-030.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>
+  CSS Gap Decorations: Gaps are painted when items overflow container - no row gaps.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-030-ref.html">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-columns: 100px 100px 100px;
+    width: 120px;
+    height: 120px;
+
+    column-rule-color: blue;
+    column-rule-style: solid;
+    column-rule-width: 5px;
+  }
+
+  .item {
+    background: gray;
+    opacity: 0.5;
+  }
+</style>
+
+<body>
+  <div class="grid-container">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+  </div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-031-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-031-ref.html
new file mode 100644
index 0000000..0615305
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-031-ref.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-rows: 100px 100px 100px;
+    grid-auto-flow: column;
+    width: 120px;
+    height: 120px;
+  }
+
+  .item {
+    background: gray;
+    opacity: 0.5;
+  }
+
+  .row-gap {
+    position: absolute;
+    width: 120px;
+    height: 0px;
+    border-bottom: solid 5px red;
+  }
+
+  .row-gap1 {
+    top: 102.5px;
+  }
+
+  .row-gap2 {
+    top: 212.5px;
+  }
+</style>
+<div class="grid-container">
+  <div class="item"></div>
+  <div class="item"></div>
+  <div class="item"></div>
+</div>
+
+<div class="row-gap row-gap1"> </div>
+<div class="row-gap row-gap2"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-031.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-031.html
new file mode 100644
index 0000000..530b661bfe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-031.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>
+  CSS Gap Decorations: Gaps are painted when items overflow container - no column gaps.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-031-ref.html">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-rows: 100px 100px 100px;
+    grid-auto-flow: column;
+    width: 120px;
+    height: 120px;
+
+    row-rule-color: red;
+    row-rule-style: solid;
+    row-rule-width: 5px;
+  }
+
+  .item {
+    background: gray;
+    opacity: 0.5;
+  }
+</style>
+
+<body>
+  <div class="grid-container">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+  </div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-032-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-032-ref.html
new file mode 100644
index 0000000..f90e3dd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-032-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+    overflow: hidden;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-columns: 100px 100px 100px;
+    grid-template-rows: repeat(6, 100px);
+    width: 120px;
+    height: 120px;
+  }
+
+  .row-gap {
+    position: absolute;
+    width: 320px;
+    height: 0px;
+    border-bottom: solid 5px red;
+  }
+
+  .row-gap1 {
+    top: 102.5px;
+  }
+
+  .row-gap2 {
+    top: 212.5px;
+  }
+
+  .row-gap3 {
+    top: 322.5px;
+  }
+
+  .row-gap4 {
+    top: 432.5px;
+  }
+
+  .row-gap5 {
+    top: 542.5px;
+  }
+
+  .col-gap {
+    position: absolute;
+    top: 0px;
+    width: 0px;
+    height: 650px;
+    border-left: solid 10px blue;
+  }
+
+  .col-gap1 {
+    left: 100px;
+  }
+
+  .col-gap2 {
+    left: 210px;
+  }
+</style>
+<div class="grid-container"></div>
+
+<div class="col-gap col-gap1"> </div>
+<div class="col-gap col-gap2"> </div>
+
+<div class="row-gap row-gap1"> </div>
+<div class="row-gap row-gap2"> </div>
+<div class="row-gap row-gap3"> </div>
+<div class="row-gap row-gap4"> </div>
+<div class="row-gap row-gap5"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-032.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-032.html
new file mode 100644
index 0000000..ac2d38f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-032.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>
+  CSS Gap Decorations: Gaps are painted when rows are dynamically added and overflow container.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-032-ref.html">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+    overflow: hidden;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-columns: 100px 100px 100px;
+    grid-template-rows: 100px;
+    width: 120px;
+    height: 120px;
+
+    column-rule-color: blue;
+    column-rule-style: solid;
+    column-rule-width: 10px;
+  }
+
+</style>
+
+<body>
+  <div class="grid-container"></div>
+<script>
+  const grid = document.querySelector('.grid-container');
+  grid.style.gridTemplateRows = 'repeat(6, 100px)';
+
+  grid.style.rowRuleColor =  'red';
+  grid.style.rowRuleStyle = 'solid';
+  grid.style.rowRuleWidth = '5px';
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-033-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-033-ref.html
new file mode 100644
index 0000000..e26143a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-033-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+    overflow: hidden;
+  }
+
+  .grid-container {
+    display: grid;
+    grid-gap: 10px;
+    grid-template-columns: repeat(3, 50px);
+    grid-template-rows: repeat(6, 50px);
+    width: 50px;
+    height: 50px;
+  }
+
+  .row-gap {
+    position: absolute;
+    width: 170px;
+    height: 0px;
+    border-bottom: solid 5px red;
+  }
+
+  .row-gap1 {
+    top: 52.5px;
+  }
+
+  .row-gap2 {
+    top: 112.5px;
+  }
+
+  .row-gap3 {
+    top: 172.5px;
+  }
+
+  .row-gap4 {
+    top: 232.5px;
+  }
+
+  .row-gap5 {
+    top: 195px;
+    border-bottom: solid 200px red; /*expand the last row gap's height*/
+  }
+
+  .col-gap {
+    position: absolute;
+    top: 0px;
+    width: 0px;
+    height: 350px;
+    border-left: solid 10px blue;
+  }
+
+  .col-gap1 {
+    left: 50px;
+  }
+
+  .col-gap2 {
+    left: 110px;
+  }
+</style>
+<div class="grid-container"></div>
+
+<div class="col-gap col-gap1"> </div>
+<div class="col-gap col-gap2"> </div>
+
+<div class="row-gap row-gap1"> </div>
+<div class="row-gap row-gap2"> </div>
+<div class="row-gap row-gap3"> </div>
+<div class="row-gap row-gap4"> </div>
+<div class="row-gap row-gap5"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-033.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-033.html
new file mode 100644
index 0000000..47ef35cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-033.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>
+  CSS Gap Decorations: Decorations are painted when rule thickness is greater than gap size.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-033-ref.html">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+    overflow: hidden;
+  }
+
+  .grid-container {
+    display: grid;
+    gap: 10px;
+    grid-template-columns: repeat(3, 50px);
+    grid-template-rows: repeat(6, 50px);
+    width: 50px;
+    height: 50px;
+
+    column-rule-color: blue;
+    column-rule-style: solid;
+    column-rule-width: 10px;
+  }
+
+</style>
+
+<body>
+  <div class="grid-container"></div>
+<script>
+  const grid = document.querySelector('.grid-container');
+
+  grid.style.rowRuleColor =  'red';
+  grid.style.rowRuleStyle = 'solid';
+  grid.style.rowRuleWidth = 'repeat(4, 5px) 200px';
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/css-scale-of-clip-path-ref.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/css-scale-of-clip-path-ref.html
new file mode 100644
index 0000000..d6fa480b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/css-scale-of-clip-path-ref.html
@@ -0,0 +1,20 @@
+<!doctype HTML>
+<style>
+.tile {
+  width: 620px;
+  height: 671px;
+  position: absolute;
+  clip-path: circle(50%);
+  background-color: lightblue;
+}
+#container {
+  transform: scale(0.25);
+  position: relative;
+  left: -200px;
+  will-change: transform;
+}
+</style>
+<div id=container>
+  <div class="tile" style="top: 520px;"></div>
+  <div class="tile" style="top: 688px; left: 390px;"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/css-scale-of-clip-path.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/css-scale-of-clip-path.html
new file mode 100644
index 0000000..dda72c0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/css-scale-of-clip-path.html
@@ -0,0 +1,23 @@
+<!doctype HTML>
+<link rel="author" title="Chris Harrelson">
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/">
+<link rel="match" href="css-scale-of-clip-path-ref.html">
+<meta name=fuzzy content="maxDifference=0-40;totalPixels=0-3000">
+<style>
+.tile {
+  width: 620px;
+  height: 671px;
+  position: absolute;
+  clip-path: circle(50%);
+  background-color: lightblue;
+}
+#container {
+  transform: scale(0.25);
+  position: relative;
+  left: -200px;
+}
+</style>
+<div id=container>
+  <div class="tile" style="top: 520px;"></div>
+  <div class="tile" style="top: 688px; left: 390px;"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-index-keyframe-value-dynamic.html b/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-index-keyframe-value-dynamic.html
new file mode 100644
index 0000000..286e0d3d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-index-keyframe-value-dynamic.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>CSS Values and Units Test: sibling-index() changing value during @keyframes animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  @keyframes --anim {
+    from {
+      z-index: sibling-index();
+    }
+    to {
+      z-index: 1;
+    }
+  }
+  #target {
+    animation: --anim 1000s step-end;
+    position: relative;
+    width: 100px;
+    height: 100px;
+    background: red;
+  }
+  #abs {
+    position: absolute;
+    width: 100px;
+    height: 100px;
+    z-index: 3;
+    background: green;
+  }
+</style>
+<p>You should see a green square below.</p>
+<div>
+  <div id="rm"></div>
+  <div id="abs"></div>
+  <div id="target"></div>
+</div>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(target).zIndex, "3");
+  }, "Initially, the sibling-index() is 3 for #target");
+
+  test(() => {
+    rm.remove();
+    assert_equals(getComputedStyle(target).zIndex, "2");
+  }, "Removing a preceding sibling of #target reduces the sibling-index()");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.tentative.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html
rename to third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.tentative.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.html
rename to third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.tentative.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html
rename to third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.tentative.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html
rename to third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-window.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-window.tentative.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-window.html
rename to third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-window.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html b/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html
index 6c294e46..352a62c 100644
--- a/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html
+++ b/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html
@@ -256,6 +256,10 @@
   root.setAttributeNS(XMLNS_URI, 'xmlns:foo', '');
   assert_equals(serialize(root), '<root xmlns="" xmlns:foo=""/>');
 }, 'Check if a prefix bound to an empty namespace URI ("no namespace") serialize');
+
+test(function() {
+  assert_equals(serialize(document.createAttribute("foobar")), "")
+}, 'Attribute nodes are serialized as the empty string')
 </script>
  </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/local-network-access/META.yml b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/META.yml
new file mode 100644
index 0000000..4c5c698
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/META.yml
@@ -0,0 +1,5 @@
+spec: https://wicg.github.io/local-network-access/
+suggested_reviewers:
+  - cthomp
+  - camillelamy
+  - hchao
diff --git a/third_party/blink/web_tests/external/wpt/fetch/local-network-access/README.md b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/README.md
new file mode 100644
index 0000000..95066cd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/README.md
@@ -0,0 +1,11 @@
+# Local Network Access tests
+
+This directory contains tests for Local Network Access' integration with
+the Fetch specification.
+
+See also:
+
+* [Explainer](https://github.com/explainers-by-googlers/local-network-access)
+
+Local Network Access replaced [Private Network
+Access](https://wicg.github.io/local-network-access/).
diff --git a/third_party/blink/web_tests/external/wpt/fetch/local-network-access/fetch.tentative.https.html b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/fetch.tentative.https.html
new file mode 100644
index 0000000..a01bad6a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/fetch.tentative.https.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>LNA Fetch tests: HTTPS and Public source </title>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/support.sub.js"></script>
+<script>
+  "use strict";
+
+  promise_test(t => {
+    const source = { server: Server.HTTPS_PUBLIC };
+    const sourceUrl =
+        resolveUrl("resources/fetch-private.html", sourceResolveOptions(source));
+
+    function checkResult(evt) {
+      const { error, ok, type, body } = evt.data;
+
+      assert_equals(ok, true, "response ok mismatch");
+      assert_equals(body, "success", "response body mismatch");
+
+      t.done();
+    }
+
+    const promise = new Promise((resolve) => {
+                      window.addEventListener('message', resolve);
+                    }).then(checkResult);
+    const popup = window.open(sourceUrl);
+    t.add_cleanup(() => popup.close());
+
+    return promise;
+}, 'LNA Public to private with permission');
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/fetch-private.html b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/fetch-private.html
new file mode 100644
index 0000000..ede16bad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/fetch-private.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Fetch Private resource</title>
+
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="support.sub.js"></script>
+<script>
+"use strict";
+
+// Grant 'local-network-access' permission then attempt to fetch a resource in the private
+// address space.
+Promise.resolve().then(async () => {
+  test_driver.set_test_context(opener);
+  await test_driver.set_permission({ name: 'local-network-access' }, 'granted');
+
+  const target = {
+    server: Server.HTTPS_PRIVATE,
+    behavior: { response: ResponseBehavior.allowCrossOrigin() },
+  };
+  const targetUrl = resolveTargetUrl(target);
+
+  fetch(targetUrl)
+      .then(async function(response) {
+        const body = await response.text();
+        const message = {
+          ok: response.ok,
+          type: response.type,
+          body: body,
+        };
+        opener.postMessage(message, "*");
+      })
+      .catch(error => {
+        opener.postMessage({ error: error.toString() }, "*");
+      });
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/support.sub.js b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/support.sub.js
new file mode 100644
index 0000000..299f004
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/support.sub.js
@@ -0,0 +1,175 @@
+// Maps protocol (without the trailing colon) and address space to port.
+const SERVER_PORTS = {
+  "http": {
+    "local": {{ports[http][0]}},
+    "private": {{ports[http-private][0]}},
+    "public": {{ports[http-public][0]}},
+  },
+  "https": {
+    "local": {{ports[https][0]}},
+    "other-local": {{ports[https][1]}},
+    "private": {{ports[https-private][0]}},
+    "public": {{ports[https-public][0]}},
+  },
+  "ws": {
+    "local": {{ports[ws][0]}},
+  },
+  "wss": {
+    "local": {{ports[wss][0]}},
+  },
+};
+
+// A `Server` is a web server accessible by tests. It has the following shape:
+//
+// {
+//   addressSpace: the IP address space of the server ("local", "private" or
+//     "public"),
+//   name: a human-readable name for the server,
+//   port: the port on which the server listens for connections,
+//   protocol: the protocol (including trailing colon) spoken by the server,
+// }
+//
+// Constants below define the available servers, which can also be accessed
+// programmatically with `get()`.
+class Server {
+  // Maps the given `protocol` (without a trailing colon) and `addressSpace` to
+  // a server. Returns null if no such server exists.
+  static get(protocol, addressSpace) {
+    const ports = SERVER_PORTS[protocol];
+    if (ports === undefined) {
+      return null;
+    }
+
+    const port = ports[addressSpace];
+    if (port === undefined) {
+      return null;
+    }
+
+    return {
+      addressSpace,
+      name: `${protocol}-${addressSpace}`,
+      port,
+      protocol: protocol + ':',
+    };
+  }
+
+  static HTTP_LOCAL = Server.get("http", "local");
+  static HTTP_PRIVATE = Server.get("http", "private");
+  static HTTP_PUBLIC = Server.get("http", "public");
+  static HTTPS_LOCAL = Server.get("https", "local");
+  static OTHER_HTTPS_LOCAL = Server.get("https", "other-local");
+  static HTTPS_PRIVATE = Server.get("https", "private");
+  static HTTPS_PUBLIC = Server.get("https", "public");
+  static WS_LOCAL = Server.get("ws", "local");
+  static WSS_LOCAL = Server.get("wss", "local");
+};
+
+// Resolves a URL relative to the current location, returning an absolute URL.
+//
+// `url` specifies the relative URL, e.g. "foo.html" or "http://foo.example".
+// `options`, if defined, should have the following shape:
+//
+//   {
+//     // Optional. Overrides the protocol of the returned URL.
+//     protocol,
+//
+//     // Optional. Overrides the port of the returned URL.
+//     port,
+//
+//     // Extra headers.
+//     headers,
+//
+//     // Extra search params.
+//     searchParams,
+//   }
+//
+function resolveUrl(url, options) {
+  const result = new URL(url, window.location);
+  if (options === undefined) {
+    return result;
+  }
+
+  const { port, protocol, headers, searchParams } = options;
+  if (port !== undefined) {
+    result.port = port;
+  }
+  if (protocol !== undefined) {
+    result.protocol = protocol;
+  }
+  if (headers !== undefined) {
+    const pipes = [];
+    for (key in headers) {
+      pipes.push(`header(${key},${headers[key]})`);
+    }
+    result.searchParams.append("pipe", pipes.join("|"));
+  }
+  if (searchParams !== undefined) {
+    for (key in searchParams) {
+      result.searchParams.append(key, searchParams[key]);
+    }
+  }
+
+  return result;
+}
+
+// Computes options to pass to `resolveUrl()` for a source document's URL.
+//
+// `server` identifies the server from which to load the document.
+// `treatAsPublic`, if set to true, specifies that the source document should
+// be artificially placed in the `public` address space using CSP.
+function sourceResolveOptions({ server, treatAsPublic }) {
+  const options = {...server};
+  if (treatAsPublic) {
+    options.headers = { "Content-Security-Policy": "treat-as-public-address" };
+  }
+  return options;
+}
+
+// Computes the URL of a target handler configured with the given options.
+//
+// `server` identifies the server from which to load the resource.
+// `behavior` specifies the behavior of the target server. It may contain:
+//   - `response`: The result of calling one of `ResponseBehavior`'s methods.
+//   - `redirect`: A URL to which the target should redirect GET requests.
+function resolveTargetUrl({ server, behavior }) {
+  if (server === undefined) {
+    throw new Error("no server specified.");
+  }
+  const options = {...server};
+  if (behavior) {
+    const { response, redirect } = behavior;
+    options.searchParams = {
+      ...response,
+    };
+    if (redirect !== undefined) {
+      options.searchParams.redirect = redirect;
+    }
+  }
+
+  return resolveUrl("target.py", options);
+}
+
+// Methods generate behavior specifications for how `resources/target.py`
+// should behave upon receiving a regular (non-preflight) request.
+const ResponseBehavior = {
+  // The response should succeed without CORS headers.
+  default: () => ({}),
+
+  // The response should succeed with CORS headers.
+  allowCrossOrigin: () => ({ "final-headers": "cors" }),
+};
+
+const FetchTestResult = {
+  SUCCESS: {
+    ok: true,
+    body: "success",
+  },
+  OPAQUE: {
+    ok: false,
+    type: "opaque",
+    body: "",
+  },
+  FAILURE: {
+    error: "TypeError: Failed to fetch",
+  },
+};
diff --git a/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/target.py b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/target.py
new file mode 100644
index 0000000..eabcdd4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/local-network-access/resources/target.py
@@ -0,0 +1,105 @@
+# This endpoint responds to requests for a target of a (possible) LNA request.
+#
+# Its behavior can be configured with various search/GET parameters, all of
+# which are optional:
+#
+# - final-headers: Valid values are:
+#   - cors: this endpoint responds with valid CORS headers to CORS-enabled
+#     non-preflight requests. These should be sufficient for non-preflighted
+#     CORS-enabled requests to succeed.
+#   - sw: this endpoint responds with a valid Service-Worker header to allow
+#     for the request to serve as a Service worker script resource. This is
+#     only valid in conjunction with the cors value above.
+#   - unspecified: this endpoint responds with no CORS headers to non-preflight
+#     requests. This should fail CORS-enabled requests, but be sufficient for
+#     no-CORS requests.
+#
+# The following parameters only affect non-preflight responses:
+#
+# - redirect: If set, the response code is set to 301 and the `Location`
+#   response header is set to this value.
+# - mime-type: If set, the `Content-Type` response header is set to this value.
+# - file: Specifies a path (relative to this file's directory) to a file. If
+#   set, the response body is copied from this file.
+# - random-js-prefix: If set to any value, the response body is prefixed with
+#   a Javascript comment line containing a random value. This is useful in
+#   service worker tests, since service workers are only updated if the new
+#   script is not byte-for-byte identical with the old script.
+# - body: If set and `file` is not, the response body is set to this value.
+#
+
+import os
+import random
+
+from wptserve.utils import isomorphic_encode
+
+_ACAO = ("Access-Control-Allow-Origin", "*")
+_ACAH = ("Access-Control-Allow-Headers", "Service-Worker")
+
+def _get_response_headers(method, mode, origin):
+  acam = ("Access-Control-Allow-Methods", method)
+
+  if mode == b"cors":
+    return [acam, _ACAO]
+
+  if mode == b"cors+sw":
+    return [acam, _ACAO, _ACAH]
+
+  if mode == b"navigation":
+    return [
+        acam,
+        ("Access-Control-Allow-Origin", origin),
+        ("Access-Control-Allow-Credentials", "true"),
+    ]
+
+  return []
+
+
+def _is_loaded_in_fenced_frame(request):
+  return request.GET.get(b"is-loaded-in-fenced-frame")
+
+def _final_response_body(request):
+  file_name = None
+  if file_name is None:
+    file_name = request.GET.get(b"file")
+  if file_name is None:
+    return request.GET.get(b"body") or "success"
+
+  prefix = b""
+  if request.GET.get(b"random-js-prefix"):
+    value = random.randint(0, 1000000000)
+    prefix = isomorphic_encode("// Random value: {}\n\n".format(value))
+
+  path = os.path.join(os.path.dirname(isomorphic_encode(__file__)), file_name)
+  with open(path, 'rb') as f:
+    contents = f.read()
+
+  return prefix + contents
+
+def _handle_final_request(request, response):
+  mode = request.GET.get(b"final-headers")
+  origin = request.headers.get("Origin")
+  headers = _get_response_headers(request.method, mode, origin)
+
+  redirect = request.GET.get(b"redirect")
+  if redirect is not None:
+    headers.append(("Location", redirect))
+    return (301, headers, b"")
+
+  mime_type = request.GET.get(b"mime-type")
+  if mime_type is not None:
+    headers.append(("Content-Type", mime_type),)
+
+  if _is_loaded_in_fenced_frame(request):
+    headers.append(("Supports-Loading-Mode", "fenced-frame"))
+
+  body = _final_response_body(request)
+  return (headers, body)
+
+
+def main(request, response):
+  try:
+    return _handle_final_request(request, response)
+  except BaseException as e:
+    # Surface exceptions to the client, where they show up as assertion errors.
+    return (500, [("X-exception", str(e))], "exception: {}".format(e))
diff --git a/third_party/blink/web_tests/external/wpt/reporting/resources/report-helper.js b/third_party/blink/web_tests/external/wpt/reporting/resources/report-helper.js
index 5b543890..216da22 100644
--- a/third_party/blink/web_tests/external/wpt/reporting/resources/report-helper.js
+++ b/third_party/blink/web_tests/external/wpt/reporting/resources/report-helper.js
@@ -40,7 +40,9 @@
 function getReport(reports, type, document_url, subresource_url) {
   for (const report of reports) {
     if (report.type !== type) continue;
-    if (report.body.documentURL === document_url && report.body.subresourceURL == subresource_url) return report;
+    if (report.body.documentURL === document_url
+        && (report.body.subresourceURL == subresource_url
+           || report.body.blockedURL == subresource_url)) return report;
   }
   return null;
 }
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/innertext.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/innertext.tentative.html
index d40b604..7716488 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/innertext.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/innertext.tentative.html
@@ -20,13 +20,18 @@
     const link = document.getElementById("link");
     testSoftNavigation({
       addContent: async () => {
-        document.getElementById("softnav-content").innerText =
-          "Lorem Ipsum dolor sit amet";
+          document.getElementById("softnav-content").innerText =
+              'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ' +
+              'sed do eiusmod tempor incididunt ut labore et dolore magna ' +
+              'aliqua. Ut enim ad minim veniam, quis nostrud exercitation ' +
+              'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis ' +
+              'aute irure dolor in reprehenderit in voluptate velit esse ' +
+              'cillum dolore eu fugiat nulla pariatur. Excepteur sint ' +
+              'occaecat cupidatat non proident, sunt in culpa qui officia ' +
+              'deserunt mollit anim id est laborum.';
       },
       link: link,
       test: "Soft navigation when only innerText was modified"});
   </script>
 </body>
 </html>
-
-
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/text-lcp-followed-by-anim-image-softnav-lcp.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/text-lcp-followed-by-anim-image-softnav-lcp.tentative.html
index 0615b51..b34a6e8 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/text-lcp-followed-by-anim-image-softnav-lcp.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/text-lcp-followed-by-anim-image-softnav-lcp.tentative.html
@@ -21,12 +21,15 @@
       addContent: async () => {
         const main = document.getElementById("main");
         main.removeChild(document.getElementsByTagName("div")[0]);
-        await addImageToMain("anim-gr.png");
+        const img = new Image(500, 500);
+        img.src = "/images/anim-gr.png?" + Math.random();
+        img.id = "imagelcp";
+        img.setAttribute("elementtiming", "imagelcp");
+        main.appendChild(img);
       },
       link: link,
-      test: "Test that a text LCP followup by a smaller soft navigation image"
-        + " LCP properly queues an LCP entry"});
+      test: "Test that a text LCP followup by an animaged image "
+        + " properly queues a soft navigation entry"});
   </script>
 </body>
 </html>
-
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/visited-link.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/visited-link.tentative.html
index 0bb149f00..0bb31aa 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/visited-link.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/visited-link.tentative.html
@@ -24,7 +24,15 @@
       }));
       const main = document.getElementById("main");
       const div = document.createElement("div");
-      const text = document.createTextNode("Lorem Ipsum");
+      const text = document.createTextNode(
+          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ' +
+          'sed do eiusmod tempor incididunt ut labore et dolore magna ' +
+          'aliqua. Ut enim ad minim veniam, quis nostrud exercitation ' +
+          'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis ' +
+          'aute irure dolor in reprehenderit in voluptate velit esse ' +
+          'cillum dolore eu fugiat nulla pariatur. Excepteur sint ' +
+          'occaecat cupidatat non proident, sunt in culpa qui officia ' +
+          'deserunt mollit anim id est laborum.');
       div.appendChild(text);
       main.appendChild(div);
     }
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/tentative/integrity-policy/parsing.https.html b/third_party/blink/web_tests/external/wpt/subresource-integrity/tentative/integrity-policy/parsing.https.html
new file mode 100644
index 0000000..20585441
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/tentative/integrity-policy/parsing.https.html
@@ -0,0 +1,119 @@
+<!doctype html>
+<head>
+  <meta name="timeout" content="long">
+  <meta name="variant" content="?type=enforce">
+  <meta name="variant" content="?type=report">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/dispatcher/dispatcher.js"></script>
+  <script src="/common/utils.js"></script>
+  <script src="/reporting/resources/report-helper.js"></script>
+</head>
+<body>
+<script>
+
+  const run_test = (test_case) => {
+    promise_test(async () => {
+      const REMOTE_EXECUTOR =
+        `/common/dispatcher/remote-executor.html?pipe=`;
+
+      let header_name = "Integrity-Policy";
+      const params = new URLSearchParams(location.search);
+      if (params.get('type') === "report") {
+        if (test_case.expected.blocked) {
+          return;
+        }
+        header_name += "-Report-Only";
+      }
+      const iframe_uuid = token();
+      const header =
+        `header(${header_name},${test_case.header_value})`;
+      const iframe_url =
+        `${REMOTE_EXECUTOR}${encodeURIComponent(header)}&uuid=${iframe_uuid}`;
+
+      const iframe = document.createElement('iframe');
+      iframe.src = iframe_url;
+      document.body.appendChild(iframe);
+
+      // Execute code directly from the iframe.
+      const ctx = new RemoteContext(iframe_uuid);
+      const result = await ctx.execute_script(async (test_case) => {
+        const resource_url = "/content-security-policy/resources/ran.js";
+        let report_observed_promise;
+
+        // Load a script with no integrity. If there's a policy in place, it
+        // would be blocked.
+        const loaded = await new Promise(resolve => {
+          const script = document.createElement('script');
+          script.onload = () => { resolve(true); };
+          script.onerror = () => { resolve(false); };
+          script.src = resource_url;
+          document.body.appendChild(script);
+        });
+        return { blocked: !loaded, ran: window.ran };
+      }, [test_case]);
+      assert_equals(!result.blocked, !!result.ran);
+      assert_equals(result.blocked, test_case.expected.blocked);
+    }, test_case.description);
+  };
+
+  const test_cases = [
+    {
+      description: "Ensure that test is working with a valid destination",
+      header_value: "blocked-destinations=\\(script\\)",
+      expected: {blocked: true},
+    },
+    {
+      description: "Ensure that test is working with a valid destination and source",
+      header_value: "blocked-destinations=\\(script\\)\\, sources=\\(inline\\)",
+      expected: {blocked: true},
+    },
+    {
+      description: "Ensure that an empty header does not block",
+      header_value: "",
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that a destination header with a token value does not parse",
+      header_value: "blocked-destinations=script",
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that a destination header with an inner list of strings does not parse",
+      header_value: 'blocked-destinations=\\("script"\\)',
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that a destination header with an inner list of single-quote strings does not parse",
+      header_value: "blocked-destinations=\\('script'\\)",
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that a destination header with an unclosed inner list does not parse",
+      header_value: "blocked-destinations=\\(script",
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that a destination header with a malformed inner list does not parse",
+      header_value: "blocked-destinations=\\(script\\,style\\)",
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that an unknown destination does not enforce a policy",
+      header_value: "blocked-destinations=\\(style\\)",
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that an unknown source causes the policy to not be enforced",
+      header_value: "blocked-destinations=\\(script\\)\\, sources=\\(telepathy\\)",
+      expected: {blocked: false},
+    },
+    {
+      description: "Ensure that an invalid source causes the policy to not be enforced",
+      header_value: "blocked-destinations=\\(script\\)\\, sources=\\(invalid",
+      expected: {blocked: false},
+    },
+  ];
+  test_cases.map(run_test);
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/tentative/integrity-policy/script.https.html b/third_party/blink/web_tests/external/wpt/subresource-integrity/tentative/integrity-policy/script.https.html
new file mode 100644
index 0000000..783374d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/tentative/integrity-policy/script.https.html
@@ -0,0 +1,239 @@
+<!doctype html>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/reporting/resources/report-helper.js"></script>
+
+<body>
+<script>
+  const {ORIGIN} = get_host_info();
+  const getAbsoluteUrl = url => {
+    return new URL(url, window.location.href).href;
+  }
+
+  const check_report = async (reporting_endpoint, reporting_uuid, iframe_url, url, report_only) => {
+    const reports = await pollReports(reporting_endpoint, reporting_uuid);
+    const abs_iframe_url = getAbsoluteUrl(iframe_url);
+    checkReportExists(reports, 'integrity-violation', abs_iframe_url);
+    const abs_blocked_url = getAbsoluteUrl(url);
+    const report = getReport(reports, 'integrity-violation', abs_iframe_url, abs_blocked_url);
+    assert_not_equals(report, null);
+    assert_equals(report.body.documentURL, abs_iframe_url);
+    assert_equals(report.body.blockedURL, abs_blocked_url);
+    assert_equals(report.body.destination, "script");
+    assert_equals(report.body.reportOnly, report_only);
+  };
+  const blob = new Blob([`window.ran=true;`],
+                        { type: 'application/javascript' });
+
+  const blob_url = URL.createObjectURL(blob);
+
+  // Generated using https://sha2.it/ed25519.html (In Chrome Canary, with Experimental Web Platform Features enabled)
+  const signature = encodeURIComponent(
+    'header(Unencoded-Digest, sha-384=:tqyFpeo21WFM8HDeUtLqH20GUq\/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak:)' +
+    '|header(Signature-Input, signature=\\("unencoded-digest";sf\\); keyid="JrQLj5P\/89iXES9+vFgrIy29clF9CC\/oPPsw3c5D0bs="; tag="sri")' +
+    '|header(Signature, signature=:qM19uLskHm2TQG5LJcH/hY0n0BWWzYOJztVWYlwk0cZb3u0JdgUMre1J4Jn8Tma0x2u5/kPBfbXRMbB+X+vTBw==:)');
+
+  const test_cases = [
+    {
+      description: "Ensure that a script without integrity did not run",
+      url: "/content-security-policy/resources/ran.js",
+      cross_origin: true,
+      integrity: "",
+      policy_violation: true,
+      block: true,
+      endpoints: true,
+      expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: false },
+    },
+    {
+      description: "Ensure that a script with unknown integrity algorithm did not run",
+      url: "/content-security-policy/resources/ran.js",
+      cross_origin: true,
+      integrity: "foobar-AAAAAAAAAAAAAAAAAAAa",
+      policy_violation: true,
+      block: true,
+      endpoints: true,
+      expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: false },
+    },
+    {
+      description: "Ensure that a script without integrity algorithm runs and gets reported in report-only mode",
+      url: "/content-security-policy/resources/ran.js",
+      cross_origin: true,
+      integrity: "",
+      policy_violation: true,
+      block: false,
+      endpoints: true,
+      expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: true },
+    },
+    {
+      description: "Ensure that a no-cors script gets blocked",
+      url: "/content-security-policy/resources/ran.js",
+      cross_origin: false,
+      integrity: "sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak",
+      policy_violation: true,
+      block: true,
+      endpoints: true,
+      expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: false },
+    },
+    {
+      description: "Ensure that ReportingObserver gets called without endpoints",
+      url: "/content-security-policy/resources/ran.js",
+      cross_origin: false,
+      integrity: "sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak",
+      policy_violation: true,
+      block: true,
+      endpoints: false,
+      expected: {blocked: ORIGIN + "/content-security-policy/resources/ran.js", ran: false },
+    },
+    {
+      description: "Ensure that a script with integrity runs",
+      url: "/content-security-policy/resources/ran.js",
+      cross_origin: true,
+      integrity: "sha384-tqyFpeo21WFM8HDeUtLqH20GUq/q3D1R6mqTzW3RtyTZ3dAYZJhC1wUcnkgOE2ak",
+      policy_violation: false,
+      block: true,
+      endpoints: true,
+      expected: {blocked: "", ran: true },
+    },
+    {
+      description: "Ensure that a script with signature integrity runs",
+      url: "/content-security-policy/resources/ran.js?pipe=" + signature,
+      cross_origin: true,
+      integrity: "ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=",
+      policy_violation: false,
+      block: true,
+      endpoints: true,
+      expected: {blocked: "", ran: true },
+    },
+    {
+      description: "Ensure that a data URI script with no integrity runs",
+      url: "data:application/javascript,window.ran=true",
+      cross_origin: true,
+      integrity: "",
+      policy_violation: false,
+      block: true,
+      endpoints: true,
+      expected: {blocked: "", ran: true },
+    },
+    {
+      description: "Ensure that a no-CORS data URI script with no integrity runs",
+      url: "data:application/javascript,window.ran=true",
+      cross_origin: false,
+      integrity: "",
+      policy_violation: false,
+      block: true,
+      endpoints: true,
+      expected: {blocked: "", ran: true },
+    },
+    {
+      description: "Ensure that a blob URL script with no integrity runs",
+      url: blob_url,
+      cross_origin: true,
+      integrity: "",
+      policy_violation: false,
+      block: true,
+      endpoints: true,
+      expected: {blocked: "", ran: true },
+    },
+    {
+      description: "Ensure that a no-CORS blob URL script with no integrity runs",
+      url: blob_url,
+      cross_origin: false,
+      integrity: "",
+      policy_violation: false,
+      block: true,
+      endpoints: true,
+      expected: {blocked: "", ran: true },
+    }
+  ];
+  test_cases.map(test_case => {
+    promise_test(async () => {
+      const REMOTE_EXECUTOR =
+        `/common/dispatcher/remote-executor.html?pipe=`;
+      const iframe_uuid = token();
+
+      const params = new URLSearchParams(location.search);
+      if (params.get('type') === "report") {
+        if (test_case.expected.blocked) {
+          return;
+        }
+        header_name += "-Report-Only";
+      }
+      const reporting_uuid_1 = token();
+      const reporting_uuid_2 = token();
+      const reporting_uuid_3 = token();
+      const reporting_endpoint = `${ORIGIN}/reporting/resources/report.py`;
+      let header = "";
+      if (test_case.block) {
+        header +=
+          `header(Integrity-Policy,blocked-destinations=\\(script\\)\\, endpoints=\\(integrity-endpoint-1 integrity-endpoint-2\\))`;
+      }
+      header +=
+        `|header(Integrity-Policy-Report-Only,blocked-destinations=\\(script\\)\\, endpoints=\\(integrity-endpoint-3\\))`;
+      if (test_case.endpoints) {
+        header +=
+          `|header(Reporting-Endpoints, integrity-endpoint-1=\"${reporting_endpoint}?reportID=${reporting_uuid_1}\"\\, ` +
+          `integrity-endpoint-2=\"${reporting_endpoint}?reportID=${reporting_uuid_2}\"\\, ` +
+          `integrity-endpoint-3=\"${reporting_endpoint}?reportID=${reporting_uuid_3}\")`;
+      }
+      const iframe_url = `${REMOTE_EXECUTOR}${encodeURIComponent(header)}&uuid=${iframe_uuid}`;
+
+      const iframe = document.createElement('iframe');
+      iframe.src = iframe_url;
+      document.body.appendChild(iframe);
+
+      // Execute code directly from the iframe.
+      const ctx = new RemoteContext(iframe_uuid);
+      const result = await ctx.execute_script(async (test_case) => {
+        window.ran = false;
+        let report_observed_promise;
+        if (test_case.policy_violation) {
+           report_observed_promise = new Promise(r => {
+            (new ReportingObserver((reports, observer) => {
+              reports.forEach(report => {
+                if (report.body.blockedURL.endsWith(test_case.url)) {
+                  r(report.body);
+                  observer.disconnect();
+                }
+              });
+            })).observe('integrity-violation');
+          });
+        }
+
+        // Load the script
+        await new Promise(resolve => {
+          const script = document.createElement('script');
+          if (test_case.cross_origin) {
+            script.crossOrigin="anonymous";
+          }
+          if (test_case.integrity) {
+            script.integrity = test_case.integrity;
+          }
+          script.onload = resolve;
+          script.onerror = resolve;
+          script.src = test_case.url;
+          document.body.appendChild(script);
+        });
+        const report_body = await report_observed_promise;
+        return { body: report_body, ran: window.ran };
+      }, [test_case]);
+      assert_equals(result.ran, test_case.expected.ran);
+      if (test_case.policy_violation) {
+        assert_equals(result.body.blockedURL, test_case.expected.blocked);
+        assert_true(result.body.documentURL.endsWith(iframe_url));
+        assert_equals(result.body.destination, "script");
+        assert_equals(result.body.reportOnly, !test_case.block);
+      }
+      if (test_case.endpoints && test_case.policy_violation) {
+        if (test_case.block) {
+          await check_report(reporting_endpoint, reporting_uuid_1, iframe_url, test_case.url, !test_case.block);
+          await check_report(reporting_endpoint, reporting_uuid_2, iframe_url, test_case.url, !test_case.block);
+        }
+        await check_report(reporting_endpoint, reporting_uuid_3, iframe_url, test_case.url, true);
+      }
+    }, test_case.description);
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/emulation/set_geolocation_override/invalid.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/emulation/set_geolocation_override/invalid.py
index 49d7de8d..2334d37 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/emulation/set_geolocation_override/invalid.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/emulation/set_geolocation_override/invalid.py
@@ -370,7 +370,18 @@
         )
 
 
-async def test_params_error_invalid_value(bidi_session, top_context):
+@pytest.mark.parametrize("value", [None, False, 42, {}, []])
+async def test_params_error_type_invalid_type(bidi_session, top_context, value):
+    with pytest.raises(error.InvalidArgumentException):
+        await bidi_session.emulation.set_geolocation_override(
+            contexts=[top_context["context"]],
+            error={
+                "type": value
+            },
+        )
+
+
+async def test_params_error_type_invalid_value(bidi_session, top_context):
     with pytest.raises(error.InvalidArgumentException):
         await bidi_session.emulation.set_geolocation_override(
             contexts=[top_context["context"]],
diff --git a/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
index 05741d9..322f028 100644
--- a/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
@@ -23,9 +23,15 @@
  
 ..
 ..
-     
+  
+..
+..
+ 
+..
 ..
      
+..
+      
 .. ..
  
 ..
@@ -45,6 +51,12 @@
 ..
 ..
  
+..
+..
+ 
+..
+..
+ 
  
  
  
@@ -65,4 +77,6 @@
  
  
  
+ 
+ 
 ..
diff --git a/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message.html b/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message.html
index d7cfd3b..385a247 100644
--- a/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message.html
+++ b/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message.html
@@ -96,6 +96,40 @@
     </span>
   </select>
 
+  <!-- Custom element -->
+  <script>
+    class CustomElement extends HTMLElement {
+        constructor() {
+            super();
+        }
+    }
+    customElements.define('custom-element', CustomElement);
+  </script>
+
+  <select>
+    <custom-element></custom-element>
+  </select>
+
+  <!-- Custom element with <option> children -->
+  <select>
+    <custom-element>
+      <option>..</option>
+      <option>..</option>
+    </custom-element>
+  </select>
+
+  <!-- Nested custom elements -->
+  <select>
+    <custom-element>
+      <custom-element>
+        <custom-element>
+          <option>..</option>
+          <option>..</option>
+        </custom-element>
+      </custom-element>
+    </custom-element>
+  </select>
+
   <!-- <noscript> -->
   <select>
     <noscript>
@@ -141,7 +175,7 @@
     <option>..</option>
   </select>
 
-  <!-- <selectedcontent> as descendant of <div>, <span> -->
+  <!-- <selectedcontent> as descendant of <div>, <span>, custom element -->
   <select>
     <button>
       <div>
@@ -158,6 +192,14 @@
     </button>
   </select>
 
+  <select>
+    <button>
+      <custom-element>
+        <selectedcontent></selectedcontent>
+      </custom-element>
+    </button>
+  </select>
+
   <!-- Allowed phrasing content as descendant of <button> and <div> -->
   <select>
     <button>
@@ -259,6 +301,30 @@
     </optgroup>
   </select>
 
+  <!-- Custom element -->
+  <select>
+    <optgroup>
+      <custom-element>
+        <option>..</option>
+        <option>..</option>
+      </custom-element>
+    </optgroup>
+  </select>
+  
+  <!-- Nested custom elements -->
+  <select>
+    <optgroup>
+      <custom-element>
+        <custom-element>
+          <custom-element>
+            <option>..</option>
+            <option>..</option>
+          </custom-element>
+        </custom-element>
+      </custom-element>
+    </optgroup>
+  </select>
+
   <!-- <noscript> -->
   <select>
     <optgroup>
@@ -361,6 +427,25 @@
     </option>
   </select>
 
+  <!-- Custom element -->
+    <select>
+      <option>
+        <custom-element></custom-element>
+      </option>
+      <option>
+        <custom-element></custom-element>
+      </option>
+    </select>
+  
+    <!-- Nested custom elements -->
+    <select>
+      <option>
+        <custom-element>
+          <custom-element></custom-element>
+        </custom-element>
+      </option>
+    </select>
+
   <!-- <noscript> -->
   <select>
     <option>
diff --git a/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
index 41c6ad5..a68bd47 100644
--- a/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
@@ -16,6 +16,7 @@
 CONSOLE ERROR: An interactive element which is not allowed in the content model of the <option> element was found within an <option> element. These elements will not consistently be accessible to people navigating by keyboard or using assistive technology.
 CONSOLE ERROR: An interactive element which is not allowed in the content model of the <option> element was found within an <option> element. These elements will not consistently be accessible to people navigating by keyboard or using assistive technology.
 CONSOLE ERROR: An interactive element which is not allowed in the content model of the <option> element was found within an <option> element. These elements will not consistently be accessible to people navigating by keyboard or using assistive technology.
+CONSOLE ERROR: An element which is not allowed in the content model of the <select> element was found within a <select> element. These elements will not consistently be accessible to people navigating by keyboard or using assistive technology. If using disallowed elements for layout structure and styling, consider using the allowed <div> element instead. Any text existing within the <select> element should either be removed or relocated to a valid element that allows text descendants, e.g., an <optgroup> with a <legend> element or <option> elements.
 CONSOLE ERROR: An interactive element which is not allowed in the content model of the <option> element was found within an <option> element. These elements will not consistently be accessible to people navigating by keyboard or using assistive technology.
 CONSOLE ERROR: An interactive element which is not allowed in the content model of the <option> element was found within an <option> element. These elements will not consistently be accessible to people navigating by keyboard or using assistive technology.
 CONSOLE ERROR: An interactive element which is not allowed in the content model of the <option> element was found within an <option> element. These elements will not consistently be accessible to people navigating by keyboard or using assistive technology.
@@ -40,3 +41,4 @@
 .. ..
  
 .. ..
+ 
diff --git a/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message.html b/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message.html
index d0b1ceb..3939de95 100644
--- a/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message.html
+++ b/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message.html
@@ -161,6 +161,21 @@
   });
 </script>
 
+<select>
+  <label is="custom-label"></label>
+</select>
+
+<script>
+  class CustomLabel extends HTMLLabelElement {
+    constructor() {
+      super();
+      this.style.color = 'blue';
+      this.style.fontWeight = 'bold';
+    }
+  }
+  customElements.define('custom-label', CustomLabel, { extends: 'label' });
+</script>
+
 <script>
 testRunner.waitUntilDone();
 testRunner.dumpAsText();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-expected.txt
index 6ed0bf5..55ac0f4 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-expected.txt
@@ -3,6 +3,6 @@
 {
     initiatorIPAddressSpace : Local
     initiatorIsSecureContext : true
-    privateNetworkRequestPolicy : PreflightBlock
+    privateNetworkRequestPolicy : PermissionWarn
 }
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-multiclient-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-multiclient-expected.txt
index cce6945..2f05133 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-multiclient-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-extra-info-client-security-state-multiclient-expected.txt
@@ -3,11 +3,11 @@
 {
     initiatorIPAddressSpace : Local
     initiatorIsSecureContext : true
-    privateNetworkRequestPolicy : PreflightBlock
+    privateNetworkRequestPolicy : PermissionWarn
 }
 {
     initiatorIPAddressSpace : Local
     initiatorIsSecureContext : true
-    privateNetworkRequestPolicy : PreflightBlock
+    privateNetworkRequestPolicy : PermissionWarn
 }
 
diff --git a/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
index c3b7a30..639ab699 100644
--- a/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
+++ b/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
@@ -10,6 +10,11 @@
 CONSOLE WARNING: A span 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 WARNING: A span 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 WARNING: A span 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A noscript 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 MESSAGE: <script> element
 CONSOLE WARNING: A button 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.
@@ -23,6 +28,9 @@
 CONSOLE WARNING: A span 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 WARNING: A selectedcontent 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 WARNING: A button 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 WARNING: A custom-element 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 WARNING: A selectedcontent 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 WARNING: A button 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 WARNING: A div 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 WARNING: A small 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 WARNING: A small 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.
@@ -48,6 +56,10 @@
 CONSOLE WARNING: A span 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 WARNING: A span 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 WARNING: A span 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A noscript 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 MESSAGE: <script> element
 CONSOLE WARNING: A svg 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.
@@ -63,6 +75,10 @@
 CONSOLE WARNING: A span 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 WARNING: A span 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 WARNING: A span 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A custom-element 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 WARNING: A noscript 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 MESSAGE: <script> element
  
@@ -87,9 +103,15 @@
  
 ..
 ..
-     
+  
+..
+..
+ 
+..
 ..
      
+..
+      
 .. ..
  
 ..
@@ -109,6 +131,12 @@
 ..
 ..
  
+..
+..
+ 
+..
+..
+ 
  
  
  
@@ -129,4 +157,6 @@
  
  
  
+ 
+ 
 ..
diff --git a/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
index 6d2f3da..755c3038 100644
--- a/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
+++ b/third_party/blink/web_tests/virtual/customizable-select-disabled/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
@@ -30,6 +30,7 @@
 CONSOLE WARNING: A div 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 WARNING: A span 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 WARNING: A span 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 WARNING: A label 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.
    
  
  
@@ -50,3 +51,4 @@
 .. ..
  
 .. ..
+ 
diff --git a/third_party/blink/web_tests/virtual/lna/README.md b/third_party/blink/web_tests/virtual/lna/README.md
new file mode 100644
index 0000000..b5d41814
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/lna/README.md
@@ -0,0 +1 @@
+This directory is for testing LocalNetworkAccess.
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
index 96cbc50..f783a74a 100644
--- a/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
+++ b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
@@ -18,3 +18,4 @@
 .. ..
  
 .. ..
+ 
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 1b5190c4..d9f0605 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5626,6 +5626,14 @@
     getter isComposing
     method constructor
     method getTargetRanges
+interface IntegrityViolationReportBody : ReportBody
+    attribute @@toStringTag
+    getter blockedURL
+    getter destination
+    getter documentURL
+    getter reportOnly
+    method constructor
+    method toJSON
 interface InterestEvent : Event
     attribute @@toStringTag
     getter source
diff --git a/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html b/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html
index 2f77b26..2f9dbd3 100644
--- a/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html
+++ b/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html
@@ -40,6 +40,7 @@
   }
 
   queueCspViolationReport() {}
+  queueIntegrityViolationReport() {}
   queueCSPHashReport(url, endpoint, subresourceUrl, integrityHash, type) {}
   queuePermissionsPolicyViolationReport() {}
   queuePotentialPermissionsPolicyViolationReport() {}
diff --git a/third_party/catapult b/third_party/catapult
index 417522f..4a83985 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 417522f6185fde0e4e0812bce00bca1277f286a5
+Subproject commit 4a839855c5e79d91689784e2c7284f3f6288123b
diff --git a/third_party/chromite b/third_party/chromite
index 7ee6e84..73e7b77 160000
--- a/third_party/chromite
+++ b/third_party/chromite
@@ -1 +1 @@
-Subproject commit 7ee6e840b449896c4bb271f1232b792eac10905c
+Subproject commit 73e7b77d6878e58c3d26d5fe0d5877cf9ac44597
diff --git a/third_party/compiler-rt/src b/third_party/compiler-rt/src
index 6558e6a..cff6ae8 160000
--- a/third_party/compiler-rt/src
+++ b/third_party/compiler-rt/src
@@ -1 +1 @@
-Subproject commit 6558e6a3eacafd269527cf2595e0e722f117c1e6
+Subproject commit cff6ae8a80960ceca4d83cf6efa271222d2e7d85
diff --git a/third_party/crossbench b/third_party/crossbench
index 3b45a21..6f0c318 160000
--- a/third_party/crossbench
+++ b/third_party/crossbench
@@ -1 +1 @@
-Subproject commit 3b45a2197a4e242d626f8479c045d89c7062a8f3
+Subproject commit 6f0c3181a39f6fdfbaea35689d8126e0361da071
diff --git a/third_party/dawn b/third_party/dawn
index c315409..0f24b33 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit c315409a56fe4ecce7f3ee49b7f7075a298d4e03
+Subproject commit 0f24b334d63efffa544d1c2fc6d779576a3aa5e9
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 553792f..682af1f 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 553792fb66b5711ebf46e2de1e5c74f6e553313b
+Subproject commit 682af1f84e33247088b8ca38e189f734ff9923ef
diff --git a/third_party/distributed_point_functions/BUILD.gn b/third_party/distributed_point_functions/BUILD.gn
deleted file mode 100644
index 7d7cdb93..0000000
--- a/third_party/distributed_point_functions/BUILD.gn
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//testing/libfuzzer/fuzzer_test.gni")
-import("//third_party/distributed_point_functions/features.gni")
-import("//third_party/protobuf/proto_library.gni")
-
-# This is Chromium's interface with the third-party distributed_point_functions
-# library. Targets outside of //third_party/distributed_point_functions should
-# depend on this target rather than using the source directly. This extra layer
-# prevents macros from leaking into Chromium code via header includes.
-source_set("distributed_point_functions") {
-  public_deps = [ "//third_party/distributed_point_functions/shim" ]
-}
-
-proto_library("proto") {
-  sources = [ "code/dpf/distributed_point_function.proto" ]
-  proto_out_dir = "third_party/distributed_point_functions/dpf"
-  cc_generator_options = "lite"
-}
-
-fuzzer_test("dpf_fuzzer") {
-  sources = [ "fuzz/dpf_fuzzer.cc" ]
-  deps = [ ":internal" ]
-
-  # Do not apply Chromium code rules to this third-party code.
-  suppressed_configs = [ "//build/config/compiler:chromium_code" ]
-  additional_configs = [ "//build/config/compiler:no_chromium_code" ]
-
-  additional_configs += [ ":includes" ]
-}
-
-# Targets below this line are only visible within this file and shim/.
-visibility = [
-  ":*",
-  "//third_party/distributed_point_functions/shim:*",
-]
-
-config("includes") {
-  include_dirs = [
-    "code",
-    "$target_gen_dir",
-  ]
-}
-
-source_set("internal") {
-  sources = [
-    "code/dpf/aes_128_fixed_key_hash.cc",
-    "code/dpf/aes_128_fixed_key_hash.h",
-    "code/dpf/distributed_point_function.cc",
-    "code/dpf/distributed_point_function.h",
-    "code/dpf/int_mod_n.cc",
-    "code/dpf/int_mod_n.h",
-    "code/dpf/internal/evaluate_prg_hwy.cc",
-    "code/dpf/internal/evaluate_prg_hwy.h",
-    "code/dpf/internal/get_hwy_mode.cc",
-    "code/dpf/internal/get_hwy_mode.h",
-    "code/dpf/internal/proto_validator.cc",
-    "code/dpf/internal/proto_validator.h",
-    "code/dpf/internal/value_type_helpers.cc",
-    "code/dpf/internal/value_type_helpers.h",
-    "code/dpf/status_macros.h",
-    "code/dpf/tuple.h",
-    "code/dpf/xor_wrapper.h",
-  ]
-
-  public_deps = [
-    ":proto",
-    "$dpf_abseil_cpp_dir:absl",
-    "$dpf_highway_cpp_dir:libhwy",
-    "//third_party/boringssl",
-    "//third_party/protobuf:protobuf_lite",
-  ]
-
-  # Do not apply Chromium code rules to this third-party code.
-  configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [ "//build/config/compiler:no_chromium_code" ]
-
-  configs += [ ":includes" ]
-}
diff --git a/third_party/distributed_point_functions/DEPS b/third_party/distributed_point_functions/DEPS
deleted file mode 100644
index 85d3dcf..0000000
--- a/third_party/distributed_point_functions/DEPS
+++ /dev/null
@@ -1,11 +0,0 @@
-include_rules = [
-  "+absl",
-  "+benchmark",
-  "+dpf",
-  "+gmock",
-  "+google/protobuf",
-  "+gtest",
-  "+testing",
-  "+hwy",
-  "+openssl",
-]
diff --git a/third_party/distributed_point_functions/DIR_METADATA b/third_party/distributed_point_functions/DIR_METADATA
deleted file mode 100644
index 71570707..0000000
--- a/third_party/distributed_point_functions/DIR_METADATA
+++ /dev/null
@@ -1,6 +0,0 @@
-monorail: {
-  component: "Internals>AttributionReporting"
-}
-buganizer_public: {
-  component_id: 1456103
-}
diff --git a/third_party/distributed_point_functions/LICENSE b/third_party/distributed_point_functions/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/third_party/distributed_point_functions/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 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/distributed_point_functions/OWNERS b/third_party/distributed_point_functions/OWNERS
deleted file mode 100644
index 53b8ead..0000000
--- a/third_party/distributed_point_functions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-alexmt@chromium.org
-csharrison@chromium.org
-linnan@chromium.org
diff --git a/third_party/distributed_point_functions/README.chromium b/third_party/distributed_point_functions/README.chromium
deleted file mode 100644
index 66ae1e9..0000000
--- a/third_party/distributed_point_functions/README.chromium
+++ /dev/null
@@ -1,25 +0,0 @@
-Name: The Incremental Distributed Point Functions library
-Short Name: distributed_point_functions
-URL: https://github.com/google/distributed_point_functions
-Version: N/A
-Revision: 2db593b64a99f178f682ef0db222d417c23e5bb5
-Date: 2023-11-16
-License: Apache-2.0
-License File: LICENSE
-Security Critical: Yes
-Shipped: yes
-CPEPrefix: unknown
-
-Description:
-This library contains an implementation of incremental distributed point
-functions, based on the paper by Boneh et al.
-
-Local Modifications:
-The directory code/ is a copy of the source code, modified in two ways. First,
-all top-level directories other than dpf/ have been removed as they are unused.
-Second, a .clang-format file has been added to disable automatic code
-formatting. Parts of code/dpf/distributed_point_function_test.cc are also
-adapted for fuzzing in fuzz/dpf_fuzzer.cc.
-Third, a missing absl/strings/str_cat.h include backported from revision
-c662ca975068bfa884cc4a96f3a1db40a7611e5e to fix build error when compiled with
-latest version of abseil.
diff --git a/third_party/distributed_point_functions/code/.bazelrc b/third_party/distributed_point_functions/code/.bazelrc
deleted file mode 100644
index 53485cb..0000000
--- a/third_party/distributed_point_functions/code/.bazelrc
+++ /dev/null
@@ -1 +0,0 @@
-build --cxxopt=-std=c++17 --host_cxxopt=-std=c++17
diff --git a/third_party/distributed_point_functions/code/.clang-format b/third_party/distributed_point_functions/code/.clang-format
deleted file mode 100644
index e384528..0000000
--- a/third_party/distributed_point_functions/code/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-DisableFormat: true
diff --git a/third_party/distributed_point_functions/code/.gitattributes b/third_party/distributed_point_functions/code/.gitattributes
deleted file mode 100644
index 4400637..0000000
--- a/third_party/distributed_point_functions/code/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-experiments/data/* filter=lfs diff=lfs merge=lfs -text
diff --git a/third_party/distributed_point_functions/code/.gitignore b/third_party/distributed_point_functions/code/.gitignore
deleted file mode 100644
index b803df0..0000000
--- a/third_party/distributed_point_functions/code/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bazel generated symlinks
-bazel-*
diff --git a/third_party/distributed_point_functions/code/BUILD b/third_party/distributed_point_functions/code/BUILD
deleted file mode 100644
index 19400ec5..0000000
--- a/third_party/distributed_point_functions/code/BUILD
+++ /dev/null
@@ -1,9 +0,0 @@
-load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
-
-package(
-    default_visibility = [":allowlist"],
-)
-
-licenses(["notice"])
-
-exports_files(["LICENSE"])
diff --git a/third_party/distributed_point_functions/code/CODE_OF_CONDUCT.md b/third_party/distributed_point_functions/code/CODE_OF_CONDUCT.md
deleted file mode 100644
index dc079b4d..0000000
--- a/third_party/distributed_point_functions/code/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, gender identity and expression, level of
-experience, education, socio-economic status, nationality, personal appearance,
-race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment
-include:
-
-*   Using welcoming and inclusive language
-*   Being respectful of differing viewpoints and experiences
-*   Gracefully accepting constructive criticism
-*   Focusing on what is best for the community
-*   Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-*   The use of sexualized language or imagery and unwelcome sexual attention or
-    advances
-*   Trolling, insulting/derogatory comments, and personal or political attacks
-*   Public or private harassment
-*   Publishing others' private information, such as a physical or electronic
-    address, without explicit permission
-*   Other conduct which could reasonably be considered inappropriate in a
-    professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are
-not aligned to this Code of Conduct, or to ban temporarily or permanently any
-contributor for other behaviors that they deem inappropriate, threatening,
-offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
-
-This Code of Conduct also applies outside the project spaces when the Project
-Steward has a reasonable belief that an individual's behavior may have a
-negative impact on the project or its community.
-
-## Conflict Resolution
-
-We do not believe that all conflict is bad; healthy debate and disagreement
-often yield positive results. However, it is never okay to be disrespectful or
-to engage in behavior that violates the project’s code of conduct.
-
-If you see someone violating the code of conduct, you are encouraged to address
-the behavior directly with those involved. Many issues can be resolved quickly
-and easily, and this gives people more control over the outcome of their
-dispute. If you are unable to resolve the matter for any reason, or if the
-behavior is threatening or harassing, report it. We are dedicated to providing
-an environment where participants feel welcome and safe.
-
-Reports should be directed to *[PROJECT STEWARD NAME(s) AND EMAIL(s)]*, the
-Project Steward(s) for *[PROJECT NAME]*. It is the Project Steward’s duty to
-receive and address reported violations of the code of conduct. They will then
-work with a committee consisting of representatives from the Open Source
-Programs Office and the Google Open Source Strategy team. If for any reason you
-are uncomfortable reaching out to the Project Steward, please email
-opensource@google.com.
-
-We will investigate every complaint, but you may not receive a direct response.
-We will use our discretion in determining when and how to follow up on reported
-incidents, which may range from not taking action to permanent expulsion from
-the project and project-sponsored spaces. We will notify the accused of the
-report and provide them an opportunity to discuss it before any action is taken.
-The identity of the reporter will be omitted from the details of the report
-supplied to the accused. In potentially harmful situations, such as ongoing
-harassment or threats to anyone's safety, we may take action without notice.
-
-## Attribution
-
-This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
-available at
-https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
diff --git a/third_party/distributed_point_functions/code/CONTRIBUTING.md b/third_party/distributed_point_functions/code/CONTRIBUTING.md
deleted file mode 100644
index 22b241c..0000000
--- a/third_party/distributed_point_functions/code/CONTRIBUTING.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# How to Contribute
-
-We'd love to accept your patches and contributions to this project. There are
-just a few small guidelines you need to follow.
-
-## Contributor License Agreement
-
-Contributions to this project must be accompanied by a Contributor License
-Agreement (CLA). You (or your employer) retain the copyright to your
-contribution; this simply gives us permission to use and redistribute your
-contributions as part of the project. Head over to
-<https://cla.developers.google.com/> to see your current agreements on file or
-to sign a new one.
-
-You generally only need to submit a CLA once, so if you've already submitted one
-(even if it was for a different project), you probably don't need to do it
-again.
-
-## Code reviews
-
-All submissions, including submissions by project members, require review. We
-use GitHub pull requests for this purpose. Consult
-[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
-information on using pull requests.
-
-## Community Guidelines
-
-This project follows
-[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
diff --git a/third_party/distributed_point_functions/code/LICENSE b/third_party/distributed_point_functions/code/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/third_party/distributed_point_functions/code/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 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/distributed_point_functions/code/README.md b/third_party/distributed_point_functions/code/README.md
deleted file mode 100644
index 0d67344..0000000
--- a/third_party/distributed_point_functions/code/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# An Implementation of Incremental Distributed Point Functions in C++ [![Build status](https://badge.buildkite.com/64bb7c0fcc8c11d630517356b2c3932d7e14850801a5f22c48.svg?branch=master)](https://buildkite.com/bazel/google-distributed-point-functions)
-
-This library contains an implementation of incremental distributed point
-functions, based on the following paper:
-> Boneh, D., Boyle, E., Corrigan-Gibbs, H., Gilboa, N., & Ishai, Y. (2020).
-Lightweight Techniques for Private Heavy Hitters. arXiv preprint
-> arXiv:2012.14884. https://arxiv.org/abs/2012.14884
-
-## About Incremental Distributed Point Functions
-
-A distributed point function (DPF) is parameterized by an index `alpha` and a
-value `beta`. It consists of two algorithms: key generation and evaluation.
-The key generation procedure produces two keys `k_a` and `k_b`, given `alpha`
-and `beta`. Evaluating each key on any point `x` in the DPF domain results in an
-additive secret share of `beta`, if `x == alpha`, and a share of 0 otherwise.
-
-Incremental DPFs additionally can be evaluated on prefixes of the index domain.
-More precisely, an incremental DPF is parameterized by a hierarchy of index
-domains, each a power of two larger than the previous. Key generation now takes
-a vector `beta`, one value `beta[i]` for each hierarchy level.
-When evaluated on a `b`-bit prefix of `alpha`, where b is the log domain size of
-the `i`-th hierarchy level, the incremental DPF returns a secret share of
-`beta[i]`, otherwise a share of 0.
-
-For more details, see the above paper, as well as the
-[`DistributedPointFunction` class documentation](dpf/distributed_point_function.h).
-
-
-## Building/Running Tests
-
-This repository requires Bazel. You can install Bazel by
-following the instructions for your platform on the
-[Bazel website](https://docs.bazel.build/versions/master/install.html).
-
-Once you have installed Bazel you can clone this repository and run all tests
-that are included by navigating into the root folder and running:
-
-```bash
-bazel test //...
-```
-
-## Security
-To report a security issue, please read [SECURITY.md](SECURITY.md).
-
-## Disclaimer
-
-This is not an officially supported Google product. The code is provided as-is,
-with no guarantees of correctness or security.
diff --git a/third_party/distributed_point_functions/code/SECURITY.md b/third_party/distributed_point_functions/code/SECURITY.md
deleted file mode 100644
index 7465c8b..0000000
--- a/third_party/distributed_point_functions/code/SECURITY.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Security
-To report a security issue, please use http://g.co/vulnz. We use
-http://g.co/vulnz for our intake, and do coordination and disclosure here on
-GitHub (including using GitHub Security Advisory). The Google Security Team will
-respond within 5 working days of your report on g.co/vulnz.
\ No newline at end of file
diff --git a/third_party/distributed_point_functions/code/WORKSPACE.bazel b/third_party/distributed_point_functions/code/WORKSPACE.bazel
deleted file mode 100644
index e9a1601..0000000
--- a/third_party/distributed_point_functions/code/WORKSPACE.bazel
+++ /dev/null
@@ -1,170 +0,0 @@
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-# rules_proto defines abstract rules for building Protocol Buffers.
-# https://github.com/bazelbuild/rules_proto
-http_archive(
-    name = "rules_proto",
-    sha256 = "0daa4fc5b2b820705fcbf239557515f9ab809be45a1e7c6dfaa1d465d5c615d4",
-    strip_prefix = "rules_proto-3f1ab99b718e3e7dd86ebdc49c580aa6a126b1cd",
-    urls = [
-        "https://github.com/bazelbuild/rules_proto/archive/3f1ab99b718e3e7dd86ebdc49c580aa6a126b1cd.zip",
-    ],
-)
-
-load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
-
-rules_proto_dependencies()
-
-rules_proto_toolchains()
-
-# rules_cc defines rules for generating C++ code from Protocol Buffers.
-# https://github.com/bazelbuild/rules_cc
-http_archive(
-    name = "rules_cc",
-    sha256 = "e17cca44563e0918a36a8ea2a50acb99ea9ad726bbd3cad8ba95a643a40121ab",
-    strip_prefix = "rules_cc-d7c11265cb157c9b962d87d9ab67b8c24e3a875f",
-    urls = [
-        "https://github.com/bazelbuild/rules_cc/archive/d7c11265cb157c9b962d87d9ab67b8c24e3a875f.zip",
-    ],
-)
-
-load("@rules_cc//cc:repositories.bzl", "rules_cc_dependencies")
-
-rules_cc_dependencies()
-
-# io_bazel_rules_go defines rules for generating C++ code from Protocol Buffers.
-# https://github.com/bazelbuild/rules_go
-http_archive(
-    name = "io_bazel_rules_go",
-    sha256 = "7c35e8515012279ef7bcbc39c4ef4b54a86756d853848cb621b7da49f156c82f",
-    strip_prefix = "rules_go-b397ab7ace3c4131f48b5f4d4d7e7e9e6809e0d2",
-    urls = [
-        "https://github.com/bazelbuild/rules_go/archive/b397ab7ace3c4131f48b5f4d4d7e7e9e6809e0d2.zip",
-    ],
-)
-
-load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
-
-go_rules_dependencies()
-
-go_register_toolchains(version = "1.19.3")
-
-# Install gtest.
-# https://github.com/google/googletest
-http_archive(
-    name = "com_github_google_googletest",
-    sha256 = "3e91944af2d909a79f18ee9760765624810146ccfae8f1a8f990037a1677d44b",
-    strip_prefix = "googletest-ac7a126f39d5bcd909b78c9e69900c76659b1bbb",
-    urls = [
-        "https://github.com/google/googletest/archive/ac7a126f39d5bcd909b78c9e69900c76659b1bbb.zip",
-    ],
-)
-
-# abseil-cpp
-# https://github.com/abseil/abseil-cpp
-http_archive(
-    name = "com_google_absl",
-    sha256 = "431c0c47217c36106f90e2ca4fcdf45af618ea21adde880804661b1ecb240056",
-    strip_prefix = "abseil-cpp-1fb3830b1cf685999bb2bbd0294be0a53c9440a6",
-    urls = [
-        "https://github.com/abseil/abseil-cpp/archive/1fb3830b1cf685999bb2bbd0294be0a53c9440a6.zip",
-    ],
-)
-
-# BoringSSL
-# https://github.com/google/boringssl
-http_archive(
-    name = "boringssl",
-    sha256 = "88e4330f4f65ebfdf24847e4807c25f3eacfd5bf1a93f6629d3941196ff9b0b3",
-    strip_prefix = "boringssl-6347808f2a480a3792148bf7732232229db9b909",
-    urls = [
-        "https://github.com/google/boringssl/archive/6347808f2a480a3792148bf7732232229db9b909.zip",
-    ],
-)
-
-# Benchmarks
-# https://github.com/google/benchmark
-http_archive(
-    name = "com_github_google_benchmark",
-    sha256 = "5f98b44165f3250f1d749b728018318d654f763ea0f4d7ea156e10e6e0cc678a",
-    strip_prefix = "benchmark-5e78bedfb07c615edb2b646d1e354980268c1728",
-    urls = [
-        "https://github.com/google/benchmark/archive/5e78bedfb07c615edb2b646d1e354980268c1728.zip",
-    ],
-)
-
-# gflags needed for glog.
-# https://github.com/gflags/gflags
-http_archive(
-    name = "com_github_gflags_gflags",
-    sha256 = "017e0a91531bfc45be9eaf07e4d8fed33c488b90b58509dbd2e33a33b2648ae6",
-    strip_prefix = "gflags-a738fdf9338412f83ab3f26f31ac11ed3f3ec4bd",
-    urls = [
-        "https://github.com/gflags/gflags/archive/a738fdf9338412f83ab3f26f31ac11ed3f3ec4bd.zip",
-    ],
-)
-
-# glog for logging
-# https://github.com/google/glog
-http_archive(
-    name = "com_github_google_glog",
-    sha256 = "0f91ee6cc1edc3b1c53a286382e69a37e5d172ce208b7e5b305be8770d8c21b1",
-    strip_prefix = "glog-f545ff5e7d7f3df95f6e86c8cb987d9d9d4bd481",
-    urls = [
-        "https://github.com/google/glog/archive/f545ff5e7d7f3df95f6e86c8cb987d9d9d4bd481.zip",
-    ],
-)
-
-# IREE for cc_embed_data.
-# https://github.com/google/iree
-http_archive(
-    name = "com_github_google_iree",
-    sha256 = "aa369b29a5c45ae9d7aa8bf49ea1308221d1711277222f0755df6e0a575f6879",
-    strip_prefix = "iree-7e6012468cbaafaaf30302748a2943771b40e2c3",
-    urls = [
-        "https://github.com/google/iree/archive/7e6012468cbaafaaf30302748a2943771b40e2c3.zip",
-    ],
-)
-
-# riegeli for file IO
-# https://github.com/google/riegeli
-http_archive(
-    name = "com_github_google_riegeli",
-    sha256 = "3de21a222271a1e2c5d728e7f46b63ab4520da829c09ef9727a322e693c9ac18",
-    strip_prefix = "riegeli-43b7ef9f995469609b6ab07f6becc82186314bfb",
-    urls = [
-        "https://github.com/google/riegeli/archive/43b7ef9f995469609b6ab07f6becc82186314bfb.zip",
-    ],
-)
-
-# rules_license needed for Highway
-# https://github.com/bazelbuild/rules_license
-http_archive(
-    name = "rules_license",
-    sha256 = "6157e1e68378532d0241ecd15d3c45f6e5cfd98fc10846045509fb2a7cc9e381",
-    urls = [
-        "https://github.com/bazelbuild/rules_license/releases/download/0.0.4/rules_license-0.0.4.tar.gz",
-    ],
-)
-
-# Highway for SIMD operations.
-# https://github.com/google/highway
-http_archive(
-    name = "com_github_google_highway",
-    sha256 = "cdba0eb21796598dd50fa0a4aa3651fa466c0d37c39d149ee383f725434e4314",
-    strip_prefix = "highway-45c98184ab7f81cf592c07633070b75fced14a52",
-    urls = [
-        "https://github.com/google/highway/archive/45c98184ab7f81cf592c07633070b75fced14a52.zip",
-    ],
-)
-
-# cppitertools for logging
-# https://github.com/ryanhaining/cppitertools
-http_archive(
-    name = "com_github_ryanhaining_cppitertools",
-    sha256 = "1608ddbe3c12b0c6e653b992ff63b5dceab9af5347ad93be8714d05e5dc17afb",
-    strip_prefix = "cppitertools-add5acc932dea2c78acd80747bab71ec0b5bce27",
-    urls = [
-        "https://github.com/ryanhaining/cppitertools/archive/add5acc932dea2c78acd80747bab71ec0b5bce27.zip",
-    ],
-)
diff --git a/third_party/distributed_point_functions/code/dpf/BUILD b/third_party/distributed_point_functions/code/dpf/BUILD
deleted file mode 100644
index 8ad71b8..0000000
--- a/third_party/distributed_point_functions/code/dpf/BUILD
+++ /dev/null
@@ -1,235 +0,0 @@
-# Copyright 2023 Google LLC
-#
-# 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.
-
-load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
-load("@rules_cc//cc:defs.bzl", "cc_library")
-load("@rules_proto//proto:defs.bzl", "proto_library")
-
-package(
-    default_visibility = ["//visibility:public"],
-)
-
-licenses(["notice"])
-
-cc_library(
-    name = "int_mod_n",
-    srcs = ["int_mod_n.cc"],
-    hdrs = ["int_mod_n.h"],
-    deps = [
-        "@com_google_absl//absl/base:config",
-        "@com_google_absl//absl/container:inlined_vector",
-        "@com_google_absl//absl/log:absl_check",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/strings:str_format",
-        "@com_google_absl//absl/types:span",
-    ],
-)
-
-cc_test(
-    name = "int_mod_n_test",
-    srcs = ["int_mod_n_test.cc"],
-    deps = [
-        ":int_mod_n",
-        "//dpf/internal:status_matchers",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/base:config",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings:str_format",
-        "@com_google_absl//absl/types:span",
-    ],
-)
-
-cc_test(
-    name = "int_mod_n_benchmark",
-    srcs = ["int_mod_n_benchmark.cc"],
-    deps = [
-        ":int_mod_n",
-        "@boringssl//:crypto",
-        "@com_github_google_benchmark//:benchmark",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/types:span",
-    ],
-)
-
-cc_library(
-    name = "distributed_point_function",
-    srcs = ["distributed_point_function.cc"],
-    hdrs = ["distributed_point_function.h"],
-    deps = [
-        ":aes_128_fixed_key_hash",
-        ":distributed_point_function_cc_proto",
-        ":status_macros",
-        "//dpf/internal:evaluate_prg_hwy",
-        "//dpf/internal:get_hwy_mode",
-        "//dpf/internal:maybe_deref_span",
-        "//dpf/internal:proto_validator",
-        "//dpf/internal:value_type_helpers",
-        "@boringssl//:crypto",
-        "@com_github_google_highway//:hwy",
-        "@com_google_absl//absl/container:btree",
-        "@com_google_absl//absl/container:flat_hash_map",
-        "@com_google_absl//absl/container:inlined_vector",
-        "@com_google_absl//absl/log:absl_check",
-        "@com_google_absl//absl/log:absl_log",
-        "@com_google_absl//absl/memory",
-        "@com_google_absl//absl/meta:type_traits",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/strings:str_format",
-        "@com_google_absl//absl/types:span",
-        "@com_google_protobuf//:protobuf",
-        "@com_google_protobuf//:protobuf_lite",
-    ],
-)
-
-cc_test(
-    name = "distributed_point_function_test",
-    size = "medium",
-    srcs = ["distributed_point_function_test.cc"],
-    deps = [
-        ":distributed_point_function",
-        ":distributed_point_function_cc_proto",
-        ":xor_wrapper",
-        "//dpf/internal:proto_validator",
-        "//dpf/internal:status_matchers",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/algorithm:container",
-        "@com_google_absl//absl/base:config",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/random",
-        "@com_google_absl//absl/random:distributions",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/strings:str_format",
-        "@com_google_absl//absl/types:span",
-        "@com_google_absl//absl/utility",
-    ],
-)
-
-proto_library(
-    name = "distributed_point_function_proto",
-    srcs = ["distributed_point_function.proto"],
-)
-
-cc_proto_library(
-    name = "distributed_point_function_cc_proto",
-    deps = [":distributed_point_function_proto"],
-)
-
-go_proto_library(
-    name = "distributed_point_function_go_proto",
-    importpath = "github.com/google/distributed_point_functions/dpf/distributed_point_function_go_proto",
-    protos = [":distributed_point_function_proto"],
-)
-
-cc_test(
-    name = "distributed_point_function_benchmark",
-    srcs = [
-        "distributed_point_function_benchmark.cc",
-    ],
-    tags = ["benchmark"],
-    deps = [
-        ":distributed_point_function",
-        "@com_github_google_benchmark//:benchmark",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_github_google_highway//:hwy",
-        "@com_google_absl//absl/container:btree",
-        "@com_google_absl//absl/log:absl_check",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/random",
-        "@com_google_absl//absl/random:distributions",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/types:span",
-        "@com_google_protobuf//:protobuf",
-    ],
-)
-
-cc_library(
-    name = "status_macros",
-    hdrs = ["status_macros.h"],
-)
-
-cc_library(
-    name = "aes_128_fixed_key_hash",
-    srcs = ["aes_128_fixed_key_hash.cc"],
-    hdrs = ["aes_128_fixed_key_hash.h"],
-    deps = [
-        "@boringssl//:crypto",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/types:span",
-    ],
-)
-
-cc_test(
-    name = "aes_128_fixed_key_hash_test",
-    srcs = ["aes_128_fixed_key_hash_test.cc"],
-    deps = [
-        ":aes_128_fixed_key_hash",
-        "//dpf/internal:status_matchers",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/types:span",
-    ],
-)
-
-cc_library(
-    name = "tuple",
-    hdrs = ["tuple.h"],
-)
-
-cc_test(
-    name = "tuple_test",
-    srcs = [
-        "tuple_test.cc",
-    ],
-    deps = [
-        ":tuple",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/numeric:int128",
-    ],
-)
-
-cc_library(
-    name = "xor_wrapper",
-    hdrs = ["xor_wrapper.h"],
-)
-
-cc_test(
-    name = "xor_wrapper_test",
-    srcs = [
-        "xor_wrapper_test.cc",
-    ],
-    deps = [
-        ":xor_wrapper",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/numeric:int128",
-    ],
-)
diff --git a/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash.cc b/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash.cc
deleted file mode 100644
index f7df231..0000000
--- a/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#include "dpf/aes_128_fixed_key_hash.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <array>
-#include <string>
-#include <utility>
-
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/types/span.h"
-#include "openssl/err.h"
-
-namespace distributed_point_functions {
-
-Aes128FixedKeyHash::Aes128FixedKeyHash(
-    bssl::UniquePtr<EVP_CIPHER_CTX> cipher_ctx, absl::uint128 key)
-    : cipher_ctx_(std::move(cipher_ctx)), key_(key) {}
-
-absl::StatusOr<Aes128FixedKeyHash> Aes128FixedKeyHash::Create(
-    absl::uint128 key) {
-  bssl::UniquePtr<EVP_CIPHER_CTX> cipher_ctx(EVP_CIPHER_CTX_new());
-  if (!cipher_ctx) {
-    return absl::InternalError("Failed to allocate AES context");
-  }
-  // Set up the OpenSSL encryption context. We want to evaluate the PRG in
-  // parallel on many seeds (see class comment in pseudorandom_generator.h), so
-  // we're using ECB mode here to achieve that. This batched evaluation is not
-  // to be confused with encryption of an array, for which ECB would be
-  // insecure.
-  int openssl_status =
-      EVP_EncryptInit_ex(cipher_ctx.get(), EVP_aes_128_ecb(), nullptr,
-                         reinterpret_cast<const uint8_t*>(&key), nullptr);
-  if (openssl_status != 1) {
-    return absl::InternalError("Failed to set up AES context");
-  }
-  return Aes128FixedKeyHash(std::move(cipher_ctx), key);
-}
-
-absl::Status Aes128FixedKeyHash::Evaluate(absl::Span<const absl::uint128> in,
-                                          absl::Span<absl::uint128> out) const {
-  if (in.size() != out.size()) {
-    return absl::InvalidArgumentError("Input and output sizes don't match");
-  }
-  if (in.empty()) {
-    // Nothing to do.
-    return absl::OkStatus();
-  }
-
-  // Compute orthomorphism sigma for each element in `in`, `kBatchSize` elements
-  // at a time.
-  auto in_size = static_cast<int64_t>(in.size());
-  std::array<absl::uint128, kBatchSize> sigma_in;
-  for (int64_t start_block = 0; start_block < in_size;
-       start_block += kBatchSize) {
-    int64_t batch_size = std::min<int64_t>(in_size - start_block, kBatchSize);
-    for (int i = 0; i < batch_size; ++i) {
-      sigma_in[i] =
-          absl::MakeUint128(absl::Uint128High64(in[start_block + i]) ^
-                                absl::Uint128Low64(in[start_block + i]),
-                            absl::Uint128High64(in[start_block + i]));
-    }
-
-    // We use EVP_Cipher here instead of EVP_EncryptUpdate, since it doesn't
-    // mutate the context in ECB mode, and so this call is thread-safe.
-    int openssl_status = EVP_Cipher(
-        cipher_ctx_.get(), reinterpret_cast<uint8_t*>(out.data() + start_block),
-        reinterpret_cast<const uint8_t*>(sigma_in.data()),
-        static_cast<int>(batch_size * sizeof(absl::uint128)));
-    if (openssl_status != 1) {
-      char buf[256];
-      ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
-      return absl::InternalError(
-          absl::StrCat("AES encryption failed: ", std::string(buf)));
-    }
-    for (int64_t i = 0; i < batch_size; ++i) {
-      out[start_block + i] ^= sigma_in[i];
-    }
-  }
-  return absl::OkStatus();
-}
-
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash.h b/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash.h
deleted file mode 100644
index 2af2061f05..0000000
--- a/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_H_
-
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/types/span.h"
-#include "openssl/cipher.h"
-
-namespace distributed_point_functions {
-
-// Aes128FixedKeyHash is a circular correlation-robust hash function based on
-// AES. For key `key`, input `in` and output `out`, the hash function is defined
-// as
-//
-//     out[i] = AES.Encrypt(key, sigma(in[i])) ^ sigma(in[i]),
-//
-// where sigma(x) = (x.high64 ^ x.low64, x.high64). This is the
-// circular correlation-robust MMO construction from
-// https://eprint.iacr.org/2019/074.pdf (pp. 18-19). Note that unlike
-// cryptographic hash functions such as SHA-256, this hash function is *not*
-// compressing and is not designed to provide any security guarantees beyond
-// circular correlation-robustness. Use with appropriate caution.
-class Aes128FixedKeyHash {
- public:
-  // Creates a new Aes128FixedKeyHash with the given `key`.
-  //
-  // Returns INTERNAL in case of allocation failures or OpenSSL errors.
-  static absl::StatusOr<Aes128FixedKeyHash> Create(absl::uint128 key);
-
-  // Computes hash values of each block in `in`, writing the output to `out`.
-  // It is safe to call this method if `in` and `out` overlap.
-  //
-  // Returns INVALID_ARGUMENT if sizes of `in` and `out` don't match or their
-  // sizes in bytes exceed an `int`, or INTERNAL in case of OpenSSL errors.
-  absl::Status Evaluate(absl::Span<const absl::uint128> in,
-                        absl::Span<absl::uint128> out) const;
-
-  // Aes128FixedKeyHash is not copyable.
-  Aes128FixedKeyHash(const Aes128FixedKeyHash&) = delete;
-  Aes128FixedKeyHash& operator=(const Aes128FixedKeyHash&) = delete;
-
-  // Aes128FixedKeyHash is movable (it just wraps a bssl::UniquePtr).
-  Aes128FixedKeyHash(Aes128FixedKeyHash&&) = default;
-  Aes128FixedKeyHash& operator=(Aes128FixedKeyHash&&) = default;
-
-  // Returns the key used to construct this hash function.
-  // DO NOT SEND THIS TO ANY OTHER PARTY!
-  const absl::uint128& key() const { return key_; }
-
-  // The maximum number of AES blocks encrypted at once. Chosen to pipeline AES
-  // as much as possible, while still allowing both source and destination to
-  // comfortably fit in the L1 CPU cache.
-  static constexpr int kBatchSize = 64;
-
- private:
-  // Called by `Create`.
-  Aes128FixedKeyHash(bssl::UniquePtr<EVP_CIPHER_CTX> cipher_ctx,
-                     absl::uint128 key);
-
-  // The OpenSSL encryption context used by `Evaluate`.
-  bssl::UniquePtr<EVP_CIPHER_CTX> cipher_ctx_;
-
-  // The key used to construct this hash function.
-  absl::uint128 key_;
-};
-
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_H_
diff --git a/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash_test.cc b/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash_test.cc
deleted file mode 100644
index f1ce37c..0000000
--- a/third_party/distributed_point_functions/code/dpf/aes_128_fixed_key_hash_test.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#include "dpf/aes_128_fixed_key_hash.h"
-
-#include <thread>  // NOLINT(build/c++11)
-#include <vector>
-
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/types/span.h"
-#include "dpf/internal/status_matchers.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace {
-
-using dpf_internal::StatusIs;
-
-// Test blocks for keys, inputs, and outputs.
-constexpr absl::uint128 kKey0 =
-    absl::MakeUint128(0x0000000000000000, 0x0000000000000000);
-constexpr absl::uint128 kKey1 =
-    absl::MakeUint128(0x1111111111111111, 0x1111111111111111);
-constexpr absl::uint128 kSeed0 =
-    absl::MakeUint128(0x0123012301230123, 0x0123012301230123);
-constexpr absl::uint128 kSeed1 =
-    absl::MakeUint128(0x4567456745674567, 0x4567456745674567);
-constexpr absl::uint128 kSeed2 =
-    absl::MakeUint128(0x89ab89ab89ab89ab, 0x89ab89ab89ab89ab);
-constexpr absl::uint128 kSeed3 =
-    absl::MakeUint128(0xcdefcdefcdefcdef, 0xcdefcdefcdefcdef);
-
-TEST(Aes128FixedKeyHashTest, CreateSucceeds) {
-  DPF_EXPECT_OK(Aes128FixedKeyHash::Create(kKey0));
-}
-
-TEST(Aes128FixedKeyHashTest, SameKeysAndSeedsGenerateSameOutput) {
-  std::vector<absl::uint128> in;
-
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg_0,
-                           Aes128FixedKeyHash::Create(kKey0));
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg_1,
-                           Aes128FixedKeyHash::Create(kKey0));
-  in = {kSeed0};
-  // Initialize output arrays with different values, to make sure they are the
-  // same afterwards.
-  std::vector<absl::uint128> out_0(in.size(), kSeed2), out_1(in.size(), kSeed3);
-
-  DPF_EXPECT_OK(prg_0.Evaluate(in, absl::MakeSpan(out_0)));
-  DPF_EXPECT_OK(prg_1.Evaluate(in, absl::MakeSpan(out_1)));
-  EXPECT_THAT(out_0, testing::ElementsAreArray(out_1));
-}
-
-TEST(Aes128FixedKeyHashTest, DifferentKeysGenerateDifferentOutput) {
-  std::vector<absl::uint128> in{kSeed0};
-
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg_0,
-                           Aes128FixedKeyHash::Create(kKey0));
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg_1,
-                           Aes128FixedKeyHash::Create(kKey1));
-  // Initialize output arrays with the same values, to make sure they are
-  // different afterwards.
-  std::vector<absl::uint128> out_0(in.size(), kSeed2), out_1(in.size(), kSeed2);
-
-  DPF_EXPECT_OK(prg_0.Evaluate(in, absl::MakeSpan(out_0)));
-  DPF_EXPECT_OK(prg_1.Evaluate(in, absl::MakeSpan(out_1)));
-  EXPECT_THAT(out_0, testing::Not(testing::ElementsAreArray(out_1)));
-}
-
-TEST(Aes128FixedKeyHashTest, DifferentSeedsGenerateDifferentOutput) {
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg,
-                           Aes128FixedKeyHash::Create(kKey0));
-  std::vector<absl::uint128> in_0, in_1;
-
-  in_0 = {kSeed0};
-  in_1 = {kSeed1};
-  // Initialize output arrays with the same values, to make sure they are
-  // different afterwards.
-  std::vector<absl::uint128> out_0(in_0.size(), kSeed2),
-      out_1(in_1.size(), kSeed2);
-
-  DPF_EXPECT_OK(prg.Evaluate(in_0, absl::MakeSpan(out_0)));
-  DPF_EXPECT_OK(prg.Evaluate(in_1, absl::MakeSpan(out_1)));
-  EXPECT_THAT(out_0, testing::Not(testing::ElementsAreArray(out_1)));
-}
-
-TEST(Aes128FixedKeyHashTest, BatchedEvaluationEqualsBlockWiseEvaluation) {
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg,
-                           Aes128FixedKeyHash::Create(kKey0));
-  std::vector<absl::uint128> in_0, in_1, in_2;
-
-  in_0 = {kSeed0};
-  in_1 = {kSeed1};
-  in_2 = {kSeed0, kSeed1};
-  std::vector<absl::uint128> out_0(in_0.size()), out_1(in_1.size()),
-      out_2(in_2.size());
-
-  DPF_EXPECT_OK(prg.Evaluate(in_0, absl::MakeSpan(out_0)));
-  DPF_EXPECT_OK(prg.Evaluate(in_1, absl::MakeSpan(out_1)));
-  DPF_EXPECT_OK(prg.Evaluate(in_2, absl::MakeSpan(out_2)));
-  EXPECT_THAT(out_2, testing::ElementsAre(out_0[0], out_1[0]));
-}
-
-TEST(Aes128FixedKeyHashTest, TestSpecificOutputValues) {
-  std::vector<absl::uint128> in, out_0, out_1;
-
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg_0,
-                           Aes128FixedKeyHash::Create(kKey0));
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg_1,
-                           Aes128FixedKeyHash::Create(kKey1));
-  in = {kSeed0, kSeed1};
-  out_0.resize(in.size());
-  out_1.resize(in.size());
-
-  DPF_EXPECT_OK(prg_0.Evaluate(in, absl::MakeSpan(out_0)));
-  DPF_EXPECT_OK(prg_1.Evaluate(in, absl::MakeSpan(out_1)));
-  EXPECT_THAT(out_0,
-              testing::ElementsAre(
-                  absl::MakeUint128(0x73c2dc14812be4ef, 0xeac64d09c8adf8ed),
-                  absl::MakeUint128(0xb8f33653a53a8436, 0xaedf39b62de91d95)));
-  EXPECT_THAT(out_1,
-              testing::ElementsAre(
-                  absl::MakeUint128(0x934704aff58fa233, 0xd3c20d1b9cc18d8f),
-                  absl::MakeUint128(0x530098817046d284, 0x43e61d3273a04f7c)));
-}
-
-TEST(Aes128FixedKeyHashTest, EvaluateFailsWhenSizesDontMatch) {
-  std::vector<absl::uint128> in{kSeed0};
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg,
-                           Aes128FixedKeyHash::Create(kKey0));
-
-  std::vector<absl::uint128> out(in.size() + 1);
-
-  EXPECT_THAT(prg.Evaluate(in, absl::MakeSpan(out)),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Input and output sizes don't match"));
-}
-
-TEST(Aes128FixedKeyHashTest, TestThreadSafety) {
-  std::vector<absl::uint128> in{kSeed0};
-  DPF_ASSERT_OK_AND_ASSIGN(Aes128FixedKeyHash prg,
-                           Aes128FixedKeyHash::Create(kKey0));
-  constexpr int kNumThreads = 1024;
-
-  auto do_evaluation = [&prg, &in]() {
-    absl::uint128 out;
-    DPF_ASSERT_OK(prg.Evaluate(in, absl::MakeSpan(&out, 1)));
-  };
-
-  std::vector<std::thread> threads;
-  threads.reserve(kNumThreads);
-  for (int i = 0; i < kNumThreads; ++i) {
-    threads.emplace_back(do_evaluation);
-  }
-
-  for (auto& thread : threads) {
-    thread.join();
-  }
-}
-
-}  // namespace
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/distributed_point_function.cc b/third_party/distributed_point_functions/code/dpf/distributed_point_function.cc
deleted file mode 100644
index a3c42d0..0000000
--- a/third_party/distributed_point_functions/code/dpf/distributed_point_function.cc
+++ /dev/null
@@ -1,732 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/distributed_point_function.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <limits>
-#include <memory>
-#include <numeric>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "absl/container/btree_map.h"
-#include "absl/container/flat_hash_map.h"
-#include "absl/container/inlined_vector.h"
-#include "absl/log/absl_check.h"
-#include "absl/log/absl_log.h"
-#include "absl/memory/memory.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-#include "dpf/internal/evaluate_prg_hwy.h"
-#include "dpf/internal/get_hwy_mode.h"
-#include "dpf/internal/proto_validator.h"
-#include "dpf/internal/value_type_helpers.h"
-#include "dpf/status_macros.h"
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-#include "hwy/aligned_allocator.h"
-#include "openssl/rand.h"
-
-namespace distributed_point_functions {
-
-namespace {
-
-// PRG keys used to expand seeds using AES. The first two are used to compute
-// correction words of seeds, while the last is used to compute correction
-// words of the incremental DPF values. Values were computed by taking the
-// first half of the SHA256 sum of the constant name, e.g., `echo
-// "DistributedPointFunction::kPrgKeyLeft" | sha256sum`
-constexpr absl::uint128 kPrgKeyLeft =
-    absl::MakeUint128(0x5be037ccf6a03de5ULL, 0x935f08d0a5b6a2fdULL);
-constexpr absl::uint128 kPrgKeyRight =
-    absl::MakeUint128(0xef94b6aedebb026cULL, 0xe2ea1fe0f66f4d0bULL);
-constexpr absl::uint128 kPrgKeyValue =
-    absl::MakeUint128(0x05a5d1588c5423e3ULL, 0x46a31101b21d1c98ULL);
-
-}  // namespace
-
-DistributedPointFunction::DistributedPointFunction(
-    std::unique_ptr<dpf_internal::ProtoValidator> proto_validator,
-    std::vector<int> blocks_needed, Aes128FixedKeyHash prg_left,
-    Aes128FixedKeyHash prg_right, Aes128FixedKeyHash prg_value,
-    absl::flat_hash_map<std::string, ValueCorrectionFunction>
-        value_correction_functions)
-    : proto_validator_(std::move(proto_validator)),
-      parameters_(proto_validator_->parameters()),
-      tree_levels_needed_(proto_validator_->tree_levels_needed()),
-      tree_to_hierarchy_(proto_validator_->tree_to_hierarchy()),
-      hierarchy_to_tree_(proto_validator_->hierarchy_to_tree()),
-      blocks_needed_(std::move(blocks_needed)),
-      prg_left_(std::move(prg_left)),
-      prg_right_(std::move(prg_right)),
-      prg_value_(std::move(prg_value)),
-      value_correction_functions_(value_correction_functions) {}
-
-absl::StatusOr<std::vector<Value>>
-DistributedPointFunction::ComputeValueCorrection(
-    int hierarchy_level, absl::Span<const absl::uint128> seeds,
-    absl::uint128 alpha, const Value& beta, bool invert) const {
-  // Compute value output component of the PRG on current seeds. To that end, we
-  // Compute x_0+0, ..., x_0+k-1, and x_1+0, ..., x_1+k-1, where x_i is the seed
-  // for helper i, and k is the number of blocks needed at the current hierarchy
-  // level. We use a single contiguous vector for both helpers, which allows us
-  // to use a single call to prg_value_.Evaluate.
-  int blocks_needed = blocks_needed_[hierarchy_level];
-  std::vector<absl::uint128> expanded_seeds(2 * blocks_needed);
-  absl::Span<absl::uint128> expanded_seed_a(&expanded_seeds[0], blocks_needed);
-  absl::Span<absl::uint128> expanded_seed_b(&expanded_seeds[blocks_needed],
-                                            blocks_needed);
-  ABSL_DCHECK(seeds.size() == 2);
-  std::iota(expanded_seed_a.begin(), expanded_seed_a.end(), seeds[0]);
-  std::iota(expanded_seed_b.begin(), expanded_seed_b.end(), seeds[1]);
-
-  // Evaluate PRG in place (this is safe as `Evaluate` creates a copy of the
-  // input).
-  DPF_RETURN_IF_ERROR(
-      prg_value_.Evaluate(expanded_seeds, absl::MakeSpan(expanded_seeds)));
-
-  // Compute index in block for alpha at the current hierarchy level.
-  int index_in_block = DomainToBlockIndex(alpha, hierarchy_level);
-
-  // Choose implementation depending on element_bitsize.
-  DPF_ASSIGN_OR_RETURN(
-      ValueCorrectionFunction func,
-      GetValueCorrectionFunction(parameters_[hierarchy_level]));
-  return func(
-      absl::string_view(reinterpret_cast<const char*>(expanded_seed_a.data()),
-                        blocks_needed * sizeof(absl::uint128)),
-      absl::string_view(reinterpret_cast<const char*>(expanded_seed_b.data()),
-                        blocks_needed * sizeof(absl::uint128)),
-      index_in_block, beta, invert);
-}
-
-// Expands the PRG seeds at the next `tree_level`, updates `seeds` and
-// `control_bits`, and writes the next correction word to `keys`.
-absl::Status DistributedPointFunction::GenerateNext(
-    int tree_level, absl::uint128 alpha, absl::Span<const Value> beta,
-    absl::Span<absl::uint128> seeds, absl::Span<bool> control_bits,
-    absl::Span<DpfKey> keys) const {
-  // As in `GenerateKeysIncremental`, we annotate code with the corresponding
-  // lines from https://arxiv.org/pdf/2012.14884.pdf#figure.caption.12.
-  //
-  // Lines 13 & 14: Compute value correction word if there is a value on the
-  // current level. This is done here already, since we use the "PRG evaluation
-  // optimization" described in Appendix C.2 of the paper. Since we are using
-  // fixed-key AES as PRG, which can have arbitrary stretch, this optimization
-  // works even for large output groups.
-  CorrectionWord* correction_word = keys[0].add_correction_words();
-  if (tree_to_hierarchy_.contains(tree_level - 1)) {
-    int hierarchy_level = tree_to_hierarchy_.at(tree_level - 1);
-    absl::uint128 alpha_prefix = 0;
-    int shift_amount = parameters_.back().log_domain_size() -
-                       parameters_[hierarchy_level].log_domain_size();
-    if (shift_amount < 128) {
-      alpha_prefix = alpha >> shift_amount;
-    }
-    DPF_ASSIGN_OR_RETURN(
-        std::vector<Value> value_correction,
-        ComputeValueCorrection(hierarchy_level, seeds, alpha_prefix,
-                               beta[hierarchy_level], control_bits[1]));
-    for (const Value& value : value_correction) {
-      *(correction_word->add_value_correction()) = value;
-    }
-  }
-
-  // Line 5: Expand seeds from previous level.
-  std::array<std::array<absl::uint128, 2>, 2> expanded_seeds;
-  DPF_RETURN_IF_ERROR(
-      prg_left_.Evaluate(seeds, absl::MakeSpan(expanded_seeds[0])));
-  DPF_RETURN_IF_ERROR(
-      prg_right_.Evaluate(seeds, absl::MakeSpan(expanded_seeds[1])));
-  std::array<std::array<bool, 2>, 2> expanded_control_bits;
-  expanded_control_bits[0][0] =
-      dpf_internal::ExtractAndClearLowestBit(expanded_seeds[0][0]);
-  expanded_control_bits[0][1] =
-      dpf_internal::ExtractAndClearLowestBit(expanded_seeds[0][1]);
-  expanded_control_bits[1][0] =
-      dpf_internal::ExtractAndClearLowestBit(expanded_seeds[1][0]);
-  expanded_control_bits[1][1] =
-      dpf_internal::ExtractAndClearLowestBit(expanded_seeds[1][1]);
-
-  // Lines 6-8: Assign keep/lose branch depending on current bit of `alpha`.
-  bool current_bit = 0;
-  if (parameters_.back().log_domain_size() - tree_level < 128) {
-    current_bit =
-        (alpha & (absl::uint128{1}
-                  << (parameters_.back().log_domain_size() - tree_level))) != 0;
-  }
-  bool keep = current_bit, lose = !current_bit;
-
-  // Line 9: Compute seed correction word.
-  absl::uint128 seed_correction =
-      expanded_seeds[lose][0] ^ expanded_seeds[lose][1];
-
-  // Line 10: Compute control bit correction words.
-  std::array<bool, 2> control_bit_correction;
-  control_bit_correction[0] = expanded_control_bits[0][0] ^
-                              expanded_control_bits[0][1] ^ current_bit ^ 1;
-  control_bit_correction[1] =
-      expanded_control_bits[1][0] ^ expanded_control_bits[1][1] ^ current_bit;
-
-  // We swap lines 11 and 12, since we first need to use the previous level's
-  // control bits before updating them.
-
-  // Line 12: Update seeds. Note that there is a typo in the paper: The
-  // multiplication / AND needs to be done with the control bit of iteration
-  // l-1, not l. Note that unlike the original algorithm, we are using the
-  // corrected seed directly for the next iteration. This is secure as we're
-  // using AES with a different key (kPrgKeyValue) to compute the value
-  // correction word below.
-  seeds[0] = expanded_seeds[keep][0];
-  seeds[1] = expanded_seeds[keep][1];
-  if (control_bits[0]) {
-    seeds[0] ^= seed_correction;
-  }
-  if (control_bits[1]) {
-    seeds[1] ^= seed_correction;
-  }
-
-  // Line 11: Update control bits.  Again, same typo as in Line 12.
-  control_bits[0] = expanded_control_bits[keep][0] ^
-                    (control_bits[0] && control_bit_correction[keep]);
-  control_bits[1] = expanded_control_bits[keep][1] ^
-                    (control_bits[1] && control_bit_correction[keep]);
-
-  // Line 15: Assemble correction word and add it to keys[0].
-  correction_word->mutable_seed()->set_high(
-      absl::Uint128High64(seed_correction));
-  correction_word->mutable_seed()->set_low(absl::Uint128Low64(seed_correction));
-  correction_word->set_control_left(control_bit_correction[0]);
-  correction_word->set_control_right(control_bit_correction[1]);
-
-  // Copy correction word to second key.
-  *(keys[1].add_correction_words()) = *correction_word;
-
-  return absl::OkStatus();
-}
-
-absl::uint128 DistributedPointFunction::DomainToTreeIndex(
-    absl::uint128 domain_index, int hierarchy_level) const {
-  int block_index_bits = parameters_[hierarchy_level].log_domain_size() -
-                         hierarchy_to_tree_[hierarchy_level];
-  ABSL_DCHECK_LT(block_index_bits, 128);
-  return domain_index >> block_index_bits;
-}
-
-int DistributedPointFunction::DomainToBlockIndex(absl::uint128 domain_index,
-                                                 int hierarchy_level) const {
-  int block_index_bits = parameters_[hierarchy_level].log_domain_size() -
-                         hierarchy_to_tree_[hierarchy_level];
-  ABSL_DCHECK_LT(block_index_bits, 128);
-  return static_cast<int>(domain_index &
-                          ((absl::uint128{1} << block_index_bits) - 1));
-}
-
-absl::Status DistributedPointFunction::EvaluateSeeds(
-    absl::Span<const absl::uint128> seeds, absl::Span<const bool> control_bits,
-    absl::Span<const absl::uint128> paths,
-    absl::Span<const CorrectionWord* const> correction_words,
-    absl::Span<absl::uint128> seeds_out,
-    absl::Span<bool> control_bits_out) const {
-  if (seeds.size() != control_bits.size() || seeds.size() != paths.size() ||
-      seeds.size() != seeds_out.size() ||
-      seeds.size() != control_bits_out.size()) {
-    return absl::InvalidArgumentError(
-        "`seeds`, `control_bits`, `paths`, `seeds_out`, and `control_bits_out` "
-        "must all have equal sizes");
-  }
-  auto num_seeds = static_cast<int64_t>(seeds.size());
-  auto num_levels = static_cast<int>(correction_words.size());
-  if (num_seeds == 0 || num_levels == 0) {
-    return absl::OkStatus();  // Nothing to do.
-  }
-
-  // Parse correction words for each level.
-  auto correction_seeds = hwy::AllocateAligned<absl::uint128>(num_levels);
-  if (correction_seeds == nullptr) {
-    return absl::ResourceExhaustedError("Memory allocation error");
-  }
-  BitVector correction_controls_left(num_levels),
-      correction_controls_right(num_levels);
-  for (int level = 0; level < num_levels; ++level) {
-    const CorrectionWord& correction = *(correction_words[level]);
-    correction_seeds[level] =
-        absl::MakeUint128(correction.seed().high(), correction.seed().low());
-    correction_controls_left[level] = correction.control_left();
-    correction_controls_right[level] = correction.control_right();
-  }
-
-  ABSL_DCHECK(seeds.size() == num_seeds);
-  ABSL_DCHECK(control_bits.size() == num_seeds);
-  ABSL_DCHECK(correction_controls_left.size() == num_levels);
-  ABSL_DCHECK(correction_controls_right.size() == num_levels);
-  ABSL_DCHECK(seeds_out.size() == num_seeds);
-  ABSL_DCHECK(control_bits_out.size() == num_seeds);
-  DPF_RETURN_IF_ERROR(dpf_internal::EvaluateSeeds(
-      num_seeds, num_levels, num_levels, seeds.data(), control_bits.data(),
-      paths.data(), 0, correction_seeds.get(), correction_controls_left.data(),
-      correction_controls_right.data(), prg_left_, prg_right_, seeds_out.data(),
-      control_bits_out.data()));
-  return absl::OkStatus();
-}
-
-absl::StatusOr<DistributedPointFunction::DpfExpansion>
-DistributedPointFunction::ExpandSeeds(
-    const DpfExpansion& partial_evaluations,
-    absl::Span<const CorrectionWord* const> correction_words) const {
-  int num_expansions = static_cast<int>(correction_words.size());
-
-  // Check that the output size fits in a size_t. This should already be checked
-  // by the caller, so using ABSL_DCHECK here is enough.
-  ABSL_DCHECK_LT(num_expansions, 63);
-  auto current_level_size =
-      static_cast<int64_t>(partial_evaluations.control_bits.size());
-  absl::uint128 output_size_128 = absl::uint128{current_level_size}
-                                  << num_expansions;
-  ABSL_DCHECK_LE(output_size_128, std::numeric_limits<size_t>::max() / 2);
-  size_t output_size = static_cast<size_t>(output_size_128);
-
-  // Allocate buffers with the correct size to avoid reallocations.
-  int64_t max_batch_size = Aes128FixedKeyHash::kBatchSize;
-  std::vector<absl::uint128> prg_buffer_left(max_batch_size),
-      prg_buffer_right(max_batch_size);
-
-  // Copy seeds and control bits. We will swap these after every expansion.
-  DpfExpansion expansion;
-  expansion.seeds = hwy::AllocateAligned<absl::uint128>(output_size);
-  if (expansion.seeds == nullptr) {
-    return absl::ResourceExhaustedError("Memory allocation error");
-  }
-  std::copy_n(partial_evaluations.seeds.get(), current_level_size,
-              expansion.seeds.get());
-  expansion.control_bits = partial_evaluations.control_bits;
-  expansion.control_bits.reserve(output_size);
-  DpfExpansion next_level_expansion;
-  next_level_expansion.seeds = hwy::AllocateAligned<absl::uint128>(output_size);
-  if (next_level_expansion.seeds == nullptr) {
-    return absl::ResourceExhaustedError("Memory allocation error");
-  }
-  next_level_expansion.control_bits.reserve(output_size);
-
-  // We use an iterative expansion here to pipeline AES as much as possible.
-  for (int i = 0; i < num_expansions; ++i) {
-    next_level_expansion.control_bits.resize(0);
-    absl::uint128 correction_seed = absl::MakeUint128(
-        correction_words[i]->seed().high(), correction_words[i]->seed().low());
-    bool correction_control_left = correction_words[i]->control_left();
-    bool correction_control_right = correction_words[i]->control_right();
-    // Expand PRG.
-    for (int64_t start_block = 0; start_block < current_level_size;
-         start_block += max_batch_size) {
-      int64_t batch_size =
-          std::min<int64_t>(current_level_size - start_block, max_batch_size);
-      DPF_RETURN_IF_ERROR(prg_left_.Evaluate(
-          absl::MakeConstSpan(expansion.seeds.get() + start_block, batch_size),
-          absl::MakeSpan(prg_buffer_left).subspan(0, batch_size)));
-      DPF_RETURN_IF_ERROR(prg_right_.Evaluate(
-          absl::MakeConstSpan(expansion.seeds.get() + start_block, batch_size),
-          absl::MakeSpan(prg_buffer_right).subspan(0, batch_size)));
-
-      // Merge results into next level of seeds and perform correction.
-      for (int64_t j = 0; j < batch_size; ++j) {
-        const int64_t index_expanded = 2 * (start_block + j);
-        if (expansion.control_bits[start_block + j]) {
-          prg_buffer_left[j] ^= correction_seed;
-          prg_buffer_right[j] ^= correction_seed;
-        }
-        next_level_expansion.seeds[index_expanded] = prg_buffer_left[j];
-        next_level_expansion.seeds[index_expanded + 1] = prg_buffer_right[j];
-        next_level_expansion.control_bits.push_back(
-            dpf_internal::ExtractAndClearLowestBit(
-                next_level_expansion.seeds[index_expanded]));
-        next_level_expansion.control_bits.push_back(
-            dpf_internal::ExtractAndClearLowestBit(
-                next_level_expansion.seeds[index_expanded + 1]));
-        if (expansion.control_bits[start_block + j]) {
-          next_level_expansion.control_bits[index_expanded] ^=
-              correction_control_left;
-          next_level_expansion.control_bits[index_expanded + 1] ^=
-              correction_control_right;
-        }
-      }
-    }
-    std::swap(expansion, next_level_expansion);
-    current_level_size *= 2;
-  }
-  return expansion;
-}
-
-absl::StatusOr<DistributedPointFunction::DpfExpansion>
-DistributedPointFunction::ComputePartialEvaluations(
-    absl::Span<const absl::uint128> prefixes, int hierarchy_level,
-    bool update_ctx, EvaluationContext& ctx) const {
-  int64_t num_prefixes = static_cast<int64_t>(prefixes.size());
-
-  DpfExpansion partial_evaluations;
-  int start_level = hierarchy_to_tree_[ctx.partial_evaluations_level()];
-  int stop_level = hierarchy_to_tree_[hierarchy_level];
-  if (ctx.partial_evaluations_size() > 0 && start_level <= stop_level) {
-    // We have partial evaluations from a tree level before the current one.
-    // Parse `ctx.partial_evaluations` into a btree_map for quick lookups up by
-    // prefix. We use a btree_map because `ctx.partial_evaluations()` will
-    // usually be sorted.
-    absl::btree_map<absl::uint128, std::pair<absl::uint128, bool>>
-        previous_partial_evaluations;
-    for (const PartialEvaluation& element : ctx.partial_evaluations()) {
-      absl::uint128 prefix =
-          absl::MakeUint128(element.prefix().high(), element.prefix().low());
-      // Try inserting `(seed, control_bit)` at `prefix` into
-      // partial_evaluations. Return an error if `prefix` is already present
-      // with a different seed or control bit.
-      auto value = std::make_pair(
-          absl::MakeUint128(element.seed().high(), element.seed().low()),
-          element.control_bit());
-      auto it = previous_partial_evaluations.try_emplace(
-          previous_partial_evaluations.end(), prefix, value);
-      if (it->second != value) {
-        return absl::InvalidArgumentError(
-            "Duplicate prefix in `ctx.partial_evaluations()` with mismatching "
-            "seed or control bit");
-      }
-    }
-    // Now select all partial evaluations from the map that correspond to
-    // `prefixes`.
-    partial_evaluations.seeds =
-        hwy::AllocateAligned<absl::uint128>(num_prefixes);
-    if (partial_evaluations.seeds == nullptr) {
-      return absl::ResourceExhaustedError("Memory allocation error");
-    }
-    partial_evaluations.control_bits.reserve(num_prefixes);
-    for (int64_t i = 0; i < num_prefixes; ++i) {
-      absl::uint128 previous_prefix = 0;
-      if (stop_level - start_level < 128) {
-        previous_prefix = prefixes[i] >> (stop_level - start_level);
-      }
-      auto it = previous_partial_evaluations.find(previous_prefix);
-      if (it == previous_partial_evaluations.end()) {
-        return absl::InvalidArgumentError(absl::StrCat(
-            "Prefix not present in ctx.partial_evaluations at hierarchy level ",
-            hierarchy_level));
-      }
-      const std::pair<absl::uint128, bool>& partial_evaluation = it->second;
-      partial_evaluations.seeds[partial_evaluations.control_bits.size()] =
-          partial_evaluation.first;
-      partial_evaluations.control_bits.push_back(partial_evaluation.second);
-    }
-  } else {
-    // No partial evaluations in `ctx` -> Start from the beginning.
-    partial_evaluations.seeds =
-        hwy::AllocateAligned<absl::uint128>(num_prefixes);
-    if (partial_evaluations.seeds == nullptr) {
-      return absl::ResourceExhaustedError("Memory allocation error");
-    }
-    auto seeds = absl::MakeSpan(partial_evaluations.seeds.get(), num_prefixes);
-    std::fill(
-        seeds.begin(), seeds.end(),
-        absl::MakeUint128(ctx.key().seed().high(), ctx.key().seed().low()));
-    partial_evaluations.control_bits.resize(
-        num_prefixes, static_cast<bool>(ctx.key().party()));
-    start_level = 0;
-  }
-
-  // Evaluate the DPF up to current_tree_level.
-  auto seeds = absl::MakeSpan(partial_evaluations.seeds.get(),
-                              partial_evaluations.control_bits.size());
-  DPF_RETURN_IF_ERROR(
-      EvaluateSeeds(seeds, partial_evaluations.control_bits, prefixes,
-                    absl::MakeConstSpan(ctx.key().correction_words())
-                        .subspan(start_level, stop_level - start_level),
-                    seeds, absl::MakeSpan(partial_evaluations.control_bits)));
-
-  // Update `partial_evaluations` in `ctx` if there are more evaluations to
-  // come.
-  ctx.clear_partial_evaluations();
-  ctx.mutable_partial_evaluations()->Reserve(num_prefixes);
-  if (update_ctx) {
-    for (int64_t i = 0; i < num_prefixes; ++i) {
-      PartialEvaluation* current_element = ctx.add_partial_evaluations();
-      current_element->mutable_prefix()->set_high(
-          absl::Uint128High64(prefixes[i]));
-      current_element->mutable_prefix()->set_low(
-          absl::Uint128Low64(prefixes[i]));
-      current_element->mutable_seed()->set_high(
-          absl::Uint128High64(partial_evaluations.seeds[i]));
-      current_element->mutable_seed()->set_low(
-          absl::Uint128Low64(partial_evaluations.seeds[i]));
-      current_element->set_control_bit(partial_evaluations.control_bits[i]);
-    }
-  }
-  ctx.set_partial_evaluations_level(hierarchy_level);
-  return partial_evaluations;
-}
-
-absl::StatusOr<DistributedPointFunction::DpfExpansion>
-DistributedPointFunction::ExpandAndUpdateContext(
-    int hierarchy_level, absl::Span<const absl::uint128> prefixes,
-    EvaluationContext& ctx) const {
-  // Expand seeds by expanding either the DPF key seed, or
-  // `ctx.partial_evaluations` for the given `prefixes`.
-  DpfExpansion selected_partial_evaluations;
-  int start_level = 0;
-  if (prefixes.empty()) {
-    // First expansion -> Expand seed of the DPF key.
-    selected_partial_evaluations.seeds = hwy::AllocateAligned<absl::uint128>(1);
-    if (selected_partial_evaluations.seeds == nullptr) {
-      return absl::ResourceExhaustedError("Memory allocation error");
-    }
-    selected_partial_evaluations.seeds[0] =
-        absl::MakeUint128(ctx.key().seed().high(), ctx.key().seed().low());
-    selected_partial_evaluations.control_bits = {
-        static_cast<bool>(ctx.key().party())};
-  } else {
-    // Second or later expansion -> Extract all seeds for `prefixes` from
-    // `ctx.partial_evaluations`. Update `ctx` if this is not the last
-    // evaluation.
-    bool update_ctx =
-        (hierarchy_level < static_cast<int>(parameters_.size()) - 1);
-    ABSL_DCHECK(ctx.previous_hierarchy_level() >= 0);
-    DPF_ASSIGN_OR_RETURN(
-        selected_partial_evaluations,
-        ComputePartialEvaluations(prefixes, ctx.previous_hierarchy_level(),
-                                  update_ctx, ctx));
-    start_level = hierarchy_to_tree_[ctx.previous_hierarchy_level()];
-  }
-
-  // Expand up to the next hierarchy level.
-  int stop_level = hierarchy_to_tree_[hierarchy_level];
-  DPF_ASSIGN_OR_RETURN(
-      DpfExpansion expansion,
-      ExpandSeeds(selected_partial_evaluations,
-                  absl::MakeConstSpan(ctx.key().correction_words())
-                      .subspan(start_level, stop_level - start_level)));
-
-  // Update hierarchy level in ctx.
-  ctx.set_previous_hierarchy_level(hierarchy_level);
-  return expansion;
-}
-
-absl::StatusOr<hwy::AlignedFreeUniquePtr<absl::uint128[]>>
-DistributedPointFunction::HashExpandedSeeds(
-    int hierarchy_level, absl::Span<const absl::uint128> expansion) const {
-  const auto expansion_size = static_cast<int64_t>(expansion.size());
-  const int blocks_needed = blocks_needed_[hierarchy_level];
-  auto hashed_expansion =
-      hwy::AllocateAligned<absl::uint128>(expansion_size * blocks_needed);
-  if (hashed_expansion == nullptr) {
-    return absl::ResourceExhaustedError("Memory allocation error");
-  }
-  for (int64_t i = 0; i < expansion_size; ++i) {
-    for (int j = 0; j < blocks_needed; ++j) {
-      hashed_expansion[i * blocks_needed + j] = expansion[i] + j;
-    }
-  }
-
-  // Evaluate PRG in place (this is safe as `Evaluate` creates a copy of the
-  // input).
-  absl::Span<absl::uint128> hashed_expansion_span(
-      hashed_expansion.get(), expansion_size * blocks_needed);
-  DPF_RETURN_IF_ERROR(
-      prg_value_.Evaluate(hashed_expansion_span, hashed_expansion_span));
-
-  return hashed_expansion;
-}
-
-absl::StatusOr<std::string>
-DistributedPointFunction::SerializeValueTypeDeterministically(
-    const ValueType& value_type) {
-  // We need to do serialization to a string by hand, in order to use
-  // deterministic serialization.
-  std::string serialized_value_type;
-  {  // Start new block so that stream destructors are run before returning.
-    ::google::protobuf::io::StringOutputStream string_stream(
-        &serialized_value_type);
-    ::google::protobuf::io::CodedOutputStream coded_stream(&string_stream);
-    coded_stream.SetSerializationDeterministic(true);
-    if (!value_type.SerializeToCodedStream(&coded_stream)) {
-      return absl::InternalError("Serializing value_type to string failed");
-    }
-  }
-  return serialized_value_type;
-}
-
-absl::StatusOr<DistributedPointFunction::ValueCorrectionFunction>
-DistributedPointFunction::GetValueCorrectionFunction(
-    const DpfParameters& parameters) const {
-  std::string serialized_value_type;
-  DPF_ASSIGN_OR_RETURN(
-      serialized_value_type,
-      SerializeValueTypeDeterministically(parameters.value_type()));
-  auto it = value_correction_functions_.find(serialized_value_type);
-  if (it == value_correction_functions_.end()) {
-    return absl::FailedPreconditionError(absl::StrCat(
-        "No value correction function known for the following parameters:\n",
-        parameters.DebugString(),
-        "Did you call RegisterValueType<T>() with your value type?"));
-  }
-  return it->second;
-}
-
-absl::StatusOr<std::unique_ptr<DistributedPointFunction>>
-DistributedPointFunction::Create(const DpfParameters& parameters) {
-  return CreateIncremental(absl::MakeConstSpan(&parameters, 1));
-}
-
-absl::StatusOr<std::unique_ptr<DistributedPointFunction>>
-DistributedPointFunction::CreateIncremental(
-    absl::Span<const DpfParameters> parameters) {
-  // Log Highway mode for debugging.
-  ABSL_LOG_FIRST_N(INFO, 1)
-      << "Highway is in " << dpf_internal::GetHwyModeAsString() << " mode";
-
-  // Validate `parameters` and store validator for later.
-  DPF_ASSIGN_OR_RETURN(
-      std::unique_ptr<dpf_internal::ProtoValidator> proto_validator,
-      dpf_internal::ProtoValidator::Create(parameters));
-
-  // Compute the number of value correction blocks needed for each hierarchy
-  // level.
-  std::vector<int> blocks_needed(parameters.size());
-  for (int i = 0; i < static_cast<int>(parameters.size()); ++i) {
-    DPF_ASSIGN_OR_RETURN(
-        int bits_needed,
-        dpf_internal::BitsNeeded(parameters[i].value_type(),
-                                 parameters[i].security_parameter()));
-    blocks_needed[i] = (bits_needed + 127) / 128;
-  }
-
-  // Set up hash functions for PRG.
-  DPF_ASSIGN_OR_RETURN(Aes128FixedKeyHash prg_left,
-                       Aes128FixedKeyHash::Create(kPrgKeyLeft));
-  DPF_ASSIGN_OR_RETURN(Aes128FixedKeyHash prg_right,
-                       Aes128FixedKeyHash::Create(kPrgKeyRight));
-  DPF_ASSIGN_OR_RETURN(Aes128FixedKeyHash prg_value,
-                       Aes128FixedKeyHash::Create(kPrgKeyValue));
-
-  // For backwards compatibility, register all single unsigned integers as value
-  // types.
-  absl::flat_hash_map<std::string, ValueCorrectionFunction>
-      value_correction_functions;
-  DPF_RETURN_IF_ERROR(
-      RegisterValueTypeImpl<uint8_t>(value_correction_functions));
-  DPF_RETURN_IF_ERROR(
-      RegisterValueTypeImpl<uint16_t>(value_correction_functions));
-  DPF_RETURN_IF_ERROR(
-      RegisterValueTypeImpl<uint32_t>(value_correction_functions));
-  DPF_RETURN_IF_ERROR(
-      RegisterValueTypeImpl<uint64_t>(value_correction_functions));
-  DPF_RETURN_IF_ERROR(
-      RegisterValueTypeImpl<absl::uint128>(value_correction_functions));
-
-  // Copy parameters and return new DPF.
-  return absl::WrapUnique(new DistributedPointFunction(
-      std::move(proto_validator), std::move(blocks_needed), std::move(prg_left),
-      std::move(prg_right), std::move(prg_value),
-      std::move(value_correction_functions)));
-}
-
-absl::StatusOr<std::pair<DpfKey, DpfKey>>
-DistributedPointFunction::GenerateKeysIncremental(
-    absl::uint128 alpha, absl::Span<const Value> beta) {
-  // Check validity of beta.
-  if (beta.size() != parameters_.size()) {
-    return absl::InvalidArgumentError(
-        "`beta` has to have the same size as `parameters` passed at "
-        "construction");
-  }
-  for (int i = 0; i < static_cast<int>(parameters_.size()); ++i) {
-    absl::Status status = proto_validator_->ValidateValue(beta[i], i);
-    if (!status.ok()) {
-      return status;
-    }
-  }
-
-  // Check validity of alpha.
-  int last_level_log_domain_size = parameters_.back().log_domain_size();
-  if (last_level_log_domain_size < 128 &&
-      alpha >= (absl::uint128{1} << last_level_log_domain_size)) {
-    return absl::InvalidArgumentError(
-        "`alpha` must be smaller than the output domain size");
-  }
-
-  std::array<DpfKey, 2> keys;
-  keys[0].set_party(0);
-  keys[1].set_party(1);
-
-  // We will annotate the following code with the corresponding lines from the
-  // pseudocode in the Incremental DPF paper
-  // (https://arxiv.org/pdf/2012.14884.pdf, Figure 11).
-  //
-  // There are two possible dimensions for each variable at each level: Parties
-  // (0 or 1) and branches (left or right). For two-dimensional arrays, we use
-  // the outer dimension for the branch, and the inner dimension for the party.
-  //
-  // Line 2: Sample random seeds for each party.
-  std::array<absl::uint128, 2> seeds;
-  RAND_bytes(reinterpret_cast<uint8_t*>(&seeds[0]), sizeof(absl::uint128));
-  RAND_bytes(reinterpret_cast<uint8_t*>(&seeds[1]), sizeof(absl::uint128));
-  keys[0].mutable_seed()->set_high(absl::Uint128High64(seeds[0]));
-  keys[0].mutable_seed()->set_low(absl::Uint128Low64(seeds[0]));
-  keys[1].mutable_seed()->set_high(absl::Uint128High64(seeds[1]));
-  keys[1].mutable_seed()->set_low(absl::Uint128Low64(seeds[1]));
-
-  // Line 3: Initialize control bits.
-  std::array<bool, 2> control_bits{0, 1};
-
-  // Line 4: Compute correction words for each level after the first one.
-  keys[0].mutable_correction_words()->Reserve(tree_levels_needed_ - 1);
-  keys[1].mutable_correction_words()->Reserve(tree_levels_needed_ - 1);
-  for (int i = 1; i < tree_levels_needed_; i++) {
-    DPF_RETURN_IF_ERROR(GenerateNext(i, alpha, beta, absl::MakeSpan(seeds),
-                                     absl::MakeSpan(control_bits),
-                                     absl::MakeSpan(keys)));
-  }
-
-  // Compute output correction word for last layer.
-  DPF_ASSIGN_OR_RETURN(
-      std::vector<Value> last_level_value_correction,
-      ComputeValueCorrection(parameters_.size() - 1, seeds, alpha, beta.back(),
-                             control_bits[1]));
-  for (const Value& value : last_level_value_correction) {
-    *(keys[0].add_last_level_value_correction()) = value;
-    *(keys[1].add_last_level_value_correction()) = value;
-  }
-
-  return std::make_pair(std::move(keys[0]), std::move(keys[1]));
-}
-
-absl::StatusOr<EvaluationContext>
-DistributedPointFunction::CreateEvaluationContext(DpfKey key) const {
-  // Check that `key` is valid.
-  DPF_RETURN_IF_ERROR(proto_validator_->ValidateDpfKey(key));
-
-  // Create new EvaluationContext with `parameters_` and `key`.
-  EvaluationContext result;
-  for (int i = 0; i < static_cast<int>(parameters_.size()); ++i) {
-    *(result.add_parameters()) = parameters_[i];
-  }
-  *(result.mutable_key()) = std::move(key);
-  // previous_hierarchy_level = -1 means that this context has not been
-  // evaluated at all.
-  result.set_previous_hierarchy_level(-1);
-  return result;
-}
-
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/distributed_point_function.h b/third_party/distributed_point_functions/code/dpf/distributed_point_function.h
deleted file mode 100644
index 6cd1c56a..0000000
--- a/third_party/distributed_point_functions/code/dpf/distributed_point_function.h
+++ /dev/null
@@ -1,1211 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_DISTRIBUTED_POINT_FUNCTION_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_DISTRIBUTED_POINT_FUNCTION_H_
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <limits>
-#include <memory>
-#include <string>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-#include "absl/container/btree_map.h"
-#include "absl/container/flat_hash_map.h"
-#include "absl/container/inlined_vector.h"
-#include "absl/log/absl_check.h"
-#include "absl/meta/type_traits.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/str_format.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-#include "dpf/aes_128_fixed_key_hash.h"
-#include "dpf/distributed_point_function.pb.h"
-#include "dpf/internal/evaluate_prg_hwy.h"
-#include "dpf/internal/maybe_deref_span.h"
-#include "dpf/internal/proto_validator.h"
-#include "dpf/internal/value_type_helpers.h"
-#include "google/protobuf/repeated_ptr_field.h"
-#include "hwy/aligned_allocator.h"
-
-namespace distributed_point_functions {
-
-// Type trait for all supported types. Used to provide meaningful error messages
-// in std::enable_if template guards.
-template <typename T>
-using is_supported_type = dpf_internal::is_supported_type<T>;
-template <typename T>
-constexpr bool is_supported_type_v = is_supported_type<T>::value;
-
-// Converts a given Value to the template parameter T.
-//
-// Returns INVALID_ARGUMENT if the conversion fails.
-template <typename T, typename = absl::enable_if_t<is_supported_type_v<T>>>
-absl::StatusOr<T> FromValue(const Value& value) {
-  return dpf_internal::ValueTypeHelper<T>::FromValue(value);
-}
-
-// ToValue Converts the argument to a Value.
-template <typename T, typename = absl::enable_if_t<is_supported_type_v<T>>>
-Value ToValue(const T& input) {
-  return dpf_internal::ValueTypeHelper<T>::ToValue(input);
-}
-
-// ToValueType<T> Returns a `ValueType` message describing T.
-template <typename T, typename = absl::enable_if_t<is_supported_type_v<T>>>
-ValueType ToValueType() {
-  return dpf_internal::ValueTypeHelper<T>::ToValueType();
-}
-
-// Implements key generation and evaluation of distributed point functions.
-// A distributed point function (DPF) is parameterized by an index `alpha` and a
-// value `beta`. The key generation procedure produces two keys `k_a`, `k_b`.
-// Evaluating each key on any point `x` in the DPF domain results in an additive
-// secret share of `beta`, if `x == alpha`, and a share of 0 otherwise. This
-// class also supports *incremental* DPFs that can additionally be evaluated on
-// prefixes of points, resulting in different values `beta_i`for each prefix of
-// `alpha`.
-class DistributedPointFunction {
- public:
-  // Creates a new instance of a distributed point function that can be
-  // evaluated only at the output layer.
-  //
-  // Returns INVALID_ARGUMENT if the parameters are invalid.
-  static absl::StatusOr<std::unique_ptr<DistributedPointFunction>> Create(
-      const DpfParameters& parameters);
-
-  // Creates a new instance of an *incremental* DPF that can be evaluated at
-  // multiple layers. Each parameter set in `parameters` should specify the
-  // domain size and element size at one of the layers to be evaluated, in
-  // increasing domain size order. Element sizes must be non-decreasing.
-  //
-  // Returns INVALID_ARGUMENT if the parameters are invalid.
-  static absl::StatusOr<std::unique_ptr<DistributedPointFunction>>
-  CreateIncremental(absl::Span<const DpfParameters> parameters);
-
-  // DistributedPointFunction is neither copyable nor movable.
-  DistributedPointFunction(const DistributedPointFunction&) = delete;
-  DistributedPointFunction& operator=(const DistributedPointFunction&) = delete;
-
-  // Converts the argument to a `Value` proto. Also registers the corresponding
-  // value type with the DPF by calling `RegisterValueType<T>()`.
-  template <typename T>
-  absl::StatusOr<Value> ToValue(const T& in) {
-    absl::Status status = RegisterValueType<T>();
-    if (!status.ok()) {
-      return status;
-    }
-    return distributed_point_functions::ToValue(in);
-  }
-
-  // Registers the template parameter type with this DPF. Note that it is rarely
-  // necessary to call this function by hand: It is called by `Create` and
-  // `CreateIncremental` for all unsigned integer types, including
-  // absl::uint128, and on every call to ToValue<T>. Only call this function
-  // when passing `Value`s created by other means than ToValue<T>.
-  //
-  // Returns OK on success and otherwise an INTERNAL status describing the
-  // failure.
-  template <typename T>
-  absl::Status RegisterValueType() {
-    return RegisterValueTypeImpl<T>(value_correction_functions_);
-  }
-
-  // Generates a pair of keys for a DPF that evaluates to `beta` when evaluated
-  // `alpha`. The type of `beta` must match the ValueType passed in `parameters`
-  // at construction.
-  //
-  // This function provides three overloads: One with `absl::uint128` for
-  // `beta`, which implies the output type is a simple integer; One with a
-  // `Value` proto for `beta`, which can be used for all supported value types;
-  // And a templated version that computes the Value by calling ToValue<T> on
-  // the argument.
-  //
-  // Example Usages (assuming a std::unique_ptr<DistributedPointFunction> dpf):
-  //
-  //   // Simple integer:
-  //   dpf->GenerateKeys(23, 42);
-  //
-  //   // Explicit `Value` proto:
-  //   Value value;
-  //   value[1]->mutable_tuple->add_elements()
-  //     ->mutable_integer->set_value_uint64(12);
-  //   value[1]->mutable_tuple->add_elements()
-  //     ->mutable_integer->set_value_uint64(34);
-  //   // Must be called once before calling GenerateKeys for any type that is
-  //   // not a simple integer. The type should match the one in the
-  //   // DpfParameters passed at construction.
-  //   dpf->RegisterValueType<Tuple<uint32_t, uint64_t>>();
-  //   dpf->GenerateKeys(23, value);
-  //
-  //   // Templated version (no call to RegisterValueType needed):
-  //   dpf->GenerateKeys(23, Tuple<uint32_t, uint64_t>{12, 34});
-  //
-  // Returns INVALID_ARGUMENT if used on an incremental DPF with more
-  // than one set of parameters, if `alpha` is outside of the domain specified
-  // at construction, or if `beta` does not match the value type passed at
-  // construction.
-  // Returns FAILED_PRECONDITION if `RegisterValueType<T>` has not been called
-  // for the type in the `DpfParameters` passed at construction.
-
-  // Overload for simple integers.
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> GenerateKeys(absl::uint128 alpha,
-                                                         absl::uint128 beta) {
-    return GenerateKeysIncremental(alpha, absl::MakeConstSpan(&beta, 1));
-  }
-
-  // Overload for explicit Value proto.
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> GenerateKeys(absl::uint128 alpha,
-                                                         Value beta) {
-    return GenerateKeysIncremental(alpha, absl::MakeConstSpan(&beta, 1));
-  }
-
-  // Template for automatic conversion to Value proto. Disabled if the argument
-  // is convertible to `absl::uint128` or `Value` to make overloading
-  // unambiguous.
-  template <typename T, typename = absl::enable_if_t<
-                            !std::is_convertible<T, absl::uint128>::value &&
-                            !std::is_convertible<T, Value>::value &&
-                            is_supported_type_v<T>>>
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> GenerateKeys(absl::uint128 alpha,
-                                                         const T& beta) {
-    absl::StatusOr<Value> value = ToValue<T>(beta);
-    if (!value.ok()) {
-      return value.status();
-    }
-    return GenerateKeysIncremental(alpha, absl::MakeConstSpan(&(*value), 1));
-  }
-
-  // Generates a pair of keys for an incremental DPF. For each parameter i
-  // passed at construction, the DPF evaluates to `beta[i]` at the lowest
-  // `parameters_[i].log_domain_size()` bits of `alpha`.
-  //
-  // Similar to `GenerateKeys`, supports three overloads: One for simple
-  // integers, passed as an `absl::Span<const absl::uint128>`; One for a span of
-  // `Value` protos; And a variadic function template that automatically
-  // converts the passed arguments to a vector of `Value`s.
-  //
-  // Example Usages (assuming a std::unique_ptr<DistributedPointFunction> dpf):
-  //
-  //   // Simple integers:
-  //   std::vector<absl::uint128> beta{123, 456};
-  //   dpf->GenerateKeysIncremental(23, beta);
-  //
-  //   // Explicit Value protos:
-  //   std::vector<Value> beta(2);
-  //   value[0]->mutable_integer()->set_value_uint128(42);
-  //   value[1]->mutable_tuple->add_elements()
-  //   ->mutable_integer->set_value_uint64(12);
-  //   value[1]->mutable_tuple->add_elements()
-  //   ->mutable_integer->set_value_uint64(34);
-  //   // Must be called once before calling GenerateKeys for any type that is
-  //   // not a simple integer. The type should match the one in the
-  //   // DpfParameters passed at construction.
-  //   dpf->RegisterValueType<Tuple<uint32_t, uint64_t>>();
-  //   dpf->GenerateKeysIncremental(23, beta);
-  //
-  //   // Templated version (equivalent to the one above):
-  //   dpf->GenerateKeysIncremental(23, 42, Tuple<uint32_t, uint64_t>{12, 34}));
-  //
-  // Returns INVALID_ARGUMENT if `beta.size() != parameters_.size()`, if `alpha`
-  // is outside of the domain specified at construction, or if `beta` does not
-  // match the element type passed at construction.
-  // Returns FAILED_PRECONDITION if `RegisterValueType<T>` has not been called
-  // for all types in the `DpfParameters` passed at construction.
-
-  // Legacy interface for absl::uint128, which doesn't require explicitly
-  // converting to absl::Span<const absl::uint128>.
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> GenerateKeysIncremental(
-      absl::uint128 alpha, const std::vector<absl::uint128>& beta) {
-    return GenerateKeysIncremental(alpha, absl::MakeConstSpan(beta));
-  }
-
-  // Templated version when all value types are equal.
-  template <typename T>
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> GenerateKeysIncremental(
-      absl::uint128 alpha, absl::Span<const T> beta) {
-    std::vector<Value> values(beta.size());
-    for (int i = 0; i < static_cast<int>(beta.size()); ++i) {
-      absl::StatusOr<Value> value = ToValue(beta[i]);
-      if (!value.ok()) {
-        return value.status();
-      }
-      values[i] = std::move(*value);
-    }
-    return GenerateKeysIncremental(alpha, values);
-  }
-
-  // Overload for Value protos.
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> GenerateKeysIncremental(
-      absl::uint128 alpha, absl::Span<const Value> beta);
-
-  // Variadic template version. Disabled if the first argument is convertible to
-  // a span of `absl::uint128`s or `Value`s to make overloading unambiguous.
-  template <
-      typename T0, typename... Tn,
-      typename = absl::enable_if_t<
-          !std::is_convertible<T0, absl::Span<const Value>>::value &&
-          !std::is_convertible<T0, absl::Span<const absl::uint128>>::value &&
-          absl::conjunction<is_supported_type<T0>,
-                            is_supported_type<Tn>...>::value>>
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> GenerateKeysIncremental(
-      absl::uint128 alpha, T0&& beta_0, Tn&&... beta_n);
-
-  // Returns an `EvaluationContext` for incrementally evaluating the given
-  // DpfKey.
-  //
-  // Returns INVALID_ARGUMENT if `key` doesn't match the parameters given at
-  // construction.
-  absl::StatusOr<EvaluationContext> CreateEvaluationContext(DpfKey key) const;
-
-  // Evaluates the given `hierarchy_level` of the DPF under all `prefixes`
-  // passed to this function. If `prefixes` is empty, evaluation starts from the
-  // seed of `ctx.key`. Otherwise, each element of `prefixes` must fit in the
-  // domain size of `ctx.previous_hierarchy_level`. Further, `prefixes` may only
-  // contain extensions of the prefixes passed in the previous call. For
-  // example, in the following sequence of calls, for each element p2 of
-  // `prefixes2`, there must be an element p1 of `prefixes1` such that p1 is a
-  // prefix of p2:
-  //
-  //   DPF_ASSIGN_OR_RETURN(std::unique_ptr<EvaluationContext> ctx,
-  //                        dpf->CreateEvaluationContext(key));
-  //   using T0 = ...;
-  //   DPF_ASSIGN_OR_RETURN(std::vector<T0> evaluations0,
-  //                        dpf->EvaluateUntil(0, {}, *ctx));
-  //
-  //   std::vector<absl::uint128> prefixes1 = ...;
-  //   using T1 = ...;
-  //   DPF_ASSIGN_OR_RETURN(std::vector<T1> evaluations1,
-  //                        dpf->EvaluateUntil(1, prefixes1, *ctx));
-  //   ...
-  //   std::vector<absl::uint128> prefixes2 = ...;
-  //   using T2 = ...;
-  //   DPF_ASSIGN_OR_RETURN(std::vector<T2> evaluations2,
-  //                        dpf->EvaluateUntil(3, prefixes2, *ctx));
-  //
-  // The prefixes are read from the lowest-order bits of the corresponding
-  // absl::uint128. The number of bits used for each prefix depends on the
-  // output domain size of the previously evaluated hierarchy level. For
-  // example, if `ctx` was last evaluated on a hierarchy level with output
-  // domain size 2**20, then the 20 lowest-order bits of each element in
-  // `prefixes` are used.
-  //
-  // Returns `INVALID_ARGUMENT` if
-  //   - any element of `prefixes` is larger than the next hierarchy level's
-  //     log_domain_size,
-  //   - `prefixes` contains elements that are not extensions of previous
-  //     prefixes, or
-  //   - the bit-size of T doesn't match the next hierarchy level's
-  //     element_bitsize.
-  template <typename T>
-  absl::StatusOr<std::vector<T>> EvaluateUntil(
-      int hierarchy_level, absl::Span<const absl::uint128> prefixes,
-      EvaluationContext& ctx) const;
-
-  template <typename T>
-  absl::StatusOr<std::vector<T>> EvaluateNext(
-      absl::Span<const absl::uint128> prefixes, EvaluationContext& ctx) const {
-    if (prefixes.empty()) {
-      return EvaluateUntil<T>(0, prefixes, ctx);
-    } else {
-      return EvaluateUntil<T>(ctx.previous_hierarchy_level() + 1, prefixes,
-                              ctx);
-    }
-  }
-
-  // Evaluates a single key at one or multiple points, up to the given
-  // `hierarchy_level`. Each element of `evaluation_points` must be within the
-  // domain of this DPF at `hierarchy_level`.
-  //
-  // Example:
-  //
-  //   DpfKey key = ...;
-  //   std::vector<absl::uint128> evaluation_points = {1, 23, 42};
-  //   // Evaluate `key` on {1, 23, 42}.
-  //   DPF_ASSIGN_OR_RETURN(std::vector<T> result,
-  //                        dpf->EvaluateAt(key, 0, evaluation_points);
-  //
-  // Returns INVALID_ARGUMENT if `key` is malformed, or if `hierarchy_level` or
-  // any element of `evaluation_points` is out of range.
-  template <typename T>
-  absl::StatusOr<std::vector<T>> EvaluateAt(
-      const DpfKey& key, int hierarchy_level,
-      absl::Span<const absl::uint128> evaluation_points) const {
-    return EvaluateAtImpl<T>(key, hierarchy_level, evaluation_points, nullptr);
-  }
-
-  // Evaluates a single key at one or multiple points, up to the given
-  // `hierarchy_level`. Each element of `evaluation_points` must be within the
-  // domain of this DPF at `hierarchy_level`.
-  //
-  // If `ctx.partial_evaluations_size() != 0`, uses the given partial
-  // evaluations as starting point of the DPF evaluation. Otherwise, the result
-  // is equivalent to calling `EvaluateAt(ctx.key(), hierarchy_level,
-  // evaluation_points)`.
-  //
-  // When successful, `ctx` is updated to include partial evaluations at
-  // `hierarchy_level`. The contents of `ctx` are undefined in case of an error.
-  //
-  // Returns INVALID_ARGUMENT if `ctx` is malformed, if `hierarchy_level` or
-  // any element of `evaluation_points` is out of range, or
-  // `ctx.partial_evaluations()` does not contain the prefixes of all
-  // `evaluation_points` at `ctx.partial_evaluations_level()`.
-  template <typename T>
-  absl::StatusOr<std::vector<T>> EvaluateAt(
-      int hierarchy_level, absl::Span<const absl::uint128> evaluation_points,
-      EvaluationContext& ctx) const {
-    return EvaluateAtImpl<T>(ctx.key(), hierarchy_level, evaluation_points,
-                             &ctx);
-  }
-
-  // Evaluates a span of DPF keys. The i-th key is evaluated at
-  // evaluation_points[i]. After each hierarchy level, calls `op` on the output
-  // at that hierarchy level. `op` must be callable with the following
-  // signature:
-  //
-  //  op(int hierarchy_level, absl::Span<T> values)
-  //
-  // It should return a value that is implicitly convertible to `bool`.
-  //
-  // This method is intended for use cases similar to
-  //
-  // absl::StatusOr<std::vector<T>> EvaluateAt(
-  //   int hierarchy_level, absl::Span<const absl::uint128> evaluation_points,
-  //   EvaluationContext& ctx)
-  //
-  // but without the overhead of EvaluationContext. Instead, all operations on
-  // intermediate values, and obtaining the final result, should be done via
-  // `op`.
-  //
-  // Return absl::OkStatus() after successfully evaluating `op` on the last
-  // hierarchy level, or as soon as `op` returns `false`. Returns
-  // INVALID_ARGUMENT in case any `key` is malformed, or if any of the
-  // `evaluation_points` are out of range.
-  template <typename T, typename Fn>
-  absl::Status EvaluateAndApply(
-      dpf_internal::MaybeDerefSpan<const DpfKey>,
-      absl::Span<const absl::uint128> evaluation_points, Fn op,
-      int evaluation_points_rightshift = 0) const;
-
-  // Returns the DpfParameters of this DPF.
-  inline absl::Span<const DpfParameters> parameters() const {
-    return parameters_;
-  }
-
- private:
-  // BitVector is a vector of bools. Allows for faster access times than
-  // std::vector<bool>, as well as inlining if the size is small.
-  using BitVector =
-      absl::InlinedVector<bool,
-                          std::max<size_t>(1, sizeof(bool*) / sizeof(bool))>;
-
-  // Seeds and control bits resulting from a DPF expansion. This type is
-  // returned by `ExpandSeeds` and `ExpandAndUpdateContext`.
-  struct DpfExpansion {
-    // Ensures that seeds are aligned correctly for SIMD operations.
-    hwy::AlignedFreeUniquePtr<absl::uint128[]> seeds;
-    BitVector control_bits;
-  };
-
-  // A function for computing value corrections. Used as return type in
-  // `GetValueCorrectionFunction`.
-  using ValueCorrectionFunction = absl::StatusOr<std::vector<Value>> (*)(
-      absl::string_view, absl::string_view, int block_index, const Value&,
-      bool);
-
-  // Private constructor, called by `CreateIncremental`.
-  DistributedPointFunction(
-      std::unique_ptr<dpf_internal::ProtoValidator> proto_validator,
-      std::vector<int> blocks_needed, Aes128FixedKeyHash prg_left,
-      Aes128FixedKeyHash prg_right, Aes128FixedKeyHash prg_value,
-      absl::flat_hash_map<std::string, ValueCorrectionFunction>
-          value_correction_functions);
-
-  // Computes the value correction for the given `hierarchy_level`, `seeds`,
-  // index `alpha` and value `beta`. If `invert` is true, the individual values
-  // in the returned block are multiplied element-wise by -1. Expands `seeds`
-  // using `prg_ctx_value_`, then calls the function returned by
-  // `GetValueCorrectionFunction(parameters_[hierarchy_level])` to obtain the
-  // value correction words.
-  //
-  // Returns multiple values in the case of packing, and a single Value
-  // otherwise.
-  //
-  // Returns INTERNAL in case the PRG expansion fails, and UNIMPLEMENTED if
-  // `element_bitsize` is not supported.
-  absl::StatusOr<std::vector<Value>> ComputeValueCorrection(
-      int hierarchy_level, absl::Span<const absl::uint128> seeds,
-      absl::uint128 alpha, const Value& beta, bool invert) const;
-
-  // Expands the PRG seeds at the next `tree_level` for an incremental DPF with
-  // index `alpha` and values `beta`, updates `seeds` and `control_bits`, and
-  // writes the next correction word to `keys`. Called from
-  // `GenerateKeysIncremental`.
-  absl::Status GenerateNext(int tree_level, absl::uint128 alpha,
-                            absl::Span<const Value> beta,
-                            absl::Span<absl::uint128> seeds,
-                            absl::Span<bool> control_bits,
-                            absl::Span<DpfKey> keys) const;
-
-  // Computes the tree index (representing a path in the FSS tree) from the
-  // given `domain_index` and `hierarchy_level`. Does NOT check whether the
-  // given domain index fits in the domain at `hierarchy_level`.
-  absl::uint128 DomainToTreeIndex(absl::uint128 domain_index,
-                                  int hierarchy_level) const;
-
-  // Computes the block index (pointing to an element in a batched 128-bit
-  // block) from the given `domain_index` and `hierarchy_level`. Does NOT check
-  // whether the given domain index fits in the domain at `hierarchy_level`.
-  int DomainToBlockIndex(absl::uint128 domain_index, int hierarchy_level) const;
-
-  // Performs DPF evaluation of the given `seeds` using prg_ctx_left_ or
-  // prg_ctx_right_, and the given `control_bits` and `correction_words`. At
-  // each level `l < correction_words.size()`, the evaluation for the i-th seed
-  // in `partial_evaluations` continues along the left or right path depending
-  // on the l-th most significant bit among the lowest `correction_words.size()`
-  // bits of `paths[i]`.
-  //
-  // The output is written to `seeds_out` and `control_bits_out`. These may
-  // overlap with `seeds` and `control_bits`. We use output spans instead of a
-  // return value to allow the caller to pre-allocate aligned output arrays,
-  // which is necessary for the vectorized implementation. The output is
-  // undefined if `correction_words.size() == 0`.
-  //
-  // Returns INVALID_ARGUMENT if the input sizes don't match.
-  // Returns INTERNAL in case of OpenSSL errors.
-  absl::Status EvaluateSeeds(
-      absl::Span<const absl::uint128> seeds,
-      absl::Span<const bool> control_bits,
-      absl::Span<const absl::uint128> paths,
-      absl::Span<const CorrectionWord* const> correction_words,
-      absl::Span<absl::uint128> seeds_out,
-      absl::Span<bool> control_bits_out) const;
-
-  // Performs DPF expansion of the given `partial_evaluations` using
-  // prg_ctx_left_ and prg_ctx_right_, and the given `correction_words`. In
-  // more detail, each of the partial evaluations is subjected to a full
-  // subtree expansion of `correction_words.size()` levels, and the
-  // concatenated result is provided in the response. The result contains
-  // `(partial_evaluations.size() * (2^correction_words.size())` evaluations
-  // in a single `DpfExpansion`.
-  //
-  // Returns INTERNAL in case of OpenSSL errors.
-  absl::StatusOr<DpfExpansion> ExpandSeeds(
-      const DpfExpansion& partial_evaluations,
-      absl::Span<const CorrectionWord* const> correction_words) const;
-
-  // Computes partial evaluations of the paths to `prefixes` up to
-  // `hierarchy_level`, to be used as the starting point of the expansion of
-  // `ctx`. If `update_ctx
-  // == true`, saves the partial evaluations of `ctx.previous_hierarchy_level`
-  // to `ctx` and sets `ctx.partial_evaluations_level` to
-  // `ctx.previous_hierarchy_level`. Called by `ExpandAndUpdateContext`.
-  //
-  // Returns INVALID_ARGUMENT if any element of `prefixes` is not found in
-  // `ctx.partial_evaluations()`, or `ctx.partial_evaluations()` contains
-  // duplicate prefixes with inconsistent seeds or control bits.
-  absl::StatusOr<DpfExpansion> ComputePartialEvaluations(
-      absl::Span<const absl::uint128> prefixes, int hierarchy_level,
-      bool update_ctx, EvaluationContext& ctx) const;
-
-  // Extracts the seeds for the given `prefixes` from `ctx` and expands them as
-  // far as needed for the next hierarchy level. Returns the result as a
-  // `DpfExpansion`. Called by `EvaluateUntil`, where the expanded seeds are
-  // corrected to obtain output values.
-  // After expansion, `ctx.hierarchy_level()` is increased. If this isn't the
-  // last expansion, the expanded seeds are also saved in `ctx` for the next
-  // expansion.
-  //
-  // Returns INVALID_ARGUMENT if any element of `prefixes` is not found in
-  // `ctx.partial_evaluations()`, or `ctx.partial_evaluations()` contains
-  // duplicate prefixes with inconsistent seeds or control bits. Returns
-  // INTERNAL in case of OpenSSL errors.
-  absl::StatusOr<DpfExpansion> ExpandAndUpdateContext(
-      int hierarchy_level, absl::Span<const absl::uint128> prefixes,
-      EvaluationContext& ctx) const;
-
-  // Compute output PRG value of expanded seeds using prg_ctx_value_.
-  // Returns blocks_needed_[hierarchy_level] * expansion.seeds.size() blocks,
-  // where every blocks_needed_[hierarchy_level] correspond to the hash of an
-  // input seed.
-  //
-  // Returns INTERNAL in case of OpenSSL errors.
-  absl::StatusOr<hwy::AlignedFreeUniquePtr<absl::uint128[]>> HashExpandedSeeds(
-      int hierarchy_level, absl::Span<const absl::uint128> expansion) const;
-
-  // Deterministically serializes the given value_type.
-  //
-  // Returns OK on success and INTERNAL in case serialization fails.
-  static absl::StatusOr<std::string> SerializeValueTypeDeterministically(
-      const ValueType& value_type);
-
-  // Returns the value correction function for the given parameters.
-  // For all value types except unsigned integers, these functions have to be
-  // first registered using RegisterValueType<T>.
-  //
-  // Returns UNIMPLEMENTED if no matching function was registered.
-  absl::StatusOr<ValueCorrectionFunction> GetValueCorrectionFunction(
-      const DpfParameters& parameters) const;
-
-  // Static implementation of RegisterValueType<T>, so we can call it from
-  // `Create`.
-  template <typename T>
-  static absl::Status RegisterValueTypeImpl(
-      absl::flat_hash_map<std::string, ValueCorrectionFunction>&
-          value_correction_functions);
-
-  // For the given `key` and `hierarchy_level`, returns the value correction
-  // words as an array of integers, where the size of the array matches the
-  // number of batched elements per block.
-  template <typename T>
-  absl::StatusOr<std::array<T, dpf_internal::ElementsPerBlock<T>()>>
-  GetValueCorrectionAsArray(const DpfKey& key, int hierarchy_level) const;
-
-  // Joint implementation of the two variants of `EvaluateAt<T>`. If `ctx !=
-  // NULL`, `key` must point to `ctx->key()`, and `*ctx` will be updated with
-  // the partial evaluations at this `hierarchy_level`.
-  //
-  template <typename T>
-  absl::StatusOr<std::vector<T>> EvaluateAtImpl(
-      const DpfKey& key, int hierarchy_level,
-      absl::Span<const absl::uint128> evaluation_points,
-      EvaluationContext* ctx) const;
-
-  // Used to validate DpfParameters, DpfKey and EvaluationContext protos.
-  const std::unique_ptr<dpf_internal::ProtoValidator> proto_validator_;
-
-  // DP parameters passed to the factory function. Contains the domain size and
-  // element size for hierarchy level of the incremental DPF. Owned by
-  // proto_validator_.
-  const absl::Span<const DpfParameters> parameters_;
-
-  // Number of levels in the evaluation tree. This is always less than or equal
-  // to the largest log_domain_size in parameters_.
-  const int tree_levels_needed_;
-
-  // Maps levels of the FSS evaluation tree to hierarchy levels (i.e., elements
-  // of parameters_).
-  const absl::flat_hash_map<int, int>& tree_to_hierarchy_;
-
-  // The inverse of tree_to_hierarchy_.
-  const std::vector<int>& hierarchy_to_tree_;
-
-  // Cached numbers of AES blocks needed for value correction at each hierarchy
-  // level.
-  const std::vector<int> blocks_needed_;
-
-  // Pseudorandom generator used for seed expansion (left and right), and value
-  // correction. The PRG G(x) for hierarchy level i is defined as the
-  // concatenation of
-  //
-  //   H_left(x), H_right(x), H_value(x + 0), ..., H_value(x + k-1)
-  //
-  // where k is equal to blocks_needed_[i], and H_*(x) is the evaluation of
-  // prg_*_ on input x.
-  const Aes128FixedKeyHash prg_left_;
-  const Aes128FixedKeyHash prg_right_;
-  const Aes128FixedKeyHash prg_value_;
-
-  // Maps serialized `ValueType` messages to the correct value correction
-  // functions. Map values are instantiations of
-  // `dpf_internal::ComputeValueCorrectionFor`. Relies on protobuf's
-  // deterministic serialization feature. This has the caveat that messages with
-  // unknown fields are not supported. However, as long as `ValueType` consists
-  // of a single `oneof` field, this is fine, since we either know the value
-  // type and have deterministic serialization because the `ValueType` can only
-  // contain one field, or we don't know the type and wouldn't be able to
-  // correct values for it anyway.
-  absl::flat_hash_map<std::string, ValueCorrectionFunction>
-      value_correction_functions_;
-};
-
-//========================//
-// Implementation Details //
-//========================//
-
-template <typename T>
-absl::Status DistributedPointFunction::RegisterValueTypeImpl(
-    absl::flat_hash_map<std::string, ValueCorrectionFunction>&
-        value_correction_functions) {
-  ValueType value_type = ToValueType<T>();
-  absl::StatusOr<std::string> serialized_value_type =
-      SerializeValueTypeDeterministically(value_type);
-  if (!serialized_value_type.ok()) {
-    return serialized_value_type.status();
-  }
-  value_correction_functions[*serialized_value_type] =
-      dpf_internal::ComputeValueCorrectionFor<T>;
-  return absl::OkStatus();
-}
-
-template <typename T0, typename... Tn, typename /*= absl::enable_if_t<...>*/>
-absl::StatusOr<std::pair<DpfKey, DpfKey>>
-DistributedPointFunction::GenerateKeysIncremental(absl::uint128 alpha,
-                                                  T0&& beta_0, Tn&&... beta_n) {
-  // Convert the first element of beta. We need to treat it separately to be
-  // able to check its type in the enable_if above.
-  absl::StatusOr<Value> value = ToValue(beta_0);
-  if (!value.ok()) {
-    return value.status();
-  }
-  std::vector<Value> values = {std::move(*value)};
-  values.reserve(1 + sizeof...(beta_n));
-  // Convert all values in the parameter pack, stopping at the first error.
-  absl::Status status = absl::OkStatus();
-  // We create an unused std::tuple<Tn...> here, because its braced-initializer
-  // list constructor allows us to operate on beta_n in a well-defined order. In
-  // C++17, this could be replaced by a fold expression instead.
-  std::tuple<Tn...>{[this, &status, &values, &value](auto&& beta_i) -> Tn {
-    if (status.ok()) {
-      value = this->ToValue(beta_i);
-      if (value.ok()) {
-        values.push_back(std::move(*value));
-      } else {
-        status = value.status();
-      }
-    }
-    return Tn{};
-  }(beta_n)...};
-  // Return if there was an error during conversion, otherwise generate keys.
-  if (!status.ok()) {
-    return status;
-  }
-  return GenerateKeysIncremental(alpha, values);
-}
-
-template <typename T>
-absl::StatusOr<std::vector<T>> DistributedPointFunction::EvaluateUntil(
-    int hierarchy_level, absl::Span<const absl::uint128> prefixes,
-    EvaluationContext& ctx) const {
-  absl::Status status = proto_validator_->ValidateEvaluationContext(ctx);
-  if (!status.ok()) {
-    return status;
-  }
-  if (hierarchy_level < 0 ||
-      hierarchy_level >= static_cast<int>(parameters_.size())) {
-    return absl::InvalidArgumentError(
-        "`hierarchy_level` must be non-negative and less than "
-        "parameters_.size()");
-  }
-  absl::StatusOr<bool> types_are_equal = dpf_internal::ValueTypesAreEqual(
-      ToValueType<T>(), parameters_[hierarchy_level].value_type());
-  if (!types_are_equal.ok()) {
-    return types_are_equal.status();
-  } else if (!*types_are_equal) {
-    return absl::InvalidArgumentError(
-        "Value type T doesn't match parameters at `hierarchy_level`");
-  }
-  if (hierarchy_level <= ctx.previous_hierarchy_level()) {
-    return absl::InvalidArgumentError(
-        "`hierarchy_level` must be greater than "
-        "`ctx.previous_hierarchy_level`");
-  }
-  if ((ctx.previous_hierarchy_level() < 0) != (prefixes.empty())) {
-    return absl::InvalidArgumentError(
-        "`prefixes` must be empty if and only if this is the first call with "
-        "`ctx`.");
-  }
-
-  int previous_log_domain_size = 0;
-  int previous_hierarchy_level = ctx.previous_hierarchy_level();
-  if (!prefixes.empty()) {
-    ABSL_DCHECK_GE(ctx.previous_hierarchy_level(), 0);
-    previous_log_domain_size =
-        parameters_[previous_hierarchy_level].log_domain_size();
-    for (absl::uint128 prefix : prefixes) {
-      if (previous_log_domain_size < 128 &&
-          prefix >= (absl::uint128{1} << previous_log_domain_size)) {
-        return absl::InvalidArgumentError(
-            absl::StrFormat("Index %d out of range for hierarchy level %d",
-                            prefix, previous_hierarchy_level));
-      }
-    }
-  }
-  int64_t prefixes_size = static_cast<int64_t>(prefixes.size());
-
-  // Check that the output size is not too large. We first check that the
-  // domain size blowup fits in an int64_t, and then check that the total size
-  // of all elements doesn't over flow a size_t.
-  int log_domain_size = parameters_[hierarchy_level].log_domain_size();
-  if (log_domain_size - previous_log_domain_size >= 63) {
-    return absl::InvalidArgumentError(
-        "Domain size gap too large. Please evaluate fewer hierarchy "
-        "levels at once, or insert intermediate hierarchy levels.");
-  }
-  int64_t outputs_per_prefix = int64_t{1}
-                               << (log_domain_size - previous_log_domain_size);
-  if (absl::uint128{prefixes_size} * outputs_per_prefix >
-      std::numeric_limits<size_t>::max() / 2) {
-    return absl::InvalidArgumentError(
-        "Output size would be too large. Please evaluate fewer hierarchy "
-        "levels at once, insert intermediate hierarchy levels, or evaluate on "
-        "fewer prefixes at once.");
-  }
-
-  // The `prefixes` passed in by the caller refer to the domain of the previous
-  // hierarchy level. However, because we batch multiple elements of type T in a
-  // single uint128 block, multiple prefixes can actually refer to the same
-  // block in the FSS evaluation tree. On a high level, our approach is as
-  // follows:
-  //
-  // 1. Split up each element of `prefixes` into a tree index, pointing to a
-  //    block in the FSS tree, and a block index, pointing to an element of type
-  //    T in that block.
-  //
-  // 2. Compute a list of unique `tree_indices`, and for each original prefix,
-  //    remember the position of the corresponding tree index in `tree_indices`.
-  //
-  // 3. After expanding the unique `tree_indices`, use the positions saved in
-  //    Step (2) together with the corresponding block index to retrieve the
-  //    expanded values for each prefix, and return them in the same order as
-  //    `prefixes`.
-  //
-  // `tree_indices` holds the unique tree indices from `prefixes`, to be passed
-  // to `ExpandAndUpdateContext`.
-  std::vector<absl::uint128> tree_indices;
-  tree_indices.reserve(prefixes_size);
-  // `tree_indices_inverse` is the inverse of `tree_indices`, used for
-  // deduplicating and constructing `prefix_map`. Use a btree_map because we
-  // expect `prefixes` (and thus `tree_indices`) to be sorted.
-  absl::btree_map<absl::uint128, int64_t> tree_indices_inverse;
-  // `prefix_map` maps each i < prefixes.size() to an element of `tree_indices`
-  // and a block index. Used to select which elements to return after the
-  // expansion, to ensure the result is ordered the same way as `prefixes`.
-  std::vector<std::pair<int64_t, int>> prefix_map;
-  prefix_map.reserve(prefixes_size);
-  for (int64_t i = 0; i < prefixes_size; ++i) {
-    absl::uint128 tree_index =
-        DomainToTreeIndex(prefixes[i], previous_hierarchy_level);
-    int block_index = DomainToBlockIndex(prefixes[i], previous_hierarchy_level);
-
-    // Check if `tree_index` already exists in `tree_indices`.
-    size_t previous_size = tree_indices_inverse.size();
-    auto it = tree_indices_inverse.try_emplace(tree_indices_inverse.end(),
-                                               tree_index, tree_indices.size());
-    if (tree_indices_inverse.size() > previous_size) {
-      tree_indices.push_back(tree_index);
-    }
-    prefix_map.push_back(std::make_pair(it->second, block_index));
-  }
-
-  // Perform expansion of unique `tree_indices`.
-  absl::StatusOr<DpfExpansion> expansion =
-      ExpandAndUpdateContext(hierarchy_level, tree_indices, ctx);
-  if (!expansion.ok()) {
-    return expansion.status();
-  }
-  const auto expansion_size =
-      static_cast<int64_t>(expansion->control_bits.size());
-  auto seeds = absl::MakeConstSpan(expansion->seeds.get(), expansion_size);
-
-  // Hash the expanded seeds.
-  absl::StatusOr<hwy::AlignedFreeUniquePtr<absl::uint128[]>> hashed_expansion =
-      HashExpandedSeeds(hierarchy_level, seeds);
-  if (!hashed_expansion.ok()) {
-    return hashed_expansion.status();
-  }
-
-  // Get output correction word from `ctx`.
-  constexpr int elements_per_block = dpf_internal::ElementsPerBlock<T>();
-  const ::google::protobuf::RepeatedPtrField<Value>* value_correction = nullptr;
-  if (hierarchy_level < static_cast<int>(parameters_.size()) - 1) {
-    value_correction =
-        &(ctx.key()
-              .correction_words(hierarchy_to_tree_[hierarchy_level])
-              .value_correction());
-  } else {
-    // Last level value correction is stored in an extra proto field, since we
-    // have one less correction word than tree levels.
-    value_correction = &(ctx.key().last_level_value_correction());
-  }
-
-  // Split output correction into elements of type T.
-  absl::StatusOr<std::array<T, elements_per_block>> correction_ints =
-      dpf_internal::ValuesToArray<T>(*value_correction);
-  if (!correction_ints.ok()) {
-    return correction_ints.status();
-  }
-
-  // Compute value corrections for each block in `expanded_seeds`. We have to
-  // account for the fact that blocks might not be full (i.e., have less than
-  // elements_per_block elements).
-  const int corrected_elements_per_block =
-      1 << (parameters_[hierarchy_level].log_domain_size() -
-            hierarchy_to_tree_[hierarchy_level]);
-  const int blocks_needed = blocks_needed_[hierarchy_level];
-  ABSL_DCHECK(corrected_elements_per_block <= elements_per_block);
-  std::vector<T> corrected_expansion(expansion_size *
-                                     corrected_elements_per_block);
-  for (int64_t i = 0; i < expansion_size; ++i) {
-    std::array<T, elements_per_block> current_elements =
-        dpf_internal::ConvertBytesToArrayOf<T>(absl::string_view(
-            reinterpret_cast<const char*>(hashed_expansion->get() +
-                                          i * blocks_needed),
-            blocks_needed * sizeof(absl::uint128)));
-    for (int j = 0; j < corrected_elements_per_block; ++j) {
-      if (expansion->control_bits[i]) {
-        current_elements[j] += (*correction_ints)[j];
-      }
-      if (ctx.key().party() == 1) {
-        current_elements[j] = -current_elements[j];
-      }
-      corrected_expansion[i * corrected_elements_per_block + j] =
-          current_elements[j];
-    }
-  }
-
-  if (prefixes.empty()) {
-    // If prefixes is empty (i.e., this is the first evaluation of `ctx`), just
-    // return the expansion.
-    ABSL_DCHECK(static_cast<int>(corrected_expansion.size()) ==
-                outputs_per_prefix);
-    return corrected_expansion;
-  } else {
-    // Otherwise, only return elements under `prefixes`.
-    int blocks_per_tree_prefix =
-        expansion->control_bits.size() / tree_indices.size();
-    std::vector<T> result(prefixes_size * outputs_per_prefix);
-    for (int64_t i = 0; i < prefixes_size; ++i) {
-      int64_t prefix_expansion_start =
-          prefix_map[i].first * blocks_per_tree_prefix *
-              corrected_elements_per_block +
-          prefix_map[i].second * outputs_per_prefix;
-      std::copy_n(&corrected_expansion[prefix_expansion_start],
-                  outputs_per_prefix, &result[i * outputs_per_prefix]);
-    }
-    return result;
-  }
-}
-
-template <typename T>
-absl::StatusOr<std::array<T, dpf_internal::ElementsPerBlock<T>()>>
-DistributedPointFunction::GetValueCorrectionAsArray(const DpfKey& key,
-                                                    int hierarchy_level) const {
-  // Get output correction word from `key`.
-  const ::google::protobuf::RepeatedPtrField<Value>* value_correction = nullptr;
-  if (hierarchy_level < static_cast<int>(parameters_.size()) - 1) {
-    value_correction =
-        &(key.correction_words(hierarchy_to_tree_[hierarchy_level])
-              .value_correction());
-  } else {
-    // Last level value correction is stored in an extra proto field, since we
-    // have one less correction word than tree levels.
-    value_correction = &(key.last_level_value_correction());
-  }
-
-  // Split output correction into elements of type T, and return it.
-  return dpf_internal::ValuesToArray<T>(*value_correction);
-}
-
-template <typename T>
-absl::StatusOr<std::vector<T>> DistributedPointFunction::EvaluateAtImpl(
-    const DpfKey& key, int hierarchy_level,
-    absl::Span<const absl::uint128> evaluation_points,
-    EvaluationContext* ctx) const {
-  if (ctx != nullptr) {
-    if (&key != &ctx->key()) {
-      return absl::InvalidArgumentError(
-          "`key` and `ctx->key()` must refer to the same object");
-    }
-  }
-  if (hierarchy_level < 0) {
-    return absl::InvalidArgumentError("`hierarchy_level` must be non-negative");
-  }
-  if (hierarchy_level >= static_cast<int>(parameters_.size())) {
-    return absl::InvalidArgumentError(
-        "`hierarchy_level` must be less than the number of parameters passed "
-        "at construction");
-  }
-  const auto num_evaluation_points =
-      static_cast<int64_t>(evaluation_points.size());
-  const int log_domain_size = parameters_[hierarchy_level].log_domain_size();
-  absl::uint128 max_evaluation_point = absl::Uint128Max();
-  if (log_domain_size < 128) {
-    max_evaluation_point = (absl::uint128{1} << log_domain_size) - 1;
-  }
-  // Check if `evaluation_points` are inside the domain. This has minimal (~ 1%)
-  // performance impact.
-  for (int64_t i = 0; i < num_evaluation_points; ++i) {
-    if (evaluation_points[i] > max_evaluation_point) {
-      return absl::InvalidArgumentError(
-          absl::StrCat("`evaluation_points[", i,
-                       "]` larger than the domain size at hierarchy level ",
-                       hierarchy_level));
-    }
-  }
-  absl::Status status = proto_validator_->ValidateDpfKey(key);
-  if (!status.ok()) {
-    return status;
-  }
-  if (num_evaluation_points == 0) {
-    return std::vector<T>{};  // Nothing to do.
-  }
-
-  // Split up evaluation_points into tree indices and block indices, if we're
-  // operating on a packed type. Otherwise set `tree_indices` to
-  // `evaluation_points`.
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> maybe_recomputed_tree_indices;
-  constexpr int elements_per_block = dpf_internal::ElementsPerBlock<T>();
-  absl::Span<const absl::uint128> tree_indices;
-  if (elements_per_block > 1) {
-    maybe_recomputed_tree_indices =
-        hwy::AllocateAligned<absl::uint128>(num_evaluation_points);
-    if (maybe_recomputed_tree_indices == nullptr) {
-      return absl::ResourceExhaustedError("Memory allocation error");
-    }
-    for (int64_t i = 0; i < num_evaluation_points; ++i) {
-      maybe_recomputed_tree_indices[i] =
-          DomainToTreeIndex(evaluation_points[i], hierarchy_level);
-    }
-    tree_indices = absl::MakeConstSpan(maybe_recomputed_tree_indices.get(),
-                                       num_evaluation_points);
-    // Copy evaluation_points to new array if not aligned.
-  } else {
-    // This avoids copying the evaluation points when elements_per_block == 1.
-    tree_indices = evaluation_points;
-  }
-
-  // Set up partial evaluations for the selected tree_indices. If we have a
-  // context `ctx`, Compute them from `ctx.partial_evaluations`, otherwise start
-  // from the beginning.
-  absl::StatusOr<DpfExpansion> selected_partial_evaluations = DpfExpansion();
-  int start_level = 0;
-  if (!ctx) {
-    // No context or context was never evaluated -> start from the beginning.
-    absl::uint128 seed = absl::MakeUint128(key.seed().high(), key.seed().low());
-    bool party = key.party();
-    selected_partial_evaluations->seeds =
-        hwy::AllocateAligned<absl::uint128>(num_evaluation_points);
-    if (selected_partial_evaluations->seeds == nullptr) {
-      return absl::ResourceExhaustedError("Memory allocation error");
-    }
-    auto seeds = absl::MakeSpan(selected_partial_evaluations->seeds.get(),
-                                num_evaluation_points);
-    std::fill(seeds.begin(), seeds.end(), seed);
-    selected_partial_evaluations->control_bits.resize(num_evaluation_points,
-                                                      party);
-  } else {
-    // We have a context -> Use it to compute partial evaluations. Always update
-    // `ctx`, since unlike for full expansion the amount of proto data written
-    // will always be `tree_indices.size()` and should therefore be negligible.
-    selected_partial_evaluations =
-        ComputePartialEvaluations(tree_indices, hierarchy_level,
-                                  /*update_ctx=*/true, *ctx);
-    if (!selected_partial_evaluations.ok()) {
-      return selected_partial_evaluations.status();
-    }
-    start_level = hierarchy_to_tree_[hierarchy_level];
-  }
-
-  // Evaluate DPFs.
-  const int stop_level = hierarchy_to_tree_[hierarchy_level];
-  absl::Span<absl::uint128> seeds(
-      selected_partial_evaluations->seeds.get(),
-      selected_partial_evaluations->control_bits.size());
-  auto correction_words = absl::MakeConstSpan(key.correction_words())
-                              .subspan(start_level, stop_level - start_level);
-  status =
-      EvaluateSeeds(seeds, selected_partial_evaluations->control_bits,
-                    tree_indices, correction_words, seeds,
-                    absl::MakeSpan(selected_partial_evaluations->control_bits));
-  if (!status.ok()) {
-    return status;
-  }
-  ABSL_DCHECK(static_cast<int64_t>(seeds.size()) == num_evaluation_points);
-
-  // Hash `seeds`.
-  absl::StatusOr<hwy::AlignedFreeUniquePtr<absl::uint128[]>> hashed_expansion =
-      HashExpandedSeeds(hierarchy_level, seeds);
-  if (!hashed_expansion.ok()) {
-    return hashed_expansion.status();
-  }
-
-  // Get value correction words.
-  absl::StatusOr<std::array<T, elements_per_block>> correction_ints =
-      GetValueCorrectionAsArray<T>(key, hierarchy_level);
-  if (!correction_ints.ok()) {
-    return correction_ints.status();
-  }
-
-  // Perform value correction.
-  std::vector<T> result(num_evaluation_points);
-  const int blocks_needed = blocks_needed_[hierarchy_level];
-  for (int64_t i = 0; i < num_evaluation_points; ++i) {
-    std::array<T, elements_per_block> current_elements =
-        dpf_internal::ConvertBytesToArrayOf<T>(absl::string_view(
-            reinterpret_cast<const char*>(hashed_expansion->get() +
-                                          i * blocks_needed),
-            blocks_needed * sizeof(absl::uint128)));
-    int block_index = 0;
-    if (elements_per_block > 1) {
-      block_index = DomainToBlockIndex(evaluation_points[i], hierarchy_level);
-    }
-    result[i] = current_elements[block_index];
-    if (selected_partial_evaluations->control_bits[i]) {
-      result[i] += (*correction_ints)[block_index];
-    }
-    if (key.party() == 1) {
-      result[i] = -result[i];
-    }
-  }
-
-  if (ctx) {
-    ctx->set_previous_hierarchy_level(hierarchy_level);
-  }
-
-  return result;
-}
-
-template <typename T, typename Fn>
-absl::Status DistributedPointFunction::EvaluateAndApply(
-    dpf_internal::MaybeDerefSpan<const DpfKey> keys,
-    absl::Span<const absl::uint128> evaluation_points, Fn op,
-    int evaluation_points_rightshift) const {
-  if (evaluation_points.size() != keys.size()) {
-    return absl::InvalidArgumentError(
-        "`keys.size()` != `evaluation_points.size()`");
-  }
-  for (size_t i = 0; i < keys.size(); ++i) {
-    absl::Status status = proto_validator_->ValidateDpfKey(keys[i]);
-    if (!status.ok()) return status;
-  }
-
-  const int64_t num_keys = keys.size();
-  const int num_hierarchy_levels = parameters_.size();
-  DpfExpansion eval;
-  eval.control_bits.resize(num_keys);
-  eval.seeds = hwy::AllocateAligned<absl::uint128>(num_keys);
-  if (eval.seeds == nullptr) {
-    return absl::ResourceExhaustedError("Memory allocation error");
-  }
-  absl::Span<absl::uint128> seeds(eval.seeds.get(), num_keys);
-  absl::Span<bool> control_bits(eval.control_bits);
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> correction_seeds;
-  BitVector correction_control_bits_left, correction_control_bits_right;
-  std::vector<T> values(num_keys);
-
-  // Initialize seeds and control bits.
-  for (int64_t i = 0; i < num_keys; ++i) {
-    seeds[i] = absl::MakeUint128(keys[i].seed().high(), keys[i].seed().low());
-    control_bits[i] = keys[i].party();
-  }
-
-  int start_level = 0;
-  int stop_level = hierarchy_to_tree_[0];
-  for (int hierarchy_level = 0; hierarchy_level < num_hierarchy_levels;
-       ++hierarchy_level) {
-    if (hierarchy_level > 0) {
-      start_level = stop_level;
-      stop_level = hierarchy_to_tree_[hierarchy_level];
-    }
-
-    // Compute index shifts for the current level.
-    const int domain_index_rightshift =
-        evaluation_points_rightshift + parameters_.back().log_domain_size() -
-        parameters_[hierarchy_level].log_domain_size();
-    const int tree_index_rightshift = evaluation_points_rightshift +
-                                      parameters_.back().log_domain_size() -
-                                      hierarchy_to_tree_[hierarchy_level];
-
-    int num_tree_levels = stop_level - start_level;
-    if (num_tree_levels > 0) {
-      correction_seeds =
-          hwy::AllocateAligned<absl::uint128>(num_tree_levels * num_keys);
-      if (correction_seeds == nullptr) {
-        return absl::ResourceExhaustedError("Memory allocation error");
-      }
-      correction_control_bits_left.resize(num_tree_levels * num_keys);
-      correction_control_bits_right.resize(num_tree_levels * num_keys);
-      for (int i = 0; i < num_tree_levels; ++i) {
-        for (int64_t j = 0; j < num_keys; ++j) {
-          const int64_t index = i * num_keys + j;
-          const CorrectionWord& cw = keys[j].correction_words(start_level + i);
-          correction_seeds[index] =
-              absl::MakeUint128(cw.seed().high(), cw.seed().low());
-          correction_control_bits_left[index] = cw.control_left();
-          correction_control_bits_right[index] = cw.control_right();
-        }
-      }
-
-      // Evaluate the current hierarchy level for all keys.
-      absl::Status status = dpf_internal::EvaluateSeeds(
-          seeds.size(), num_tree_levels, num_tree_levels * num_keys,
-          seeds.data(), control_bits.data(), evaluation_points.data(),
-          tree_index_rightshift, correction_seeds.get(),
-          correction_control_bits_left.data(),
-          correction_control_bits_right.data(), prg_left_, prg_right_,
-          seeds.data(), control_bits.data());
-      if (!status.ok()) {
-        return status;
-      }
-    }
-
-    // Hash `seeds`.
-    absl::StatusOr<hwy::AlignedFreeUniquePtr<absl::uint128[]>>
-        hashed_expansion = HashExpandedSeeds(hierarchy_level, seeds);
-    if (!hashed_expansion.ok()) {
-      return hashed_expansion.status();
-    }
-
-    // Compute value correction for the current level.
-    constexpr int elements_per_block = dpf_internal::ElementsPerBlock<T>();
-    const int blocks_needed = blocks_needed_[hierarchy_level];
-    for (int64_t i = 0; i < num_keys; ++i) {
-      std::array<T, elements_per_block> current_elements =
-          dpf_internal::ConvertBytesToArrayOf<T>(absl::string_view(
-              reinterpret_cast<const char*>(hashed_expansion->get() +
-                                            i * blocks_needed),
-              blocks_needed * sizeof(absl::uint128)));
-      absl::StatusOr<std::array<T, elements_per_block>> correction_ints =
-          GetValueCorrectionAsArray<T>(keys[i], hierarchy_level);
-      if (!correction_ints.ok()) {
-        return correction_ints.status();
-      }
-      int block_index = 0;
-      if (elements_per_block > 1 && domain_index_rightshift < 128) {
-        block_index = DomainToBlockIndex(
-            evaluation_points[i] >> domain_index_rightshift, hierarchy_level);
-      }
-      values[i] = current_elements[block_index];
-      if (control_bits[i]) {
-        values[i] += (*correction_ints)[block_index];
-      }
-      if (keys[i].party() == 1) {
-        values[i] = -values[i];
-      }
-    }
-
-    // Call the callback with the values at the current level, and return if the
-    // result is `false`.
-    if (!op(values)) {
-      break;
-    }
-  }
-  return absl::OkStatus();
-}
-
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_DISTRIBUTED_POINT_FUNCTION_H_
diff --git a/third_party/distributed_point_functions/code/dpf/distributed_point_function.proto b/third_party/distributed_point_functions/code/dpf/distributed_point_function.proto
deleted file mode 100644
index 058d759..0000000
--- a/third_party/distributed_point_functions/code/dpf/distributed_point_function.proto
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-syntax = "proto3";
-
-package distributed_point_functions;
-
-// For faster allocations of sub-messages.
-option cc_enable_arenas = true;
-
-// Describes the type of a single DPF output value. Any additional types added
-// here should also be supported in internal/value_type_helpers.h.
-// LINT.IfChange
-message ValueType {
-  // Describes an integer modulo 2^l. Maps to the C++ types `uint8_t`,
-  // `uint16_t`, `uint32_t`, `uint64_t`, and `absl::uint128`.
-  message Integer {
-    // Number of bits per integer. Must be a power of 2 and at most 128.
-    int32 bitsize = 1;
-  }
-
-  // Describes a tuple of value types.
-  message Tuple {
-    repeated ValueType elements = 1;
-  }
-
-  // Describes an integer ring modulo `modulus`.
-  message IntModN {
-    // The underlying integer type used to represent elements in the ring.
-    Integer base_integer = 1;
-    // The modulus.
-    Value.Integer modulus = 2;
-  }
-
-  oneof type {
-    // A single integer modulo 2^l.
-    Integer integer = 1;
-    // A tuple of values.
-    Tuple tuple = 2;
-    // A integer with custom modulus.
-    IntModN int_mod_n = 3;
-    // An XOR-wrapped integer. Corresponds to the XorWrapper C++ class.
-    Integer xor_wrapper = 4;
-  }
-  // Do not add fields outside of the `oneof` above, to ensure that messages
-  // with known ValueTypes are serialized deterministically. See the
-  // documentation of `value_correction_functions_` in
-  // distributed_point_function.h for details.
-}
-
-// Used to correct output values to the desired DPF magnitude. Holds the values
-// corresponding to the types defined in `ValueType`.
-message Value {
-  message Integer {
-    oneof value {
-      // Any value up to 64 bits.
-      uint64 value_uint64 = 1;
-      // 128-bit values.
-      Block value_uint128 = 2;
-    }
-  }
-
-  message Tuple {
-    repeated Value elements = 1;
-  }
-
-  oneof value {
-    Integer integer = 1;
-    Tuple tuple = 2;
-    Integer int_mod_n =
-        3;  // The value of an IntModN is represented by its base_integer type.
-    Integer xor_wrapper = 4;
-  }
-}
-// LINT.ThenChange(
-//   internal/value_type_helpers.h,
-//   internal/value_type_helpers.cc
-// )
-
-// Parameters of a single hierarchy level of a distributed point function (DPF).
-message DpfParameters {
-  reserved 2;
-  // Base-2 logarithm of the number of elements.
-  int32 log_domain_size = 1;
-  // Describes the type of output values at this hierarchy level.
-  ValueType value_type = 3;
-  // The negative logarithm of the total variation distance from uniform that an
-  // evaluation at a *single point* at this hierarchy level is allowed to have.
-  // The correct value for this parameter depends on the maximum number of
-  // points at which this hierarchy level is evaluated. It should be at least 40
-  // + log2(number_of_evaluation_points). Defaults to
-  // ProtoValidator::kDefaultSecurityParameter + log_domain_size.
-  double security_parameter = 4;
-}
-
-// A single 128-bit AES block.
-message Block {
-  uint64 high = 1;
-  uint64 low = 2;
-}
-
-// A correction word used to evaluate a single layer in the DPF evaluation tree.
-message CorrectionWord {
-  // Block used to correct the new seeds after PRG evaluation.
-  Block seed = 1;
-  // Correction bits for the left and right control bits.
-  bool control_left = 2;
-  bool control_right = 3;
-  // Reserved for deprecated value correction field.
-  reserved 4;
-  // Used to correct the output value at the previous tree layer. Only included
-  // if the previous tree layer is an output layer. Repeated to capture the case
-  // where multiple correction values are needed due to packing.
-  repeated Value value_correction = 5;
-}
-
-// A key of a distributed point function (DPF).
-message DpfKey {
-  // Initial seed at the first level.
-  Block seed = 1;
-  // Correction words for each level after expansion.
-  repeated CorrectionWord correction_words = 2;
-  // Party this DpfKey belongs to (0 or 1).
-  int32 party = 3;
-  // Deprecated last level value correction.
-  reserved 4;
-  // Output correction for the last level of the evaluation tree.
-  repeated Value last_level_value_correction = 5;
-}
-
-// Maps a single prefix of a DPF index to a PRG seed. Used to store partial
-// evaluation state between hierarchy levels in `EvaluationContext`
-message PartialEvaluation {
-  // Prefix in the FSS evaluation tree. Does not necessarily coincide with the
-  // corresponding prefix of the output domain at this hierarchy level.
-  Block prefix = 1;
-  // Seed for the next evaluation.
-  Block seed = 2;
-  // Control bit for the correction in the next evaluation.
-  bool control_bit = 3;
-}
-
-// An EvaluationContext holds the state of a partially evaluated incremental
-// DPF.
-message EvaluationContext {
-  // The parameters of the DPF being evaluated. One set of parameters for each
-  // hierarchy level of the incremental DPF.
-  repeated DpfParameters parameters = 1;
-  // The DPF key being evaluated.
-  DpfKey key = 2;
-  // The hierarchy level that this EvaluationContext was last evaluated on.
-  int32 previous_hierarchy_level = 3;
-  // Maps prefixes from an earlier hierarchy level to PRG seeds, which are used
-  // to continue the evaluation under each prefix. Uses a repeated message field
-  // since Protobuf doesn't allow messages (such as `Block`) as map keys.
-  repeated PartialEvaluation partial_evaluations = 4;
-  // The hierarchy level `partial_evaluations` corresponds to. Ignored when
-  // `partial_evaluations` is empty.
-  int32 partial_evaluations_level = 5;
-}
diff --git a/third_party/distributed_point_functions/code/dpf/distributed_point_function_benchmark.cc b/third_party/distributed_point_functions/code/dpf/distributed_point_function_benchmark.cc
deleted file mode 100644
index 0deabc3..0000000
--- a/third_party/distributed_point_functions/code/dpf/distributed_point_function_benchmark.cc
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include <algorithm>
-#include <cmath>
-#include <memory>
-#include <numeric>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "absl/container/btree_set.h"
-#include "absl/log/absl_check.h"
-#include "absl/numeric/int128.h"
-#include "absl/random/random.h"
-#include "absl/random/uniform_int_distribution.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/types/span.h"
-#include "benchmark/benchmark.h"
-#include "dpf/distributed_point_function.h"
-#include "google/protobuf/arena.h"
-#include "hwy/aligned_allocator.h"
-
-namespace distributed_point_functions {
-namespace {
-
-// Benchmarks a regular DPF evaluation. Expects the first range argument to
-// specify the output log domain size.
-template <typename T>
-void BM_EvaluateRegularDpf(benchmark::State& state) {
-  DpfParameters parameters;
-  parameters.set_log_domain_size(state.range(0));
-  *(parameters.mutable_value_type()) = ToValueType<T>();
-  std::unique_ptr<DistributedPointFunction> dpf =
-      DistributedPointFunction::Create(parameters).value();
-  absl::uint128 alpha = 0;
-  T beta{};
-  ABSL_CHECK(dpf->RegisterValueType<T>().ok());
-  std::pair<DpfKey, DpfKey> keys = dpf->GenerateKeys(alpha, beta).value();
-  EvaluationContext ctx_0 = dpf->CreateEvaluationContext(keys.first).value();
-  for (auto s : state) {
-    google::protobuf::Arena arena;
-    EvaluationContext* ctx =
-        google::protobuf::Arena::CreateMessage<EvaluationContext>(&arena);
-    *ctx = ctx_0;
-    std::vector<T> result = dpf->EvaluateNext<T>({}, *ctx).value();
-    benchmark::DoNotOptimize(result);
-  }
-}
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, uint8_t)->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, uint16_t)->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, uint32_t)->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, uint64_t)->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, absl::uint128)->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, Tuple<uint32_t, uint32_t>)
-    ->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, Tuple<uint32_t, uint64_t>)
-    ->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, Tuple<uint64_t, uint64_t>)
-    ->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf,
-                   Tuple<uint32_t, uint32_t, uint32_t, uint32_t>)
-    ->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf,
-                   Tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint32_t>)
-    ->DenseRange(12, 24, 2);
-BENCHMARK_TEMPLATE(
-    BM_EvaluateRegularDpf,
-    Tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t>)
-    ->DenseRange(12, 24, 2);
-
-using MyIntModN = IntModN<uint32_t, 4294967291u>;  // 2**32 - 5.
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf,
-                   Tuple<MyIntModN, MyIntModN, MyIntModN, MyIntModN, MyIntModN>)
-    ->DenseRange(12, 24, 2);
-using MyIntModN64 = IntModN<uint64_t, 18446744073709551557ull>;  // 2**64 - 59.
-BENCHMARK_TEMPLATE(
-    BM_EvaluateRegularDpf,
-    Tuple<MyIntModN64, MyIntModN64, MyIntModN64, MyIntModN64, MyIntModN64>)
-    ->DenseRange(12, 22, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateRegularDpf, XorWrapper<absl::uint128>)
-    ->DenseRange(1, 24, 1);
-
-// Benchmarks full evaluation of all hierarchy levels. Expects the first range
-// argument to specify the number of iterations. The output domain size is fixed
-// to 2**20.
-template <typename T>
-void BM_EvaluateHierarchicalFull(benchmark::State& state) {
-  // Set up DPF with the given parameters.
-  const int kMaxLogDomainSize = 20;
-  int num_hierarchy_levels = state.range(0);
-  std::vector<DpfParameters> parameters(num_hierarchy_levels);
-  for (int i = 0; i < num_hierarchy_levels; ++i) {
-    parameters[i].set_log_domain_size(static_cast<int>(
-        static_cast<double>(i + 1) / num_hierarchy_levels * kMaxLogDomainSize));
-    parameters[i].mutable_value_type()->mutable_integer()->set_bitsize(
-        sizeof(T) * 8);
-  }
-  std::unique_ptr<DistributedPointFunction> dpf =
-      DistributedPointFunction::CreateIncremental(parameters).value();
-
-  // Generate keys.
-  absl::uint128 alpha = 12345;
-  std::vector<absl::uint128> beta(num_hierarchy_levels);
-  for (int i = 0; i < num_hierarchy_levels; ++i) {
-    beta[i] = i;
-  }
-  std::pair<DpfKey, DpfKey> keys =
-      dpf->GenerateKeysIncremental(alpha, beta).value();
-
-  // Set up evaluation context and evaluation prefixes for each level.
-  EvaluationContext ctx_0 = dpf->CreateEvaluationContext(keys.first).value();
-  std::vector<std::vector<absl::uint128>> prefixes(num_hierarchy_levels);
-  for (int i = 1; i < num_hierarchy_levels; ++i) {
-    prefixes[i].resize(1 << parameters[i - 1].log_domain_size());
-    std::iota(prefixes[i].begin(), prefixes[i].end(), absl::uint128{0});
-  }
-
-  // Run hierarchical evaluation.
-  for (auto s : state) {
-    google::protobuf::Arena arena;
-    EvaluationContext* ctx =
-        google::protobuf::Arena::CreateMessage<EvaluationContext>(&arena);
-    *ctx = ctx_0;
-    for (int i = 0; i < num_hierarchy_levels; ++i) {
-      std::vector<T> result = dpf->EvaluateNext<T>(prefixes[i], *ctx).value();
-      benchmark::DoNotOptimize(result);
-    }
-    benchmark::DoNotOptimize(*ctx);
-  }
-}
-BENCHMARK_TEMPLATE(BM_EvaluateHierarchicalFull, uint8_t)->DenseRange(1, 16, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateHierarchicalFull, uint16_t)->DenseRange(1, 16, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateHierarchicalFull, uint32_t)->DenseRange(1, 16, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateHierarchicalFull, uint64_t)->DenseRange(1, 16, 2);
-BENCHMARK_TEMPLATE(BM_EvaluateHierarchicalFull, absl::uint128)
-    ->DenseRange(1, 16, 2);
-
-// Generates random prefixes for the given set of `parameters`. Generates
-// `num_nonzeros[i]` prefixes at hierarchy level `i`.
-std::vector<std::vector<absl::uint128>> GenerateRandomPrefixes(
-    absl::Span<const DpfParameters> parameters,
-    absl::Span<const int> num_nonzeros) {
-  auto num_hierarchy_levels = static_cast<int>(parameters.size());
-  std::vector<std::vector<absl::uint128>> prefixes(parameters.size());
-
-  absl::BitGen rng;
-  absl::uniform_int_distribution<uint32_t> dist_index, dist_value;
-  for (int i = 0; i < num_hierarchy_levels; ++i) {
-    if (i > 0) {  // prefixes must be empty for the first level.
-      prefixes[i] = std::vector<absl::uint128>(num_nonzeros[i - 1]);
-      absl::uint128 prefix = 0;
-      // Difference between the previous domain size and the one before that.
-      // This is the amount of bits we have to shift prefixes from the previous
-      // level to append the current level.
-      int previous_domain_size_difference = parameters[i - 1].log_domain_size();
-      if (i > 1) {
-        previous_domain_size_difference -= parameters[i - 2].log_domain_size();
-      }
-      dist_value = absl::uniform_int_distribution<uint32_t>(
-          0, (1 << previous_domain_size_difference) - 1);
-      if (i > 1) {
-        dist_index = absl::uniform_int_distribution<uint32_t>(
-            0, prefixes[i - 1].size() - 1);
-      }
-      for (int j = 0; i > 0 && j < num_nonzeros[i - 1]; ++j) {
-        if (i > 1) {
-          // Choose a random prefix from the previous level to extend.
-          prefix = prefixes[i - 1][dist_index(rng)]
-                   << previous_domain_size_difference;
-        }
-        prefixes[i][j] = prefix | dist_value(rng);
-      }
-    }
-    std::sort(prefixes[i].begin(), prefixes[i].end());
-  }
-  return prefixes;
-}
-
-// Benchmark the example used here:
-// https://github.com/abetterinternet/prio-documents/issues/18#issuecomment-801248636
-void BM_IsrgExampleHierarchy(benchmark::State& state) {
-  const int kNumHierarchyLevels = 2;
-  std::vector<DpfParameters> parameters(kNumHierarchyLevels);
-  std::vector<int> num_nonzeros(kNumHierarchyLevels - 1);
-
-  parameters[0].set_log_domain_size(12);
-  parameters[0].mutable_value_type()->mutable_integer()->set_bitsize(32);
-  num_nonzeros[0] = 32;
-
-  parameters[1].set_log_domain_size(25);
-  parameters[1].mutable_value_type()->mutable_integer()->set_bitsize(32);
-
-  std::unique_ptr<DistributedPointFunction> dpf =
-      DistributedPointFunction::CreateIncremental(parameters).value();
-
-  // Create DPF keys.
-  absl::uint128 alpha = 1234567;
-  std::vector<absl::uint128> beta(kNumHierarchyLevels, 1);
-  std::pair<DpfKey, DpfKey> keys =
-      dpf->GenerateKeysIncremental(alpha, beta).value();
-
-  // Generate prefixes for evaluation with the appropriate number of nonzeros.
-  std::vector<std::vector<absl::uint128>> prefixes =
-      GenerateRandomPrefixes(parameters, num_nonzeros);
-
-  // Run hierarchical evaluation.
-  EvaluationContext ctx_0 = dpf->CreateEvaluationContext(keys.first).value();
-  for (auto s : state) {
-    google::protobuf::Arena arena;
-    EvaluationContext* ctx =
-        google::protobuf::Arena::CreateMessage<EvaluationContext>(&arena);
-    *ctx = ctx_0;
-    for (int i = 0; i < kNumHierarchyLevels; ++i) {
-      std::vector<uint32_t> result =
-          dpf->EvaluateNext<uint32_t>(prefixes[i], *ctx).value();
-      benchmark::DoNotOptimize(result);
-    }
-    benchmark::DoNotOptimize(*ctx);
-  }
-}
-BENCHMARK(BM_IsrgExampleHierarchy);
-
-// Benchmarks the time needed to generate keys. The log domain size is read from
-// the first range argument. If `direct_evaluation` is true, a single hierarchy
-// level will be used. Otherwise, the number of hierarchy levels is eqaual to
-// the log domain size (i.e., one level per bit in the domain).
-template <bool direct_evaluation>
-void BM_KeyGeneration(benchmark::State& state) {
-  int last_level_log_domain_size = state.range(0);
-  std::vector<DpfParameters> parameters(1);
-  if (direct_evaluation) {
-    parameters[0].set_log_domain_size(last_level_log_domain_size);
-    parameters[0].mutable_value_type()->mutable_integer()->set_bitsize(32);
-  } else {
-    parameters.resize(last_level_log_domain_size);
-    for (int i = 0; i < last_level_log_domain_size; ++i) {
-      parameters[i].set_log_domain_size(i + 1);
-      parameters[i].mutable_value_type()->mutable_integer()->set_bitsize(32);
-    }
-  }
-  std::unique_ptr<DistributedPointFunction> dpf =
-      *(DistributedPointFunction::CreateIncremental(parameters));
-
-  std::vector<absl::uint128> beta(parameters.size(), 23);
-  absl::BitGen rng;
-  absl::uniform_int_distribution<uint64_t> dist;
-  absl::uint128 alpha_mask =
-      (absl::uint128{1} << parameters.back().log_domain_size()) - 1;
-  std::pair<DpfKey, DpfKey> result;
-  for (auto s : state) {
-    // Sample alpha randomly, so we don't rely on any structure here.
-    absl::uint128 alpha = absl::MakeUint128(dist(rng), dist(rng)) & alpha_mask;
-    result = dpf->GenerateKeysIncremental(alpha, beta).value();
-    benchmark::DoNotOptimize(result);
-  }
-  state.SetLabel(absl::StrCat("key_size: ", result.first.ByteSizeLong()));
-}
-BENCHMARK_TEMPLATE(BM_KeyGeneration, true)->RangeMultiplier(2)->Range(1, 128);
-BENCHMARK_TEMPLATE(BM_KeyGeneration, false)->RangeMultiplier(2)->Range(1, 128);
-
-// Generates `num_nonzeros` uniform indices, and computes their prefixes for
-// each hierarchy level in `parameters`.
-absl::StatusOr<std::vector<std::vector<absl::uint128>>> GenerateUniformPrefixes(
-    absl::Span<const DpfParameters> parameters, int num_nonzeros) {
-  int num_parameters = static_cast<int>(parameters.size());
-  std::vector<std::vector<absl::uint128>> result(num_parameters);
-  if (num_parameters <= 1) {
-    return result;
-  }
-  if (std::log2(num_nonzeros) >
-      parameters[num_parameters - 2].log_domain_size()) {
-    return absl::InvalidArgumentError("num_nonzeros out of range");
-  }
-
-  absl::BitGen rng;
-  absl::uniform_int_distribution<uint64_t> dist;
-
-  // Generate prefixes for last level.
-  absl::btree_set<absl::uint128> last_level_prefixes;
-  while (static_cast<int>(last_level_prefixes.size()) < num_nonzeros) {
-    absl::uint128 mask = (absl::uint128{1} << parameters[parameters.size() - 2]
-                                                  .log_domain_size()) -
-                         1;
-    last_level_prefixes.insert(absl::MakeUint128(dist(rng), dist(rng)) & mask);
-  }
-  result.back() = std::vector<absl::uint128>(last_level_prefixes.begin(),
-                                             last_level_prefixes.end());
-
-  // Iterate backwards through previous levels, computing prefixes by
-  // appropriately shifting the ones from higher levels.
-  for (int i = static_cast<int>(result.size()) - 1; i > 1; --i) {
-    absl::btree_set<absl::uint128> current_level_prefixes;
-    for (const auto& x : result[i]) {
-      absl::uint128 prefix = x >> (parameters[i - 1].log_domain_size() -
-                                   parameters[i - 2].log_domain_size());
-      current_level_prefixes.insert(prefix);
-    }
-    result[i - 1] = std::vector<absl::uint128>(current_level_prefixes.begin(),
-                                               current_level_prefixes.end());
-  }
-  return result;
-}
-
-// Benchmark a bit-wise hierarchy as in https://github.com/henrycg/heavyhitters.
-// Uses a variable domain size with 10000 uniform non-zeros at the last
-// hierarchy level, and evaluate at every bit.
-void BM_HeavyHitters(benchmark::State& state) {
-  int num_parameters = state.range(0);
-  const int kNumNonzeros = 10000;
-  std::vector<DpfParameters> parameters(num_parameters);
-  for (int i = 0; i < num_parameters; ++i) {
-    parameters[i].set_log_domain_size(i + 1);
-    parameters[i].mutable_value_type()->mutable_integer()->set_bitsize(64);
-  }
-  std::unique_ptr<DistributedPointFunction> dpf =
-      *(DistributedPointFunction::CreateIncremental(parameters));
-
-  std::vector<absl::uint128> beta(num_parameters, 23);
-  absl::uint128 alpha = 42;
-  DpfKey key = dpf->GenerateKeysIncremental(alpha, beta).value().first;
-  std::vector<std::vector<absl::uint128>> prefixes =
-      GenerateUniformPrefixes(parameters, kNumNonzeros).value();
-
-  // Run hierarchical evaluation.
-  EvaluationContext ctx_0 = dpf->CreateEvaluationContext(key).value();
-  for (auto s : state) {
-    google::protobuf::Arena arena;
-    EvaluationContext* ctx =
-        google::protobuf::Arena::CreateMessage<EvaluationContext>(&arena);
-    *ctx = ctx_0;
-    for (int i = 0; i < num_parameters; ++i) {
-      std::vector<uint64_t> result =
-          dpf->EvaluateNext<uint64_t>(prefixes[i], *ctx).value();
-      benchmark::DoNotOptimize(result);
-    }
-    benchmark::DoNotOptimize(*ctx);
-  }
-}
-BENCHMARK(BM_HeavyHitters)->RangeMultiplier(2)->Range(16, 128);
-
-// Benchmark batch evaluation of multiple DPF keys at a single point each.
-// The first argument specifies the number of keys, the second the domain size,
-// and the last the number of evaluation points per key.
-template <typename T>
-void BM_BatchEvaluation(benchmark::State& state) {
-  const int num_keys = state.range(0);
-  const int evaluation_points_per_key = state.range(1);
-  constexpr int kLogDomainSize = 63 - 7;
-
-  absl::uint128 domain_mask = absl::Uint128Max();
-  if (kLogDomainSize < 128) {
-    domain_mask = (absl::uint128{1} << kLogDomainSize) - 1;
-  }
-
-  DpfParameters parameters;
-  parameters.set_log_domain_size(kLogDomainSize);
-  *(parameters.mutable_value_type()) = ToValueType<T>();
-
-  std::unique_ptr<DistributedPointFunction> dpf =
-      DistributedPointFunction::Create(parameters).value();
-
-  absl::BitGen rng;
-  google::protobuf::Arena arena;
-  std::vector<const DpfKey*> key_pointers(num_keys * evaluation_points_per_key);
-  auto evaluation_points =
-      hwy::AllocateAligned<absl::uint128>(num_keys * evaluation_points_per_key);
-  ABSL_CHECK(evaluation_points != nullptr);
-  for (int i = 0; i < num_keys; ++i) {
-    absl::uint128 alpha = absl::MakeUint128(absl::Uniform<uint64_t>(rng),
-                                            absl::Uniform<uint64_t>(rng)) &
-                          domain_mask;
-    T beta{};
-    DpfKey* key = google::protobuf::Arena::CreateMessage<DpfKey>(&arena);
-    *key = dpf->GenerateKeys(alpha, beta).value().first;
-
-    for (int j = 0; j < evaluation_points_per_key; ++j) {
-      key_pointers[i * evaluation_points_per_key + j] = key;
-      evaluation_points[i * evaluation_points_per_key + j] =
-          absl::MakeUint128(absl::Uniform<uint64_t>(rng),
-                            absl::Uniform<uint64_t>(rng)) &
-          domain_mask;
-    }
-  }
-
-  for (auto s : state) {
-    for (int i = 0; i < num_keys; ++i) {
-      std::vector<T> result =
-          dpf->EvaluateAt<T>(
-                 *(key_pointers[i]), 0,
-                 absl::MakeConstSpan(
-                     evaluation_points.get() + i * evaluation_points_per_key,
-                     evaluation_points_per_key))
-              .value();
-      benchmark::DoNotOptimize(result);
-    }
-  }
-}
-BENCHMARK_TEMPLATE(BM_BatchEvaluation, XorWrapper<absl::uint128>)
-    ->ArgPair(1, 400000)
-    ->ArgPair(10, 40000)
-    ->ArgPair(100, 4000);
-
-}  // namespace
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/distributed_point_function_test.cc b/third_party/distributed_point_functions/code/dpf/distributed_point_function_test.cc
deleted file mode 100644
index c651818b..0000000
--- a/third_party/distributed_point_functions/code/dpf/distributed_point_function_test.cc
+++ /dev/null
@@ -1,1189 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/distributed_point_function.h"
-
-#include <memory>
-#include <ostream>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "absl/algorithm/container.h"
-#include "absl/base/config.h"
-#include "absl/numeric/int128.h"
-#include "absl/random/random.h"
-#include "absl/random/uniform_int_distribution.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_format.h"
-#include "absl/strings/str_join.h"
-#include "absl/types/span.h"
-#include "absl/utility/utility.h"
-#include "dpf/distributed_point_function.pb.h"
-#include "dpf/internal/proto_validator.h"
-#include "dpf/internal/status_matchers.h"
-#include "dpf/xor_wrapper.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace {
-
-using dpf_internal::IsOk;
-using dpf_internal::IsOkAndHolds;
-using dpf_internal::StatusIs;
-using ::testing::HasSubstr;
-using ::testing::Ne;
-using ::testing::StartsWith;
-
-TEST(DistributedPointFunction, TestCreate) {
-  for (int log_domain_size = 0; log_domain_size <= 128; ++log_domain_size) {
-    for (int element_bitsize = 1; element_bitsize <= 128;
-         element_bitsize *= 2) {
-      DpfParameters parameters;
-
-      parameters.set_log_domain_size(log_domain_size);
-      parameters.mutable_value_type()->mutable_integer()->set_bitsize(
-          element_bitsize);
-
-      EXPECT_THAT(DistributedPointFunction::Create(parameters),
-                  IsOkAndHolds(Ne(nullptr)))
-          << "log_domain_size=" << log_domain_size
-          << " element_bitsize=" << element_bitsize;
-    }
-  }
-}
-
-TEST(DistributedPointFunction, TestCreateIncrementalLargeDomain) {
-  std::vector<DpfParameters> parameters(2);
-  parameters[0].mutable_value_type()->mutable_integer()->set_bitsize(128);
-  parameters[1].mutable_value_type()->mutable_integer()->set_bitsize(128);
-
-  // Test that creating an incremental DPF with a large total domain size works.
-  parameters[0].set_log_domain_size(10);
-  parameters[1].set_log_domain_size(100);
-
-  EXPECT_THAT(DistributedPointFunction::CreateIncremental(parameters),
-              IsOkAndHolds(Ne(nullptr)));
-}
-
-TEST(DistributedPointFunction, CreateFailsForTupleTypesWithDifferentIntModN) {
-  DpfParameters parameters;
-  parameters.set_log_domain_size(10);
-  *(parameters.mutable_value_type()) =
-      ToValueType<Tuple<IntModN<uint32_t, 3>, IntModN<uint64_t, 4>>>();
-
-  EXPECT_THAT(
-      DistributedPointFunction::Create(parameters),
-      StatusIs(absl::StatusCode::kUnimplemented,
-               "All elements of type IntModN in a tuple must be the same"));
-}
-
-TEST(DistributedPointFunction, CreateFailsForMissingValueType) {
-  DpfParameters parameters;
-  parameters.set_log_domain_size(10);
-
-  EXPECT_THAT(
-      DistributedPointFunction::Create(parameters),
-      StatusIs(absl::StatusCode::kInvalidArgument, "`value_type` is required"));
-}
-
-TEST(DistributedPointFunction, CreateFailsForInvalidValueType) {
-  DpfParameters parameters;
-  parameters.set_log_domain_size(10);
-  *(parameters.mutable_value_type()) = ValueType{};
-
-  EXPECT_THAT(DistributedPointFunction::Create(parameters),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       StartsWith("ValidateValueType: Unsupported ValueType")));
-}
-
-TEST(DistributedPointFunction, TestGenerateKeysIncrementalVariadicTemplate) {
-  std::vector<DpfParameters> parameters(2);
-
-  parameters[0].set_log_domain_size(10);
-  parameters[1].set_log_domain_size(20);
-  *(parameters[0].mutable_value_type()) = ToValueType<uint16_t>();
-  *(parameters[1].mutable_value_type()) =
-      ToValueType<Tuple<uint32_t, uint64_t>>();
-  DPF_ASSERT_OK_AND_ASSIGN(
-      std::unique_ptr<DistributedPointFunction> dpf,
-      DistributedPointFunction::CreateIncremental(parameters));
-
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> keys = dpf->GenerateKeysIncremental(
-      23, uint16_t{42}, Tuple<uint32_t, uint64_t>{123, 456});
-  EXPECT_THAT(keys, IsOk());
-}
-
-TEST(DistributedPointFunction, TestGenerateKeysIncrementalTemplate) {
-  std::vector<DpfParameters> parameters(2);
-  using T = XorWrapper<absl::uint128>;
-
-  parameters[0].set_log_domain_size(10);
-  parameters[1].set_log_domain_size(20);
-  *(parameters[0].mutable_value_type()) = ToValueType<T>();
-  *(parameters[1].mutable_value_type()) = ToValueType<T>();
-  DPF_ASSERT_OK_AND_ASSIGN(
-      std::unique_ptr<DistributedPointFunction> dpf,
-      DistributedPointFunction::CreateIncremental(parameters));
-
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> keys =
-      dpf->GenerateKeysIncremental(23, T{42}, T{123});
-  EXPECT_THAT(keys, IsOk());
-}
-
-TEST(DistributedPointFunction, KeyGenerationFailsIfValueTypeNotRegistered) {
-  DpfParameters parameters;
-  parameters.set_log_domain_size(10);
-  parameters.mutable_value_type()
-      ->mutable_tuple()
-      ->add_elements()
-      ->mutable_integer()
-      ->set_bitsize(32);
-  DPF_ASSERT_OK_AND_ASSIGN(std::unique_ptr<DistributedPointFunction> dpf,
-                           DistributedPointFunction::Create(parameters));
-
-  // Tuple<uint32_t> should not be registered by default.
-  absl::uint128 alpha = 23;
-  Value beta;
-  beta.mutable_tuple()->add_elements()->mutable_integer()->set_value_uint64(42);
-
-  EXPECT_THAT(dpf->GenerateKeys(alpha, beta),
-              StatusIs(absl::StatusCode::kFailedPrecondition,
-                       StartsWith("No value correction function known")));
-}
-
-TEST(DistributedPointFunction, EvaluationFailsIfDomainSizeGapTooLarge) {
-  std::vector<DpfParameters> parameters(2);
-  parameters[0].mutable_value_type()->mutable_integer()->set_bitsize(128);
-  parameters[1].mutable_value_type()->mutable_integer()->set_bitsize(128);
-  parameters[0].set_log_domain_size(10);
-  parameters[1].set_log_domain_size(100);
-  DPF_ASSERT_OK_AND_ASSIGN(
-      std::unique_ptr<DistributedPointFunction> dpf,
-      DistributedPointFunction::CreateIncremental(parameters));
-
-  std::pair<DpfKey, DpfKey> keys;
-  DPF_ASSERT_OK_AND_ASSIGN(keys, dpf->GenerateKeysIncremental(123, 456u, 789u));
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf->CreateEvaluationContext(keys.first));
-
-  EXPECT_THAT(
-      dpf->EvaluateUntil<absl::uint128>(1, {}, ctx),
-      StatusIs(absl::StatusCode::kInvalidArgument, StartsWith("Domain size")));
-}
-
-TEST(DistributedPointFunction, EvaluationFailsIfOutputSizeTooLarge) {
-  std::vector<DpfParameters> parameters(2);
-  parameters[0].mutable_value_type()->mutable_integer()->set_bitsize(128);
-  parameters[1].mutable_value_type()->mutable_integer()->set_bitsize(128);
-  parameters[0].set_log_domain_size(10);
-  parameters[1].set_log_domain_size(72);
-  DPF_ASSERT_OK_AND_ASSIGN(
-      std::unique_ptr<DistributedPointFunction> dpf,
-      DistributedPointFunction::CreateIncremental(parameters));
-
-  std::pair<DpfKey, DpfKey> keys;
-  DPF_ASSERT_OK_AND_ASSIGN(keys, dpf->GenerateKeysIncremental(123, 456u, 789u));
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf->CreateEvaluationContext(keys.first));
-
-  // Evaluate on 2**2 prefixes, bringing the output size to 2**(72-10+2) =
-  // 2**64, which overflows an int64_t. Assumes a size_t is at most 64 bits.
-  std::vector<absl::uint128> prefixes = {123, 456, 789, 1011};
-  DPF_ASSERT_OK(dpf->EvaluateUntil<absl::uint128>(0, {}, ctx));
-  EXPECT_THAT(
-      dpf->EvaluateUntil<absl::uint128>(1, prefixes, ctx),
-      StatusIs(absl::StatusCode::kInvalidArgument, StartsWith("Output size")));
-}
-
-TEST(DistributedPointFunction, TestSinglePointPartialEvaluation) {
-  // Two hierarchy levels: The first will be evaluated with only a single
-  // prefix, the second will be fully evaluated.
-  std::vector<DpfParameters> parameters(2);
-  parameters[0].set_log_domain_size(108);
-  parameters[0].mutable_value_type()->mutable_integer()->set_bitsize(32);
-  parameters[1].set_log_domain_size(128);
-  parameters[1].mutable_value_type()->mutable_integer()->set_bitsize(32);
-
-  DPF_ASSERT_OK_AND_ASSIGN(
-      auto dpf, DistributedPointFunction::CreateIncremental(parameters));
-  absl::uint128 prefix = 0xdeadbeef;
-  absl::uint128 suffix = 23;
-  absl::uint128 alpha = (prefix << 20) + suffix;
-  uint32_t beta = 42;
-  DpfKey key_a, key_b;
-  DPF_ASSERT_OK_AND_ASSIGN(std::tie(key_a, key_b),
-                           dpf->GenerateKeysIncremental(alpha, {beta, beta}));
-
-  // First evaluate directly up to `prefix`
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx_a,
-                           dpf->CreateEvaluationContext(key_a));
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx_b,
-                           dpf->CreateEvaluationContext(key_b));
-  std::vector<uint32_t> result_a, result_b;
-  DPF_ASSERT_OK_AND_ASSIGN(result_a,
-                           dpf->EvaluateAt<uint32_t>(0, {prefix}, ctx_a));
-  DPF_ASSERT_OK_AND_ASSIGN(result_b,
-                           dpf->EvaluateAt<uint32_t>(0, {prefix}, ctx_b));
-  EXPECT_EQ(result_a[0] + result_b[0], beta);
-
-  // Now fully evaluate the second level.
-  DPF_ASSERT_OK_AND_ASSIGN(result_a,
-                           dpf->EvaluateUntil<uint32_t>(1, {prefix}, ctx_a));
-  DPF_ASSERT_OK_AND_ASSIGN(result_b,
-                           dpf->EvaluateUntil<uint32_t>(1, {prefix}, ctx_b));
-  EXPECT_EQ(result_a.size(), result_b.size());
-  EXPECT_EQ(result_a.size(), 1 << 20);
-  for (int i = 0; i < static_cast<int>(result_a.size()); ++i) {
-    if (i == suffix) {
-      EXPECT_EQ(result_a[i] + result_b[i], beta);
-    } else {
-      EXPECT_EQ(result_a[i] + result_b[i], 0);
-    }
-  }
-}
-
-class RegularDpfKeyGenerationTest
-    : public testing::TestWithParam<std::tuple<int, int>> {
- public:
-  void SetUp() {
-    std::tie(log_domain_size_, element_bitsize_) = GetParam();
-    DpfParameters parameters;
-    parameters.set_log_domain_size(log_domain_size_);
-    parameters.mutable_value_type()->mutable_integer()->set_bitsize(
-        element_bitsize_);
-    DPF_ASSERT_OK_AND_ASSIGN(dpf_,
-                             DistributedPointFunction::Create(parameters));
-    DPF_ASSERT_OK_AND_ASSIGN(
-        proto_validator_, dpf_internal::ProtoValidator::Create({parameters}));
-  }
-
- protected:
-  int log_domain_size_;
-  int element_bitsize_;
-  std::unique_ptr<DistributedPointFunction> dpf_;
-  std::unique_ptr<dpf_internal::ProtoValidator> proto_validator_;
-};
-
-TEST_P(RegularDpfKeyGenerationTest, KeyHasCorrectFormat) {
-  DpfKey key_a, key_b;
-  DPF_ASSERT_OK_AND_ASSIGN(std::tie(key_a, key_b), dpf_->GenerateKeys(0, 0));
-
-  // Check that party is set correctly.
-  EXPECT_EQ(key_a.party(), 0);
-  EXPECT_EQ(key_b.party(), 1);
-  // Check that keys are accepted by proto_validator_.
-  DPF_EXPECT_OK(proto_validator_->ValidateDpfKey(key_a));
-  DPF_EXPECT_OK(proto_validator_->ValidateDpfKey(key_b));
-}
-
-TEST_P(RegularDpfKeyGenerationTest, FailsIfBetaHasTheWrongSize) {
-  EXPECT_THAT(
-      dpf_->GenerateKeysIncremental(0, {1, 2}),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               "`beta` has to have the same size as `parameters` passed at "
-               "construction"));
-}
-
-TEST_P(RegularDpfKeyGenerationTest, FailsIfAlphaIsTooLarge) {
-  if (log_domain_size_ >= 128) {
-    // Alpha is an absl::uint128, so never too large in this case.
-    return;
-  }
-
-  EXPECT_THAT(dpf_->GenerateKeys((absl::uint128{1} << log_domain_size_), 1),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`alpha` must be smaller than the output domain size"));
-}
-
-TEST_P(RegularDpfKeyGenerationTest, FailsIfBetaIsTooLarge) {
-  if (element_bitsize_ >= 128) {
-    // Beta is an absl::uint128, so never too large in this case.
-    return;
-  }
-
-  const auto beta = absl::uint128{1} << element_bitsize_;
-
-  // Not testing error message, as it's an implementation detail of
-  // ProtoValidator.
-  EXPECT_THAT(dpf_->GenerateKeys(0, beta),
-              StatusIs(absl::StatusCode::kInvalidArgument));
-}
-
-INSTANTIATE_TEST_SUITE_P(VaryDomainAndElementSizes, RegularDpfKeyGenerationTest,
-                         testing::Combine(testing::Values(0, 1, 2, 3, 4, 5, 6,
-                                                          7, 8, 9, 10, 32, 62),
-                                          testing::Values(8, 16, 32, 64, 128)));
-
-struct DpfTestParameters {
-  int log_domain_size;
-  int element_bitsize;
-
-  friend std::ostream& operator<<(std::ostream& os,
-                                  const DpfTestParameters& parameters) {
-    return os << "{ log_domain_size: " << parameters.log_domain_size
-              << ", element_bitsize: " << parameters.element_bitsize << " }";
-  }
-};
-
-class IncrementalDpfTest : public testing::TestWithParam<
-                               std::tuple</*parameters*/
-                                          std::vector<DpfTestParameters>,
-                                          /*alpha*/ absl::uint128,
-                                          /*beta*/ std::vector<absl::uint128>,
-                                          /*level_step*/ int,
-                                          /*single_point*/ bool>> {
- protected:
-  void SetUp() {
-    const std::vector<DpfTestParameters>& parameters = std::get<0>(GetParam());
-    parameters_.resize(parameters.size());
-    for (int i = 0; i < static_cast<int>(parameters.size()); ++i) {
-      parameters_[i].set_log_domain_size(parameters[i].log_domain_size);
-      parameters_[i].mutable_value_type()->mutable_integer()->set_bitsize(
-          parameters[i].element_bitsize);
-    }
-    DPF_ASSERT_OK_AND_ASSIGN(
-        dpf_, DistributedPointFunction::CreateIncremental(parameters_));
-    alpha_ = std::get<1>(GetParam());
-    beta_ = std::get<2>(GetParam());
-    DPF_ASSERT_OK_AND_ASSIGN(keys_,
-                             dpf_->GenerateKeysIncremental(alpha_, beta_));
-    level_step_ = std::get<3>(
-        GetParam());  // Number of hierarchy level to evaluate at once.
-    single_point_ = std::get<4>(GetParam());
-    DPF_ASSERT_OK_AND_ASSIGN(proto_validator_,
-                             dpf_internal::ProtoValidator::Create(parameters_));
-  }
-
-  // Returns the prefix of `index` for the domain of `hierarchy_level`.
-  absl::uint128 GetPrefixForLevel(int hierarchy_level, absl::uint128 index) {
-    absl::uint128 result = 0;
-    int shift_amount = parameters_.back().log_domain_size() -
-                       parameters_[hierarchy_level].log_domain_size();
-    if (shift_amount < 128) {
-      result = index >> shift_amount;
-    }
-    return result;
-  }
-
-  // Evaluates both contexts `ctx0` and `ctx1` at `hierarchy level`, using the
-  // appropriate prefixes of `evaluation_points`. Checks that the expansion of
-  // both keys form correct DPF shares, i.e., they add up to
-  // `beta_[ctx.hierarchy_level()]` under prefixes of `alpha_`, and to 0
-  // otherwise. If `singl_point == true`, only evaluates at the prefixes of the
-  // given `evaluation_points`. Otherwise, fully expands the given
-  // `hierarchy_level`.
-  template <typename T>
-  void EvaluateAndCheckLevel(int hierarchy_level,
-                             absl::Span<const absl::uint128> evaluation_points,
-                             EvaluationContext& ctx0, EvaluationContext& ctx1) {
-    int previous_hierarchy_level = ctx0.previous_hierarchy_level();
-    int current_log_domain_size =
-        parameters_[hierarchy_level].log_domain_size();
-    int previous_log_domain_size = 0;
-    int num_expansions = 1;
-    bool is_first_evaluation = previous_hierarchy_level < 0;
-    std::vector<absl::uint128> prefixes;
-    if (single_point_) {
-      // Single point evaluation: Generate prefixes for the current hierarchy
-      // level.
-      prefixes.resize(evaluation_points.size());
-      for (int i = 0; i < static_cast<int>(evaluation_points.size()); ++i) {
-        prefixes[i] = GetPrefixForLevel(hierarchy_level, evaluation_points[i]);
-      }
-    } else if (!is_first_evaluation) {
-      // Full expansion: Generate prefixes for the previous hierarchy level if
-      // we're not on the first level.
-      num_expansions = static_cast<int>(evaluation_points.size());
-      prefixes.resize(evaluation_points.size());
-      previous_log_domain_size =
-          parameters_[previous_hierarchy_level].log_domain_size();
-      for (int i = 0; i < static_cast<int>(evaluation_points.size()); ++i) {
-        prefixes[i] =
-            GetPrefixForLevel(previous_hierarchy_level, evaluation_points[i]);
-      }
-    }
-
-    absl::StatusOr<std::vector<T>> result_0, result_1;
-    if (single_point_) {
-      result_0 = dpf_->EvaluateAt<T>(hierarchy_level, prefixes, ctx0);
-      result_1 = dpf_->EvaluateAt<T>(hierarchy_level, prefixes, ctx1);
-    } else {
-      result_0 = dpf_->EvaluateUntil<T>(hierarchy_level, prefixes, ctx0);
-      result_1 = dpf_->EvaluateUntil<T>(hierarchy_level, prefixes, ctx1);
-    }
-
-    // Check results are ok.
-    DPF_EXPECT_OK(result_0)
-        << "hierarchy_level=" << hierarchy_level << "\nparameters={\n"
-        << parameters_[hierarchy_level].DebugString() << "}\n";
-    DPF_EXPECT_OK(result_1);
-    if (result_0.ok() && result_1.ok()) {
-      // Check output sizes match.
-      ASSERT_EQ(result_0->size(), result_1->size());
-
-      if (single_point_) {
-        absl::uint128 current_alpha_prefix =
-            GetPrefixForLevel(hierarchy_level, alpha_);
-        for (int i = 0; i < result_0->size(); ++i) {
-          if (prefixes[i] == current_alpha_prefix) {
-            EXPECT_EQ(static_cast<T>((*result_0)[i] + (*result_1)[i]),
-                      beta_[hierarchy_level])
-                << "i=" << i << ", hierarchy_level=" << hierarchy_level
-                << "\nparameters={\n"
-                << parameters_[hierarchy_level].DebugString() << "}\n"
-                << "current_alpha_prefix=" << current_alpha_prefix << "\n"
-                << "prefixes[" << i << "]=" << prefixes[i] << "\n"
-                << "evaluation_points[" << i << "]=" << evaluation_points[i]
-                << "\n";
-          } else {
-            EXPECT_EQ(static_cast<T>((*result_0)[i] + (*result_1)[i]), 0)
-                << "i=" << i << ", hierarchy_level=" << hierarchy_level
-                << "\nparameters={\n"
-                << parameters_[hierarchy_level].DebugString() << "}\n"
-                << "current_alpha_prefix=" << current_alpha_prefix << "\n"
-                << "prefixes[" << i << "]=" << prefixes[i] << "\n"
-                << "evaluation_points[" << i << "]=" << evaluation_points[i]
-                << "\n";
-          }
-        }
-      } else {
-        int64_t outputs_per_prefix =
-            int64_t{1} << (current_log_domain_size - previous_log_domain_size);
-        int64_t expected_output_size = num_expansions * outputs_per_prefix;
-        ASSERT_EQ(result_0->size(), expected_output_size);
-
-        // Iterate over the outputs and check that they sum up to 0 or to
-        // beta_[current_hierarchy_level].
-        absl::uint128 previous_alpha_prefix = 0;
-        if (!is_first_evaluation) {
-          previous_alpha_prefix =
-              GetPrefixForLevel(previous_hierarchy_level, alpha_);
-        }
-        absl::uint128 current_alpha_prefix =
-            GetPrefixForLevel(hierarchy_level, alpha_);
-        for (int64_t i = 0; i < expected_output_size; ++i) {
-          int prefix_index = i / outputs_per_prefix;
-          int prefix_expansion_index = i % outputs_per_prefix;
-          // The output is on the path to alpha, if we're at the first level or
-          // under a prefix of alpha, and the current block in the expansion of
-          // the prefix is also on the path to alpha.
-          if ((is_first_evaluation ||
-               prefixes[prefix_index] == previous_alpha_prefix) &&
-              prefix_expansion_index ==
-                  (current_alpha_prefix % outputs_per_prefix)) {
-            // We need to static_cast here since otherwise operator+ returns an
-            // unsigned int without doing a modular reduction, which causes the
-            // test to fail on types with sizeof(T) < sizeof(unsigned).
-            EXPECT_EQ(static_cast<T>((*result_0)[i] + (*result_1)[i]),
-                      beta_[hierarchy_level])
-                << "i=" << i << ", hierarchy_level=" << hierarchy_level
-                << "\nparameters={\n"
-                << parameters_[hierarchy_level].DebugString() << "}\n"
-                << "previous_alpha_prefix=" << previous_alpha_prefix << "\n"
-                << "current_alpha_prefix=" << current_alpha_prefix << "\n";
-          } else {
-            EXPECT_EQ(static_cast<T>((*result_0)[i] + (*result_1)[i]), 0)
-                << "i=" << i << ", hierarchy_level=" << hierarchy_level
-                << "\nparameters={\n"
-                << parameters_[hierarchy_level].DebugString() << "}\n";
-          }
-        }
-      }
-    }
-  }
-
-  std::vector<DpfParameters> parameters_;
-  std::unique_ptr<DistributedPointFunction> dpf_;
-  absl::uint128 alpha_;
-  std::vector<absl::uint128> beta_;
-  std::pair<DpfKey, DpfKey> keys_;
-  int level_step_;
-  bool single_point_;
-  std::unique_ptr<dpf_internal::ProtoValidator> proto_validator_;
-};
-
-TEST_P(IncrementalDpfTest, CreateEvaluationContextCreatesValidContext) {
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-  DPF_EXPECT_OK(proto_validator_->ValidateEvaluationContext(ctx));
-}
-
-TEST_P(IncrementalDpfTest, FailsIfPrefixNotPresentInCtx) {
-  if (parameters_.size() < 3 || parameters_[0].log_domain_size() < 1 ||
-      parameters_[0].value_type().integer().bitsize() != 128 ||
-      parameters_[1].value_type().integer().bitsize() != 128 ||
-      parameters_[2].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  // Evaluate on prefixes 0 and 1, then delete partial evaluations for prefix 0.
-  DPF_ASSERT_OK(dpf_->EvaluateNext<absl::uint128>({}, ctx));
-  DPF_ASSERT_OK(dpf_->EvaluateNext<absl::uint128>({0, 1}, ctx));
-  ctx.mutable_partial_evaluations()->erase(ctx.partial_evaluations().begin());
-
-  // The missing prefix corresponds to hierarchy level 1, even though we
-  // evaluate at level 2.
-  EXPECT_THAT(dpf_->EvaluateNext<absl::uint128>({0}, ctx),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Prefix not present in ctx.partial_evaluations at "
-                       "hierarchy level 1"));
-}
-
-TEST_P(IncrementalDpfTest, FailsIfDuplicatePrefixInCtx) {
-  if (parameters_.size() < 3 || parameters_[0].log_domain_size() < 1 ||
-      parameters_[0].value_type().integer().bitsize() != 128 ||
-      parameters_[1].value_type().integer().bitsize() != 128 ||
-      parameters_[2].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  // Evaluate on prefixes 0 and 1, then add duplicate prefix for 0 with
-  // different seed.
-  DPF_ASSERT_OK(dpf_->EvaluateNext<absl::uint128>({}, ctx));
-  DPF_ASSERT_OK(dpf_->EvaluateNext<absl::uint128>({0, 1}, ctx));
-  *(ctx.add_partial_evaluations()) = ctx.partial_evaluations(0);
-  Block changed_seed = ctx.partial_evaluations(0).seed();
-  changed_seed.set_low(changed_seed.low() + 1);
-  *((ctx.mutable_partial_evaluations()->end() - 1)->mutable_seed()) =
-      changed_seed;
-
-  // The missing prefix corresponds to hierarchy level 1, even though we
-  // evaluate at level 2.
-  EXPECT_THAT(dpf_->EvaluateNext<absl::uint128>({0}, ctx),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Duplicate prefix in `ctx.partial_evaluations()` with "
-                       "mismatching seed or control bit"));
-}
-
-TEST_P(IncrementalDpfTest, EvaluationFailsOnEmptyContext) {
-  if (parameters_[0].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  EvaluationContext ctx;
-
-  // We don't check the error message, since it depends on the ProtoValidator
-  // implementation which is tested in the corresponding unit test.
-  EXPECT_THAT(dpf_->EvaluateNext<absl::uint128>({}, ctx),
-              StatusIs(absl::StatusCode::kInvalidArgument));
-}
-
-TEST_P(IncrementalDpfTest, EvaluationFailsIfHierarchyLevelNegative) {
-  if (parameters_[0].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  EXPECT_THAT(dpf_->EvaluateUntil<absl::uint128>(-1, {}, ctx),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`hierarchy_level` must be non-negative and less than "
-                       "parameters_.size()"));
-}
-
-TEST_P(IncrementalDpfTest, EvaluationFailsIfHierarchyLevelTooLarge) {
-  if (parameters_[0].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  EXPECT_THAT(dpf_->EvaluateUntil<absl::uint128>(parameters_.size(), {}, ctx),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`hierarchy_level` must be non-negative and less than "
-                       "parameters_.size()"));
-}
-
-TEST_P(IncrementalDpfTest, EvaluationFailsIfValueTypeDoesntMatch) {
-  using SomeStrangeType = Tuple<uint8_t, uint32_t, uint8_t, uint16_t, uint8_t>;
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  EXPECT_THAT(
-      dpf_->EvaluateUntil<SomeStrangeType>(0, {}, ctx),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               "Value type T doesn't match parameters at `hierarchy_level`"));
-}
-
-TEST_P(IncrementalDpfTest, EvaluationFailsIfLevelAlreadyEvaluated) {
-  if (parameters_.size() < 2 ||
-      parameters_[0].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  DPF_ASSERT_OK(dpf_->EvaluateUntil<absl::uint128>(0, {}, ctx));
-
-  EXPECT_THAT(dpf_->EvaluateUntil<absl::uint128>(0, {}, ctx),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`hierarchy_level` must be greater than "
-                       "`ctx.previous_hierarchy_level`"));
-}
-
-TEST_P(IncrementalDpfTest, EvaluationFailsIfPrefixesNotEmptyOnFirstCall) {
-  if (parameters_[0].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  EXPECT_THAT(
-      dpf_->EvaluateUntil<absl::uint128>(0, {0}, ctx),
-      StatusIs(
-          absl::StatusCode::kInvalidArgument,
-          "`prefixes` must be empty if and only if this is the first call with "
-          "`ctx`."));
-}
-
-TEST_P(IncrementalDpfTest, EvaluationFailsIfPrefixOutOfRange) {
-  if (parameters_.size() < 2 ||
-      parameters_[0].value_type().integer().bitsize() != 128 ||
-      parameters_[1].value_type().integer().bitsize() != 128) {
-    return;
-  }
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx,
-                           dpf_->CreateEvaluationContext(keys_.first));
-
-  DPF_ASSERT_OK(dpf_->EvaluateUntil<absl::uint128>(0, {}, ctx));
-  auto invalid_prefix = absl::uint128{1} << parameters_[0].log_domain_size();
-
-  EXPECT_THAT(dpf_->EvaluateUntil<absl::uint128>(1, {invalid_prefix}, ctx),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       StrFormat("Index %d out of range for hierarchy level 0",
-                                 invalid_prefix)));
-}
-
-TEST_P(IncrementalDpfTest, TestCorrectness) {
-  // Generate a random set of evaluation points. The library should be able to
-  // handle duplicates, so fixing the size to 1000 works even for smaller
-  // domains.
-  absl::BitGen rng;
-  absl::uniform_int_distribution<uint64_t> dist;
-  const int kNumEvaluationPoints = 1000;
-  std::vector<absl::uint128> evaluation_points(kNumEvaluationPoints);
-  for (int i = 0; i < kNumEvaluationPoints - 1; ++i) {
-    evaluation_points[i] = absl::MakeUint128(dist(rng), dist(rng));
-    if (parameters_.back().log_domain_size() < 128) {
-      evaluation_points[i] %= absl::uint128{1}
-                              << parameters_.back().log_domain_size();
-    }
-  }
-  evaluation_points.back() = alpha_;  // Always evaluate on alpha_.
-
-  int num_levels = static_cast<int>(parameters_.size());
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx0,
-                           dpf_->CreateEvaluationContext(keys_.first));
-  DPF_ASSERT_OK_AND_ASSIGN(EvaluationContext ctx1,
-                           dpf_->CreateEvaluationContext(keys_.second));
-
-  for (int i = level_step_ - 1; i < num_levels; i += level_step_) {
-    switch (parameters_[i].value_type().integer().bitsize()) {
-      case 8:
-        EvaluateAndCheckLevel<uint8_t>(i, evaluation_points, ctx0, ctx1);
-        break;
-      case 16:
-        EvaluateAndCheckLevel<uint16_t>(i, evaluation_points, ctx0, ctx1);
-        break;
-      case 32:
-        EvaluateAndCheckLevel<uint32_t>(i, evaluation_points, ctx0, ctx1);
-        break;
-      case 64:
-        EvaluateAndCheckLevel<uint64_t>(i, evaluation_points, ctx0, ctx1);
-        break;
-      case 128:
-        EvaluateAndCheckLevel<absl::uint128>(i, evaluation_points, ctx0, ctx1);
-        break;
-      default:
-        ASSERT_TRUE(0) << "Unsupported element_bitsize";
-    }
-  }
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    OneHierarchyLevelVaryElementSizes, IncrementalDpfTest,
-    testing::Combine(
-        // DPF parameters.
-        testing::Values(
-            // Vary element sizes, small domain size.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 16}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 32}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 128}},
-            // Vary element sizes, medium domain size.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 10, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 10, .element_bitsize = 16}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 10, .element_bitsize = 32}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 10, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 10, .element_bitsize = 128}}),
-        testing::Values(0, 1, 15),  // alpha
-        testing::Values(std::vector<absl::uint128>(1, 1),
-                        std::vector<absl::uint128>(1, 100),
-                        std::vector<absl::uint128>(1, 255)),  // beta
-        testing::Values(1),                                   // level_step
-        testing::Values(false, true)                          // single_point
-        ));
-
-INSTANTIATE_TEST_SUITE_P(
-    OneHierarchyLevelVaryDomainSizes, IncrementalDpfTest,
-    testing::Combine(
-        // DPF parameters.
-        testing::Values(
-            // Vary domain sizes, small element size.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 1, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 2, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 3, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 6, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 7, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 8, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 9, .element_bitsize = 8}},
-            // Vary domain sizes, medium element size.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 1, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 2, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 3, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 6, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 7, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 8, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 9, .element_bitsize = 64}},
-            // Vary domain sizes, large element size.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 1, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 2, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 3, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 6, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 7, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 8, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 9, .element_bitsize = 128}}),
-        testing::Values(0),  // alpha
-        testing::Values(std::vector<absl::uint128>(1, 1),
-                        std::vector<absl::uint128>(1, 100),
-                        std::vector<absl::uint128>(1, 255)),  // beta
-        testing::Values(1),                                   // level_step
-        testing::Values(false, true)                          // single_point
-        ));
-
-INSTANTIATE_TEST_SUITE_P(
-    TwoHierarchyLevels, IncrementalDpfTest,
-    testing::Combine(
-        // DPF parameters.
-        testing::Values(
-            // Equal element sizes.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 8},
-                {.log_domain_size = 10, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 16},
-                {.log_domain_size = 10, .element_bitsize = 16}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 32},
-                {.log_domain_size = 10, .element_bitsize = 32}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 64},
-                {.log_domain_size = 10, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 128},
-                {.log_domain_size = 10, .element_bitsize = 128}},
-            // First correction is in seed word.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 8},
-                {.log_domain_size = 10, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 16},
-                {.log_domain_size = 10, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 32},
-                {.log_domain_size = 10, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 64},
-                {.log_domain_size = 10, .element_bitsize = 128}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 128},
-                {.log_domain_size = 10, .element_bitsize = 128}}),
-        testing::Values(0, 1, 2, 100, 1023),  // alpha
-        testing::Values(std::vector<absl::uint128>({1, 2}),
-                        std::vector<absl::uint128>({80, 90}),
-                        std::vector<absl::uint128>({255, 255})),  // beta
-        testing::Values(1, 2),                                    // level_step
-        testing::Values(false, true)  // single_point
-        ));
-
-INSTANTIATE_TEST_SUITE_P(
-    ThreeHierarchyLevels, IncrementalDpfTest,
-    testing::Combine(
-        // DPF parameters.
-        testing::Values<std::vector<DpfTestParameters>>(
-            // Equal element sizes.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 8},
-                {.log_domain_size = 10, .element_bitsize = 8},
-                {.log_domain_size = 15, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 16},
-                {.log_domain_size = 10, .element_bitsize = 16},
-                {.log_domain_size = 15, .element_bitsize = 16}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 32},
-                {.log_domain_size = 10, .element_bitsize = 32},
-                {.log_domain_size = 15, .element_bitsize = 32}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 64},
-                {.log_domain_size = 10, .element_bitsize = 64},
-                {.log_domain_size = 15, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 128},
-                {.log_domain_size = 10, .element_bitsize = 128},
-                {.log_domain_size = 15, .element_bitsize = 128}},
-            // Varying element sizes
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 5, .element_bitsize = 8},
-                {.log_domain_size = 10, .element_bitsize = 16},
-                {.log_domain_size = 15, .element_bitsize = 32}},
-            // Small level distances.
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 4, .element_bitsize = 8},
-                {.log_domain_size = 5, .element_bitsize = 8},
-                {.log_domain_size = 6, .element_bitsize = 8}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 3, .element_bitsize = 16},
-                {.log_domain_size = 4, .element_bitsize = 16},
-                {.log_domain_size = 5, .element_bitsize = 16}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 2, .element_bitsize = 32},
-                {.log_domain_size = 3, .element_bitsize = 32},
-                {.log_domain_size = 4, .element_bitsize = 32}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 1, .element_bitsize = 64},
-                {.log_domain_size = 2, .element_bitsize = 64},
-                {.log_domain_size = 3, .element_bitsize = 64}},
-            std::vector<DpfTestParameters>{
-                {.log_domain_size = 0, .element_bitsize = 128},
-                {.log_domain_size = 1, .element_bitsize = 128},
-                {.log_domain_size = 2, .element_bitsize = 128}}),
-        testing::Values(0, 1),                                   // alpha
-        testing::Values(std::vector<absl::uint128>({1, 2, 3})),  // beta
-        testing::Values(1, 2),                                   // level_step
-        testing::Values(false, true)                             // single_point
-        ));
-
-INSTANTIATE_TEST_SUITE_P(
-    MaximumOutputDomainSize, IncrementalDpfTest,
-    testing::Combine(
-        // DPF parameters. We want to be able to evaluate at every bit, so this
-        // lambda returns a vector with 129 parameters with log domain sizes
-        // 0...128.
-        testing::Values([]() -> std::vector<DpfTestParameters> {
-          std::vector<DpfTestParameters> parameters(129);
-          for (int i = 0; i < static_cast<int>(parameters.size()); ++i) {
-            parameters[i].log_domain_size = i;
-            parameters[i].element_bitsize = 64;
-          }
-          return parameters;
-        }()),
-        testing::Values(absl::MakeUint128(23, 42)),                 // alpha
-        testing::Values(std::vector<absl::uint128>(129, 1234567)),  // beta
-        testing::Values(1, 2, 3, 5, 7),  // level_step
-        testing::Values(false, true)     // single_point
-        ));
-
-template <typename T>
-class DpfEvaluationTest : public ::testing::Test {
- protected:
-  void SetUp() { SetUp(10, 23); }
-  void SetUp(int log_domain_size, absl::uint128 alpha) {
-    return SetUp(absl::MakeConstSpan(&log_domain_size, 1), alpha);
-  }
-  void SetUp(absl::Span<const int> log_domain_size, absl::uint128 alpha) {
-    log_domain_size_.resize(log_domain_size.size());
-    absl::c_copy(log_domain_size, log_domain_size_.begin());
-    alpha_ = alpha;
-    beta_.resize(log_domain_size.size());
-    for (T& beta : beta_) {
-      SetTo42(beta);
-    }
-    parameters_.resize(log_domain_size.size());
-    for (int i = 0; i < parameters_.size(); ++i) {
-      parameters_[i].set_log_domain_size(log_domain_size_[i]);
-      parameters_[i].set_security_parameter(48);
-      *(parameters_[i].mutable_value_type()) = ToValueType<T>();
-    }
-    DPF_ASSERT_OK_AND_ASSIGN(
-        dpf_, DistributedPointFunction::CreateIncremental(parameters_));
-    DPF_ASSERT_OK(this->dpf_->template RegisterValueType<T>());
-    DPF_ASSERT_OK_AND_ASSIGN(
-        keys_, this->dpf_->GenerateKeysIncremental(
-                   this->alpha_, absl::MakeConstSpan(this->beta_)));
-  }
-
-  // Helper function that recursively sets all elements of a tuple to 42.
-  template <typename T0>
-  static void SetTo42(T0& x) {
-    x = T0(42);
-  }
-  template <typename T0, typename... Tn>
-  static void SetTo42(T0& x0, Tn&... xn) {
-    SetTo42(x0);
-    SetTo42(xn...);
-  }
-  template <typename... Tn>
-  static void SetTo42(Tuple<Tn...>& x) {
-    absl::apply([](auto&... in) { SetTo42(in...); }, x.value());
-  }
-
-  std::vector<int> log_domain_size_;
-  absl::uint128 alpha_;
-  std::vector<T> beta_;
-  std::vector<DpfParameters> parameters_;
-  std::unique_ptr<DistributedPointFunction> dpf_;
-  std::pair<DpfKey, DpfKey> keys_;
-};
-
-using MyIntModN = IntModN<uint32_t, 4294967291u>;                // 2**32 - 5.
-using MyIntModN64 = IntModN<uint64_t, 18446744073709551557ull>;  // 2**64 - 59.
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-using MyIntModN128 =
-    IntModN<absl::uint128, (unsigned __int128)(absl::MakeUint128(
-                               65535u, 18446744073709551551ull))>;  // 2**80-65
-#endif
-using DpfEvaluationTypes = ::testing::Types<
-    // Integers
-    uint8_t, uint32_t, uint64_t, absl::uint128,
-    // Tuple
-    Tuple<uint8_t>, Tuple<uint32_t>, Tuple<absl::uint128>,
-    Tuple<uint32_t, uint32_t>, Tuple<uint32_t, uint64_t>,
-    Tuple<uint64_t, uint64_t>, Tuple<uint8_t, uint16_t, uint32_t, uint64_t>,
-    Tuple<uint32_t, uint32_t, uint32_t, uint32_t>,
-    Tuple<uint32_t, Tuple<uint32_t, uint32_t>, uint32_t>,
-    Tuple<uint32_t, absl::uint128>,
-    // IntModN
-    MyIntModN, Tuple<MyIntModN>, Tuple<uint32_t, MyIntModN>,
-    Tuple<absl::uint128, MyIntModN>, Tuple<MyIntModN, Tuple<MyIntModN>>,
-    Tuple<MyIntModN, MyIntModN, MyIntModN, MyIntModN, MyIntModN>,
-    Tuple<MyIntModN64, MyIntModN64>
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-    ,
-    Tuple<MyIntModN128, MyIntModN128>,
-#endif
-    // XorWrapper
-    XorWrapper<uint8_t>, XorWrapper<absl::uint128>,
-    Tuple<XorWrapper<uint32_t>, absl::uint128>>;
-TYPED_TEST_SUITE(DpfEvaluationTest, DpfEvaluationTypes);
-
-TYPED_TEST(DpfEvaluationTest, TestRegularDpf) {
-  int log_domain_size = 10;
-  absl::uint128 alpha = 23;
-  this->SetUp(log_domain_size, alpha);
-  DPF_ASSERT_OK_AND_ASSIGN(
-      EvaluationContext ctx_1,
-      this->dpf_->CreateEvaluationContext(this->keys_.first));
-  DPF_ASSERT_OK_AND_ASSIGN(
-      EvaluationContext ctx_2,
-      this->dpf_->CreateEvaluationContext(this->keys_.second));
-  DPF_ASSERT_OK_AND_ASSIGN(
-      std::vector<TypeParam> output_1,
-      this->dpf_->template EvaluateNext<TypeParam>({}, ctx_1));
-  DPF_ASSERT_OK_AND_ASSIGN(
-      std::vector<TypeParam> output_2,
-      this->dpf_->template EvaluateNext<TypeParam>({}, ctx_2));
-
-  EXPECT_EQ(output_1.size(), 1 << log_domain_size);
-  EXPECT_EQ(output_2.size(), 1 << log_domain_size);
-  for (int i = 0; i < (1 << log_domain_size); ++i) {
-    TypeParam sum = output_1[i] + output_2[i];
-    if (i == this->alpha_) {
-      EXPECT_EQ(sum, this->beta_[0]);
-    } else {
-      EXPECT_EQ(sum, TypeParam{});
-    }
-  }
-}
-
-TYPED_TEST(DpfEvaluationTest, TestBatchSinglePointEvaluation) {
-  // Set Up with a large output domain, to make sure this works.
-  for (int log_domain_size : {0, 1, 2, 32, 128}) {
-    absl::uint128 max_evaluation_point = absl::Uint128Max();
-    if (log_domain_size < 128) {
-      max_evaluation_point = (absl::uint128{1} << log_domain_size) - 1;
-    }
-    const absl::uint128 alpha = 23 & max_evaluation_point;
-    this->SetUp(log_domain_size, alpha);
-    for (int num_evaluation_points : {0, 1, 2, 100, 1000}) {
-      std::vector<absl::uint128> evaluation_points(num_evaluation_points);
-      for (int i = 0; i < num_evaluation_points; ++i) {
-        evaluation_points[i] = i & max_evaluation_point;
-      }
-      DPF_ASSERT_OK_AND_ASSIGN(std::vector<TypeParam> output_1,
-                               this->dpf_->template EvaluateAt<TypeParam>(
-                                   this->keys_.first, 0, evaluation_points));
-      DPF_ASSERT_OK_AND_ASSIGN(std::vector<TypeParam> output_2,
-                               this->dpf_->template EvaluateAt<TypeParam>(
-                                   this->keys_.second, 0, evaluation_points));
-      ASSERT_EQ(output_1.size(), output_2.size());
-      ASSERT_EQ(output_1.size(), num_evaluation_points);
-
-      for (int i = 0; i < num_evaluation_points; ++i) {
-        TypeParam sum = output_1[i] + output_2[i];
-        if (evaluation_points[i] == this->alpha_) {
-          EXPECT_EQ(sum, this->beta_[0])
-              << "i=" << i << ", log_domain_size=" << log_domain_size;
-        } else {
-          EXPECT_EQ(sum, TypeParam{})
-              << "i=" << i << ", log_domain_size=" << log_domain_size;
-        }
-      }
-    }
-  }
-}
-
-TYPED_TEST(DpfEvaluationTest, TestEvaluateAndApplySimpleAddition) {
-  std::vector<std::vector<int>> parameters = {
-      {0, 1, 2}, {8, 16, 32, 64}, {0, 128}, {128}, {/* filled below */}};
-  for (int i = 0; i <= 128; ++i) {
-    parameters.back().push_back(i);
-  }
-  for (const auto& log_domain_sizes : parameters) {
-    absl::uint128 max_domain_element = absl::Uint128Max();
-    if (log_domain_sizes.back() < 128) {
-      max_domain_element = (absl::uint128{1} << log_domain_sizes.back()) - 1;
-    }
-    absl::uint128 alpha = max_domain_element;
-    this->SetUp(log_domain_sizes, alpha);
-
-    std::vector<absl::uint128> evaluation_points = {23, 42, 123, 0,
-                                                    absl::Uint128Max()};
-    for (auto& point : evaluation_points) {
-      point &= max_domain_element;
-    }
-    std::vector<const DpfKey*> keys = {
-        &(this->keys_.first), &(this->keys_.second), &(this->keys_.first),
-        &(this->keys_.second), &(this->keys_.first)};
-    int num_levels = log_domain_sizes.size();
-    int num_keys = keys.size();
-
-    std::vector<TypeParam> sum(num_keys, TypeParam{});
-    int count = 0;
-    auto fn = [&sum, &count](absl::Span<const TypeParam> values) {
-      for (int i = 0; i < values.size(); ++i) {
-        sum[i] += values[i];
-      }
-      ++count;
-      return true;
-    };
-
-    // Run evaluation level-by-level to compute the expected sum.
-    std::vector<TypeParam> expected(num_keys, TypeParam{});
-    for (int hierarchy_level = 0; hierarchy_level < num_levels;
-         ++hierarchy_level) {
-      const int shift_amount =
-          (log_domain_sizes.back() - log_domain_sizes[hierarchy_level]);
-      for (int i = 0; i < num_keys; ++i) {
-        absl::uint128 prefix = 0;
-        if (shift_amount < 128) {
-          prefix = evaluation_points[i] >> shift_amount;
-        }
-        DPF_ASSERT_OK_AND_ASSIGN(
-            auto result,
-            this->dpf_->template EvaluateAt<TypeParam>(
-                *keys[i], hierarchy_level, absl::MakeConstSpan(&prefix, 1)));
-        expected[i] += result[0];
-      }
-    }
-
-    EXPECT_THAT(this->dpf_->template EvaluateAndApply<TypeParam>(
-                    keys, evaluation_points, fn),
-                IsOk());
-    EXPECT_EQ(sum, expected)
-        << "log_domain_sizes=" << absl::StrJoin(log_domain_sizes, " ");
-    EXPECT_EQ(count, num_levels);
-  }
-}
-
-TYPED_TEST(DpfEvaluationTest,
-           EvaluateAndApplyFailsWithTooManyEvaluationPoints) {
-  std::vector<absl::uint128> evaluation_points = {0, 1};
-
-  EXPECT_THAT(
-      this->dpf_->template EvaluateAndApply<TypeParam>(
-          absl::MakeConstSpan(&(this->keys_.first), 1), evaluation_points,
-          [](absl::Span<const TypeParam>) { return true; }),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               HasSubstr("evaluation_points")));
-}
-
-TYPED_TEST(DpfEvaluationTest, EvaluateAndApplyFailsWithInvalidKey) {
-  DpfKey key;
-
-  EXPECT_THAT(this->dpf_->template EvaluateAndApply<TypeParam>(
-                  absl::MakeConstSpan(&key, 1), {0},
-                  [](absl::Span<const TypeParam>) { return true; }),
-              StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("key")));
-}
-
-}  // namespace
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/int_mod_n.cc b/third_party/distributed_point_functions/code/dpf/int_mod_n.cc
deleted file mode 100644
index 3b5d9926..0000000
--- a/third_party/distributed_point_functions/code/dpf/int_mod_n.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/int_mod_n.h"
-
-#include <cmath>
-#include <string>
-
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_format.h"
-
-namespace distributed_point_functions {
-
-namespace dpf_internal {
-
-double IntModNBase::GetSecurityLevel(int num_samples, absl::uint128 modulus) {
-  return 128 + 3 -
-         (std::log2(static_cast<double>(modulus)) +
-          std::log2(static_cast<double>(num_samples)) +
-          std::log2(static_cast<double>(num_samples + 1)));
-}
-
-absl::Status IntModNBase::CheckParameters(int num_samples,
-                                          int base_integer_bitsize,
-                                          absl::uint128 modulus,
-                                          double security_parameter) {
-  if (num_samples <= 0) {
-    return absl::InvalidArgumentError("num_samples must be positive");
-  }
-  if (base_integer_bitsize <= 0) {
-    return absl::InvalidArgumentError("base_integer_bitsize must be positive");
-  }
-  if (base_integer_bitsize > 128) {
-    return absl::InvalidArgumentError(
-        "base_integer_bitsize must be at most 128");
-  }
-  if (base_integer_bitsize < 128 &&
-      (absl::uint128{1} << base_integer_bitsize) < modulus) {
-    return absl::InvalidArgumentError(absl::StrFormat(
-        "kModulus %d out of range for base_integer_bitsize = %d", modulus,
-        base_integer_bitsize));
-  }
-
-  // Compute the level of security that we will get, and fail if it is
-  // insufficient.
-  const double sigma = GetSecurityLevel(num_samples, modulus);
-  if (security_parameter > sigma) {
-    return absl::InvalidArgumentError(absl::StrFormat(
-        "For num_samples = %d and kModulus = %d this approach can only "
-        "provide "
-        "%f bits of statistical security. You can try calling this function "
-        "several times with smaller values of num_samples.",
-        num_samples, modulus, sigma));
-  }
-  return absl::OkStatus();
-}
-
-absl::StatusOr<int> IntModNBase::GetNumBytesRequired(
-    int num_samples, int base_integer_bitsize, absl::uint128 modulus,
-    double security_parameter) {
-  absl::Status status = CheckParameters(num_samples, base_integer_bitsize,
-                                        modulus, security_parameter);
-  if (!status.ok()) {
-    return status;
-  }
-
-  const int base_integer_bytes = ((base_integer_bitsize + 7) / 8);
-  // We start the sampling by requiring a 128-bit (16 bytes) block, see
-  // function `SampleFromBytes`.
-  return 16 + base_integer_bytes * (num_samples - 1);
-}
-
-}  // namespace dpf_internal
-
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/int_mod_n.h b/third_party/distributed_point_functions/code/dpf/int_mod_n.h
deleted file mode 100644
index 0f61ed0..0000000
--- a/third_party/distributed_point_functions/code/dpf/int_mod_n.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_INT_MOD_N_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_INT_MOD_N_H_
-
-#include <algorithm>
-#include <string>
-#include <type_traits>
-
-#include "absl/base/config.h"
-#include "absl/container/inlined_vector.h"
-#include "absl/log/absl_check.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-
-namespace distributed_point_functions {
-
-namespace dpf_internal {
-
-// Base class holding common functions of IntModN that are independent of the
-// template parameter.
-class IntModNBase {
- public:
-  // Computes the security level achievable when sampling `num_samples` elements
-  // with the given `kModulus`.
-  //
-  static double GetSecurityLevel(int num_samples, absl::uint128 modulus);
-
-  // Checks if the given parameters are consistent and valid for an IntModN.
-  //
-  // Returns OK for valid parameters, and INVALID_ARGUMENT otherwise.
-  static absl::Status CheckParameters(int num_samples, int base_integer_bitsize,
-                                      absl::uint128 modulus,
-                                      double security_parameter);
-
-  // Computes the number of bytes required to sample `num_samples` integers
-  // modulo `kModulus` with an underlying integer type of
-  // `base_integer_bitsize`.
-  //
-  // Returns INVALID_ARGUMENT if the achievable security level with the given
-  // parameters is less than `security_parameter`, or if the parameters are
-  // invalid.
-  static absl::StatusOr<int> GetNumBytesRequired(int num_samples,
-                                                 int base_integer_bitsize,
-                                                 absl::uint128 modulus,
-                                                 double security_parameter);
-
-  // Creates a value of type T from the given `bytes`, using little-endian
-  // encoding. Called by SampleFromBytes. Crashes if bytes.size() != sizeof(T).
-  //
-  // This is a reimplementation of dpf_internal::ConvertBytesTo for integers,
-  // to avoid depending on value_type_helpers here.
-  template <typename T>
-  static T ConvertBytesTo(absl::string_view bytes) {
-    ABSL_CHECK(bytes.size() == sizeof(T));
-    T out{0};
-#ifdef ABSL_IS_LITTLE_ENDIAN
-    std::copy_n(bytes.begin(), sizeof(T), reinterpret_cast<char*>(&out));
-#else
-    for (int i = sizeof(T) - 1; i >= 0; --i) {
-      out |= absl::bit_cast<uint8_t>(bytes[i]);
-      out <<= 8;
-    }
-#endif
-    return out;
-  }
-};
-
-template <typename BaseInteger, typename ModulusType, ModulusType kModulus>
-class IntModNImpl : public IntModNBase {
-  static_assert(sizeof(BaseInteger) <= sizeof(absl::uint128),
-                "BaseInteger may be at most 128 bits large");
-  static_assert(
-      std::is_same<BaseInteger, absl::uint128>::value ||
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-          // std::is_unsigned_v<unsigned __int128> is not true everywhere:
-          // https://quuxplusone.github.io/blog/2019/02/28/is-int128-integral/#signedness
-          std::is_same<BaseInteger, unsigned __int128>::value ||
-#endif
-          std::is_unsigned<BaseInteger>::value,
-      "BaseInteger must be unsigned");
-  static_assert(kModulus <= ModulusType(BaseInteger(-1)),
-                "kModulus must fit in BaseInteger");
-
- public:
-  using Base = BaseInteger;
-
-  constexpr IntModNImpl() : value_(0) {}
-  explicit constexpr IntModNImpl(BaseInteger value)
-      : value_(value % kModulus) {}
-
-  // Copyable.
-  constexpr IntModNImpl(const IntModNImpl& a) = default;
-
-  constexpr IntModNImpl& operator=(const IntModNImpl& a) = default;
-
-  // Assignment operators.
-  constexpr IntModNImpl& operator=(const BaseInteger& a) {
-    value_ = a % kModulus;
-    return *this;
-  }
-
-  constexpr IntModNImpl& operator+=(const IntModNImpl& a) {
-    AddBaseInteger(a.value_);
-    return *this;
-  }
-
-  constexpr IntModNImpl& operator-=(const IntModNImpl& a) {
-    SubtractBaseInteger(a.value_);
-    return *this;
-  }
-
-  // Returns the underlying representation as a BaseInteger.
-  constexpr BaseInteger value() const { return value_; }
-
-  // Returns the modulus of this IntModNImpl type.
-  static constexpr BaseInteger modulus() { return kModulus; }
-
-  // Returns the number of (pseudo)random bytes required to extract
-  // `num_samples` samples r1, ..., rn
-  // so that the stream r1, ..., rn is close to a truly (pseudo) random
-  // sequence up to total variation distance < 2^(-`security_parameter`)
-  static absl::StatusOr<int> GetNumBytesRequired(int num_samples,
-                                                 double security_parameter) {
-    return IntModNBase::GetNumBytesRequired(
-        num_samples, 8 * sizeof(BaseInteger), kModulus, security_parameter);
-  }
-
-  // Extracts `samples.size()` samples r1, ..., rn so that the stream r1, ...,
-  // rn is close to a truly (pseudo) random sequence up to total variation
-  // distance < 2^(-`security_parameter`). Returns r1, ..., rn in `samples`.
-  //
-  // The optional template argument allows users to specify the number of
-  // samples at compile time, which can save heap allocations.
-  //
-  // Caution: For performance reasons, this function does not check whether
-  // `bytes` is long enough for the required number of samples and security
-  // parameter. Use `GetNumBytesRequired` or `SampleFromBytes` if such checks
-  // are needed.
-  //
-  template <int kCompiledNumSamples = 1>
-  static void UnsafeSampleFromBytes(absl::string_view bytes,
-                                    double security_parameter,
-                                    absl::Span<IntModNImpl> samples) {
-    static_assert(kCompiledNumSamples >= 1,
-                  "kCompiledNumSamples must be positive");
-    absl::uint128 r = ConvertBytesTo<absl::uint128>(bytes.substr(0, 16));
-    absl::InlinedVector<BaseInteger, std::max(1, kCompiledNumSamples - 1)>
-        randomness(samples.size() - 1);
-    for (int i = 0; i < static_cast<int>(randomness.size()); ++i) {
-      randomness[i] = ConvertBytesTo<BaseInteger>(
-          bytes.substr(16 + i * sizeof(BaseInteger), sizeof(BaseInteger)));
-    }
-    for (int i = 0; i < static_cast<int>(samples.size()); ++i) {
-      samples[i] = IntModNImpl(static_cast<BaseInteger>(r % kModulus));
-      if (i < static_cast<int>(randomness.size())) {
-        r /= kModulus;
-        if (sizeof(BaseInteger) < sizeof(absl::uint128)) {
-          r <<= (sizeof(BaseInteger) * 8);
-        }
-        r |= randomness[i];
-      }
-    }
-  }
-
-  //  Checks that length(`bytes`) is enough to extract
-  // `samples.size()` samples r1, ..., rn
-  //  so that the stream r1, ..., rn is close to a truly (pseudo) random
-  //  sequence up to total variation distance < 2^(-`security_parameter`) and
-  //  fails if that is not the case.
-  //  Otherwise returns r1, ..., rn in `samples`.
-  static absl::Status SampleFromBytes(absl::string_view bytes,
-                                      double security_parameter,
-                                      absl::Span<IntModNImpl> samples) {
-    if (samples.empty()) {
-      return absl::InvalidArgumentError(
-          "The number of samples required must be > 0");
-    }
-    absl::StatusOr<int> num_bytes_lower_bound =
-        GetNumBytesRequired(samples.size(), security_parameter);
-    if (!num_bytes_lower_bound.ok()) {
-      return num_bytes_lower_bound.status();
-    }
-    if (*num_bytes_lower_bound > bytes.size()) {
-      return absl::InvalidArgumentError(
-          absl::StrCat("The number of bytes provided (", bytes.size(),
-                       ") is insufficient for the required "
-                       "statistical security and number of samples."));
-    }
-    UnsafeSampleFromBytes(bytes, security_parameter, samples);
-    return absl::OkStatus();
-  }
-
- private:
-  constexpr void SubtractBaseInteger(const BaseInteger& a) {
-    if (value_ >= a) {
-      value_ -= a;
-    } else {
-      value_ = kModulus - a + value_;
-    }
-  }
-
-  constexpr void AddBaseInteger(const BaseInteger& a) {
-    SubtractBaseInteger(kModulus - a);
-  }
-
-  BaseInteger value_;
-};
-
-template <typename BaseInteger, typename ModulusType, ModulusType kModulus>
-constexpr IntModNImpl<BaseInteger, ModulusType, kModulus> operator+(
-    IntModNImpl<BaseInteger, ModulusType, kModulus> a,
-    const IntModNImpl<BaseInteger, ModulusType, kModulus>& b) {
-  a += b;
-  return a;
-}
-
-template <typename BaseInteger, typename ModulusType, ModulusType kModulus>
-constexpr IntModNImpl<BaseInteger, ModulusType, kModulus> operator-(
-    IntModNImpl<BaseInteger, ModulusType, kModulus> a,
-    const IntModNImpl<BaseInteger, ModulusType, kModulus>& b) {
-  a -= b;
-  return a;
-}
-
-template <typename BaseInteger, typename ModulusType, ModulusType kModulus>
-constexpr IntModNImpl<BaseInteger, ModulusType, kModulus> operator-(
-    IntModNImpl<BaseInteger, ModulusType, kModulus> a) {
-  IntModNImpl<BaseInteger, ModulusType, kModulus> result(BaseInteger{0});
-  result -= a;
-  return result;
-}
-
-template <typename BaseInteger, typename ModulusType, ModulusType kModulus>
-constexpr bool operator==(
-    const IntModNImpl<BaseInteger, ModulusType, kModulus>& a,
-    const IntModNImpl<BaseInteger, ModulusType, kModulus>& b) {
-  return a.value() == b.value();
-}
-
-template <typename BaseInteger, typename ModulusType, ModulusType kModulus>
-constexpr bool operator!=(
-    const IntModNImpl<BaseInteger, ModulusType, kModulus>& a,
-    const IntModNImpl<BaseInteger, ModulusType, kModulus>& b) {
-  return !(a == b);
-}
-
-}  // namespace dpf_internal
-
-// Since `absl::uint128` is not an alias to `unsigned __int128`, but a struct,
-// we cannot use it as a template parameter type. So if we have an intrinsic
-// int128, we always use that as the modulus type. Otherwise, the modulus type
-// is the same as BaseInteger.
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-template <typename BaseInteger, unsigned __int128 kModulus>
-using IntModN =
-    dpf_internal::IntModNImpl<BaseInteger, unsigned __int128, kModulus>;
-#else
-template <typename BaseInteger, BaseInteger kModulus>
-using IntModN = dpf_internal::IntModNImpl<BaseInteger, BaseInteger, kModulus>;
-#endif
-
-}  // namespace distributed_point_functions
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_INT_MOD_N_H_
diff --git a/third_party/distributed_point_functions/code/dpf/int_mod_n_benchmark.cc b/third_party/distributed_point_functions/code/dpf/int_mod_n_benchmark.cc
deleted file mode 100644
index b095faa..0000000
--- a/third_party/distributed_point_functions/code/dpf/int_mod_n_benchmark.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include <stdint.h>
-
-#include <cmath>
-#include <vector>
-
-#include "absl/status/statusor.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-#include "benchmark/benchmark.h"
-#include "dpf/int_mod_n.h"
-#include "openssl/rand.h"
-
-namespace distributed_point_functions {
-namespace {
-
-using MyInt = IntModN<uint32_t, 4294967291u>;  // 2**32 - 5.
-constexpr int kNumSamples = 5;
-
-void BM_Sample(benchmark::State& state) {
-  int num_iterations = state.range(0);
-  double security_parameter = 40 + std::log2(num_iterations);
-  std::vector<uint8_t> bytes(
-      MyInt::GetNumBytesRequired(kNumSamples, security_parameter).value());
-  RAND_bytes(bytes.data(), bytes.size());
-  std::vector<MyInt> output(num_iterations * kNumSamples);
-  for (auto s : state) {
-    for (int i = 0; i < num_iterations; ++i) {
-      MyInt::UnsafeSampleFromBytes<kNumSamples>(
-          absl::string_view(reinterpret_cast<const char*>(bytes.data()),
-                            bytes.size()),
-          security_parameter,
-          absl::MakeSpan(&output[i * kNumSamples], kNumSamples));
-    }
-    benchmark::DoNotOptimize(output);
-  }
-}
-BENCHMARK(BM_Sample)->Range(1, 1 << 20);
-
-}  // namespace
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/int_mod_n_test.cc b/third_party/distributed_point_functions/code/dpf/int_mod_n_test.cc
deleted file mode 100644
index dd03d503..0000000
--- a/third_party/distributed_point_functions/code/dpf/int_mod_n_test.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/int_mod_n.h"
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-#include "absl/base/config.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_format.h"
-#include "absl/types/span.h"
-#include "dpf/internal/status_matchers.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace {
-
-constexpr double kFeasibleSecurityParameter = 40;
-constexpr double kUnfeasibleSecurityParameter = 95;
-constexpr int kNumSamples = 5;
-
-template <typename T>
-class IntModNTest : public testing::Test {};
-using IntModNTypes = ::testing::Types<
-    IntModN<uint32_t, 4294967291u>,             //  2**32-5
-    IntModN<uint64_t, 18446744073709551557ull>  //  2**64-59
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-    ,
-    IntModN<absl::uint128, (unsigned __int128)(absl::MakeUint128(
-                               65535u, 18446744073709551551ull))>  // 2**80-65
-#endif
-    >;
-TYPED_TEST_SUITE(IntModNTest, IntModNTypes);
-
-TYPED_TEST(IntModNTest, DefaultValueIsZero) {
-  TypeParam a;
-  EXPECT_EQ(a.value(), 0);
-}
-
-TYPED_TEST(IntModNTest, SetValueWorks) {
-  TypeParam a;
-  EXPECT_EQ(a.value(), 0);
-  a = 23;
-  EXPECT_EQ(a.value(), 23);
-}
-
-TYPED_TEST(IntModNTest, AdditionWithoutWrapAroundWorks) {
-  TypeParam a;
-  TypeParam b;
-  a += b;
-  EXPECT_EQ(a.value(), 0);
-  b = 23;
-  a += b;
-  EXPECT_EQ(a.value(), 23);
-  b = 4294967200;
-  a += b;
-  EXPECT_EQ(a.value(), 4294967223);
-}
-
-TYPED_TEST(IntModNTest, AdditionWithWrapAroundWorks) {
-  TypeParam a;
-  TypeParam b;
-  a += b;
-  EXPECT_EQ(a.value(), 0);
-  b = 23;
-  a += b;
-  EXPECT_EQ(a.value(), 23);
-  b = TypeParam::modulus() - 10;
-  a += b;
-  EXPECT_EQ(a.value(), 13);
-}
-
-TYPED_TEST(IntModNTest, NegationWorks) {
-  TypeParam a(10);
-  TypeParam b = -a;
-  EXPECT_EQ(a + b, TypeParam(0));
-}
-
-TYPED_TEST(IntModNTest, GetNumBytesRequiredFailsIfUnfeasible) {
-  absl::StatusOr<int> result =
-      TypeParam::GetNumBytesRequired(kNumSamples, kUnfeasibleSecurityParameter);
-  EXPECT_THAT(result, dpf_internal::StatusIs(
-                          absl::StatusCode::kInvalidArgument,
-                          testing::StartsWith(absl::StrFormat(
-                              "For num_samples = 5 and kModulus = %d",
-                              absl::uint128(TypeParam::modulus())))));
-}
-
-TYPED_TEST(IntModNTest, GetNumBytesRequiredSucceedsIfFeasible) {
-  absl::StatusOr<int> result =
-      TypeParam::GetNumBytesRequired(5, kFeasibleSecurityParameter);
-  EXPECT_EQ(result.ok(), true);
-}
-
-TYPED_TEST(IntModNTest, SampleFailsIfUnfeasible) {
-  absl::StatusOr<int> r_getnum =
-      TypeParam::GetNumBytesRequired(5, kFeasibleSecurityParameter);
-  EXPECT_EQ(r_getnum.ok(), true);
-
-  std::string bytes = std::string(16, '#');
-  EXPECT_GT(r_getnum.value(), bytes.size());
-  std::vector<TypeParam> samples(5);
-  absl::Status r_sample = TypeParam::SampleFromBytes(
-      bytes, kFeasibleSecurityParameter, absl::MakeSpan(samples));
-  EXPECT_EQ(r_sample.ok(), false);
-  EXPECT_THAT(
-      r_sample,
-      dpf_internal::StatusIs(
-          absl::StatusCode::kInvalidArgument,
-          "The number of bytes provided (16) is insufficient for the required "
-          "statistical security and number of samples."));
-}
-
-TYPED_TEST(IntModNTest, SampleSucceedsIfFeasible) {
-  absl::StatusOr<int> r_getnum =
-      TypeParam::GetNumBytesRequired(5, kFeasibleSecurityParameter);
-  EXPECT_EQ(r_getnum.ok(), true);
-
-  std::string bytes = std::string(r_getnum.value(), '#');
-  std::vector<TypeParam> samples(5);
-  absl::Status r_sample = TypeParam::SampleFromBytes(
-      bytes, kFeasibleSecurityParameter, absl::MakeSpan(samples));
-  EXPECT_EQ(r_sample.ok(), true);
-}
-
-TYPED_TEST(IntModNTest, FirstEntryOfSamplesIsAsExpected) {
-  absl::StatusOr<int> r_getnum =
-      TypeParam::GetNumBytesRequired(5, kFeasibleSecurityParameter);
-  EXPECT_EQ(r_getnum.ok(), true);
-
-  std::string bytes = std::string(r_getnum.value(), '#');
-  std::vector<TypeParam> samples(5);
-  absl::Status r_sample = TypeParam::SampleFromBytes(
-      bytes, kFeasibleSecurityParameter, absl::MakeSpan(samples));
-  EXPECT_EQ(r_sample.ok(), true);
-  EXPECT_EQ(
-      samples[0].value(),
-      TypeParam::template ConvertBytesTo<absl::uint128>(bytes.substr(0, 16)) %
-          TypeParam::modulus());
-}
-
-using BaseInteger = uint32_t;
-constexpr BaseInteger kModulus32 = 4294967291u;  // 2**32 - 5
-using MyIntModN = IntModN<BaseInteger, kModulus32>;
-
-TEST(IntModNTest, SampleFromBytesWorksInConcreteExample) {
-  absl::StatusOr<int> r_getnum =
-      MyIntModN::GetNumBytesRequired(5, kFeasibleSecurityParameter);
-  EXPECT_EQ(r_getnum.ok(), true);
-  EXPECT_EQ(*r_getnum, 32);
-  std::string bytes = "this is a length 32 test string.";
-  EXPECT_EQ(bytes.size(), 32);
-
-  std::vector<MyIntModN> samples(5);
-  absl::Status r_sample = MyIntModN::SampleFromBytes(
-      bytes, kFeasibleSecurityParameter, absl::MakeSpan(samples));
-  EXPECT_EQ(r_sample.ok(), true);
-  absl::uint128 r =
-      MyIntModN::ConvertBytesTo<absl::uint128>("this is a length");
-  EXPECT_EQ(samples[0].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>(" 32 ");
-  EXPECT_EQ(samples[1].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>("test");
-  EXPECT_EQ(samples[2].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>(" str");
-  EXPECT_EQ(samples[3].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>("ing.");
-  EXPECT_EQ(samples[4].value(), r % MyIntModN::modulus());
-}
-
-TEST(IntModNTest, SampleFromBytesFailsAsExpectedInConcreteExample) {
-  absl::StatusOr<int> r_getnum =
-      MyIntModN::GetNumBytesRequired(5, kFeasibleSecurityParameter);
-  EXPECT_EQ(r_getnum.ok(), true);
-  EXPECT_EQ(*r_getnum, 32);
-  std::string bytes = "this is a length 32 test string.";
-  EXPECT_EQ(bytes.size(), 32);
-
-  std::vector<MyIntModN> samples(5);
-  absl::Status r_sample = MyIntModN::SampleFromBytes(
-      bytes, kFeasibleSecurityParameter, absl::MakeSpan(samples));
-  EXPECT_EQ(r_sample.ok(), true);
-  absl::uint128 r =
-      MyIntModN::ConvertBytesTo<absl::uint128>("this is a length");
-  EXPECT_EQ(samples[0].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>(" 32 ");
-  EXPECT_EQ(samples[1].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>("test");
-  EXPECT_EQ(samples[2].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>(" str");
-  EXPECT_EQ(samples[3].value(), r % MyIntModN::modulus());
-  r /= MyIntModN::modulus();
-  r <<= (sizeof(MyIntModN::Base) * 8);
-  r |= MyIntModN::ConvertBytesTo<MyIntModN::Base>("ing#");  // # instead of .
-  EXPECT_NE(samples[4].value(), r % MyIntModN::modulus());
-}
-
-// Test if IntModN operators are in fact constexpr. This will fail to compile
-// otherwise.
-constexpr MyIntModN TestAddition() { return MyIntModN(2) + MyIntModN(5); }
-static_assert(TestAddition().value() == 7,
-              "constexpr addition of IntModNs incorrect");
-
-constexpr MyIntModN TestSubtraction() { return MyIntModN(5) - MyIntModN(2); }
-static_assert(TestSubtraction().value() == 3,
-              "constexpr subtraction of IntModNs incorrect");
-
-constexpr MyIntModN TestAssignment() {
-  MyIntModN x(0);
-  x = 5;
-  return x;
-}
-static_assert(TestAssignment().value() == 5,
-              "constexpr assignment to IntModN incorrect");
-
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-constexpr unsigned __int128 kModulus128 =
-    (unsigned __int128)(-1);  // 2**128 - 159
-using MyIntModN128 = IntModN<unsigned __int128, kModulus128>;
-constexpr MyIntModN128 TestAddition128() {
-  return MyIntModN128(2) + MyIntModN128(5);
-}
-static_assert(TestAddition128().value() == 7,
-              "constexpr addition of IntModNs incorrect");
-#endif
-
-}  // namespace
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/internal/BUILD b/third_party/distributed_point_functions/code/dpf/internal/BUILD
deleted file mode 100644
index cfbdc6ac..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/BUILD
+++ /dev/null
@@ -1,238 +0,0 @@
-# Copyright 2023 Google LLC
-#
-# 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.
-
-load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
-load("@com_github_google_iree//build_tools/embed_data:build_defs.bzl", "cc_embed_data")
-
-package(
-    default_visibility = ["//:__subpackages__"],
-)
-
-licenses(["notice"])
-
-cc_library(
-    name = "value_type_helpers",
-    srcs = ["value_type_helpers.cc"],
-    hdrs = ["value_type_helpers.h"],
-    deps = [
-        "//dpf:distributed_point_function_cc_proto",
-        "//dpf:int_mod_n",
-        "//dpf:status_macros",
-        "//dpf:tuple",
-        "//dpf:xor_wrapper",
-        "@com_google_absl//absl/base:config",
-        "@com_google_absl//absl/log:absl_check",
-        "@com_google_absl//absl/meta:type_traits",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/strings:str_format",
-        "@com_google_absl//absl/utility",
-        "@com_google_protobuf//:protobuf_lite",
-    ],
-)
-
-cc_test(
-    name = "value_type_helpers_test",
-    srcs = ["value_type_helpers_test.cc"],
-    deps = [
-        ":status_matchers",
-        ":value_type_helpers",
-        "//dpf:distributed_point_function_cc_proto",
-        "//dpf:int_mod_n",
-        "//dpf:tuple",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/base:config",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-    ],
-)
-
-cc_library(
-    name = "status_matchers",
-    testonly = 1,
-    srcs = [
-        "status_matchers.cc",
-    ],
-    hdrs = ["status_matchers.h"],
-    deps = [
-        "//dpf:status_macros",
-        "@com_github_google_googletest//:gtest",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-    ],
-)
-
-cc_library(
-    name = "proto_validator",
-    srcs = [
-        "proto_validator.cc",
-    ],
-    hdrs = [
-        "proto_validator.h",
-    ],
-    deps = [
-        ":value_type_helpers",
-        "//dpf:distributed_point_function_cc_proto",
-        "//dpf:status_macros",
-        "@com_google_absl//absl/container:flat_hash_map",
-        "@com_google_absl//absl/log:absl_check",
-        "@com_google_absl//absl/memory",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/strings:str_format",
-        "@com_google_absl//absl/types:span",
-        "@com_google_protobuf//:protobuf_lite",
-    ],
-)
-
-cc_embed_data(
-    name = "proto_validator_test_textproto_embed",
-    srcs = [
-        "proto_validator_test.textproto",
-    ],
-    cc_file_output = "proto_validator_test_textproto_embed.cc",
-    cpp_namespace = "distributed_point_functions::dpf_internal",
-    h_file_output = "proto_validator_test_textproto_embed.h",
-)
-
-cc_test(
-    name = "proto_validator_test",
-    srcs = [
-        "proto_validator_test.cc",
-    ],
-    data = [
-        "proto_validator_test.textproto",
-    ],
-    deps = [
-        ":proto_validator",
-        ":proto_validator_test_textproto_embed",
-        ":status_matchers",
-        "//dpf:distributed_point_function_cc_proto",
-        "//dpf:tuple",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/strings",
-        "@com_google_absl//absl/strings:str_format",
-        "@com_google_protobuf//:protobuf",
-    ],
-)
-
-cc_library(
-    name = "evaluate_prg_hwy",
-    srcs = ["evaluate_prg_hwy.cc"],
-    hdrs = ["evaluate_prg_hwy.h"],
-    deps = [
-        ":aes_128_fixed_key_hash_hwy",
-        "//dpf:aes_128_fixed_key_hash",
-        "//dpf:status_macros",
-        "@boringssl//:crypto",
-        "@com_github_google_highway//:hwy",
-        "@com_google_absl//absl/base:config",
-        "@com_google_absl//absl/base:core_headers",
-        "@com_google_absl//absl/container:inlined_vector",
-        "@com_google_absl//absl/log:absl_check",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/types:span",
-    ],
-)
-
-cc_test(
-    name = "evaluate_prg_hwy_test",
-    srcs = [
-        "evaluate_prg_hwy_test.cc",
-    ],
-    deps = [
-        ":evaluate_prg_hwy",
-        ":status_matchers",
-        "//dpf:aes_128_fixed_key_hash",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_github_google_highway//:hwy",
-        "@com_github_google_highway//:hwy_test_util",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-    ],
-)
-
-cc_library(
-    name = "get_hwy_mode",
-    srcs = ["get_hwy_mode.cc"],
-    hdrs = ["get_hwy_mode.h"],
-    deps = [
-        "@com_github_google_highway//:hwy",
-        "@com_google_absl//absl/strings",
-    ],
-)
-
-cc_library(
-    name = "aes_128_fixed_key_hash_hwy",
-    hdrs = [
-        "aes_128_fixed_key_hash_hwy.h",
-    ],
-    deps = [
-        "@com_github_google_highway//:hwy",
-        "@com_google_absl//absl/numeric:int128",
-    ],
-)
-
-cc_library(
-    name = "maybe_deref_span",
-    hdrs = ["maybe_deref_span.h"],
-    deps = [
-        "@com_google_absl//absl/meta:type_traits",
-        "@com_google_absl//absl/types:span",
-        "@com_google_absl//absl/types:variant",
-    ],
-)
-
-cc_test(
-    name = "aes_128_fixed_key_hash_hwy_test",
-    srcs = [
-        "aes_128_fixed_key_hash_hwy_test.cc",
-    ],
-    deps = [
-        ":aes_128_fixed_key_hash_hwy",
-        ":get_hwy_mode",
-        ":status_matchers",
-        "//dpf:aes_128_fixed_key_hash",
-        "@boringssl//:crypto",
-        "@com_github_google_googletest//:gtest_main",
-        "@com_github_google_highway//:hwy",
-        "@com_github_google_highway//:hwy_test_util",
-        "@com_google_absl//absl/flags:parse",
-        "@com_google_absl//absl/log:absl_log",
-        "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
-        "@com_google_absl//absl/types:span",
-    ],
-)
-
-cc_test(
-    name = "maybe_deref_span_test",
-    srcs = ["maybe_deref_span_test.cc"],
-    deps = [
-        ":maybe_deref_span",
-        "@com_github_google_googletest//:gtest_main",
-    ],
-)
diff --git a/third_party/distributed_point_functions/code/dpf/internal/aes_128_fixed_key_hash_hwy.h b/third_party/distributed_point_functions/code/dpf/internal/aes_128_fixed_key_hash_hwy.h
deleted file mode 100644
index 3d1f8ec6..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/aes_128_fixed_key_hash_hwy.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-// Highway-specific include guard, ensuring the header can get included once per
-// target architecture.
-#if defined(                                                                   \
-    DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_HWY_H_) == \
-    defined(HWY_TARGET_TOGGLE)
-#ifdef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_HWY_H_
-#undef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_HWY_H_
-#else
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_HWY_H_
-#endif
-
-#include <limits>
-
-#include "absl/numeric/int128.h"
-#include "hwy/highway.h"
-
-HWY_BEFORE_NAMESPACE();
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace HWY_NAMESPACE {
-
-// There is no AES support on HWY_SCALAR, but we still want to be able to
-// include this header when compiling for HWY_SCALAR. The caller has to make
-// sure to only call the functions defined here when not on HWY_SCALAR.
-#if HWY_TARGET != HWY_SCALAR
-
-namespace hn = hwy::HWY_NAMESPACE;
-
-constexpr int kAesBlockSize = 16;
-
-// Helper to convert a Highway tag to a tag for vectors of the same bit size,
-// but with 64-bit lanes.
-template <typename D>
-constexpr auto To64(D d) {
-  return hn::Repartition<uint64_t, D>();
-}
-
-// The following macros define parts of the fixed-key AES hash function
-// implementation. We use macros here since Highway doesn't allow creating
-// arrays of vectors/SIMD registers. That way, we can access each register by a
-// unique variable name. All inputs and outputs are assumed to be of type
-// hn::ScalableTag<uint8_t>.
-
-// Loads the AES round key for the given round and key_index.
-#define DPF_AES_LOAD_ROUND_KEY(key_index, round) \
-  const auto round_##round##_key_##key_index =   \
-      hn::LoadDup128(d, round_keys_##key_index + kAesBlockSize * round);
-
-// Selects key_0 or key_1 for the given block_index and round, depending on the
-// bits in `mask`. Keys are first converted to 64-bit vectors to apply the more
-// efficient 64 bit masks.
-#define DPF_AES_SELECT_KEY(block_index, round)                         \
-  const auto selected_round_##round##_key_##block_index = hn::BitCast( \
-      d, hn::IfThenElse(mask_##block_index,                            \
-                        hn::BitCast(To64(d), round_##round##_key_1),   \
-                        hn::BitCast(To64(d), round_##round##_key_0)));
-
-// Load mask for computing {0, x.high64}, for computing sigma(x) below.
-HWY_ALIGN constexpr absl::uint128 kSigmaMask =
-    absl::MakeUint128(std::numeric_limits<uint64_t>::max(), 0);
-#define DPF_AES_LOAD_SIGMA_MASK() \
-  const auto sigma_mask =         \
-      hn::LoadDup128(To64(d), reinterpret_cast<const uint64_t*>(&kSigmaMask));
-
-// Compute sigma(x) = {x.high64, x.high64^x.low64} (in little-endian notation).
-#define DPF_AES_COMPUTE_SIGMA(block_index)                                   \
-  const auto in_##block_index##_64 = hn::BitCast(To64(d), in_##block_index); \
-  const auto sigma_##block_index =                                           \
-      hn::BitCast(d, hn::Xor(hn::Shuffle01(in_##block_index##_64),           \
-                             hn::And(sigma_mask, in_##block_index##_64)));
-
-// Performs the first round of AES for the given block_index, using sigma as the
-// input.
-#define DPF_AES_FIRST_ROUND(block_index) \
-  out_##block_index =                    \
-      hn::Xor(sigma_##block_index, selected_round_0_key_##block_index)
-
-// Performs a middle round of AES for the given block_index.
-#define DPF_AES_MIDDLE_ROUND(block_index, round) \
-  out_##block_index = hn::AESRound(              \
-      out_##block_index, selected_round_##round##_key_##block_index);
-
-// Performs the last round of AES for the given block_index.
-#define DPF_AES_LAST_ROUND(block_index)                   \
-  out_##block_index = hn::AESLastRound(out_##block_index, \
-                                       selected_round_10_key_##block_index);
-
-// Finalize the hash by XORing with sigma.
-#define DPF_AES_FINALIZE_HASH(block_index) \
-  out_##block_index = hn::Xor(out_##block_index, sigma_##block_index);
-
-// Helper macro for hashing a single vector.
-#define DPF_AES_MIDDLE_ROUND_1(round) \
-  DPF_AES_LOAD_ROUND_KEY(0, round);   \
-  DPF_AES_LOAD_ROUND_KEY(1, round);   \
-  DPF_AES_SELECT_KEY(0, round);       \
-  DPF_AES_MIDDLE_ROUND(0, round);
-
-// Hashes a vector `in_0`, writing the output to `out_0`. Each block is hashed
-// using either `round_keys_0` or `round_keys_1`, which both must point to a
-// byte array containing two expanded AES keys. Which key is used for each block
-// depends on `mask_0`: If the mask 0, then `round_keys_0` is used, otherwise
-// `round_keys_1`. Note that the masks are masks on 64 bit integers, so there
-// are two mask bits per AES block. The caller is responsible for making sure
-// that the masks for the two halves of any given block have the same value.
-template <typename V, typename D, typename M>
-void HashOneWithKeyMask(D d, V in_0, M mask_0,
-                        const uint8_t* HWY_RESTRICT round_keys_0,
-                        const uint8_t* HWY_RESTRICT round_keys_1, V& out_0) {
-  // Compute sigma(in_0)
-  DPF_AES_LOAD_SIGMA_MASK();
-  DPF_AES_COMPUTE_SIGMA(0);
-
-  // First AES round.
-  DPF_AES_LOAD_ROUND_KEY(0, 0);
-  DPF_AES_LOAD_ROUND_KEY(1, 0);
-  DPF_AES_SELECT_KEY(0, 0);
-  DPF_AES_FIRST_ROUND(0);
-
-  // Middle AES rounds.
-  DPF_AES_MIDDLE_ROUND_1(1);
-  DPF_AES_MIDDLE_ROUND_1(2);
-  DPF_AES_MIDDLE_ROUND_1(3);
-  DPF_AES_MIDDLE_ROUND_1(4);
-  DPF_AES_MIDDLE_ROUND_1(5);
-  DPF_AES_MIDDLE_ROUND_1(6);
-  DPF_AES_MIDDLE_ROUND_1(7);
-  DPF_AES_MIDDLE_ROUND_1(8);
-  DPF_AES_MIDDLE_ROUND_1(9);
-
-  // Last AES round.
-  DPF_AES_LOAD_ROUND_KEY(0, 10);
-  DPF_AES_LOAD_ROUND_KEY(1, 10);
-  DPF_AES_SELECT_KEY(0, 10)
-  DPF_AES_LAST_ROUND(0);
-
-  // Finalize hash.
-  DPF_AES_FINALIZE_HASH(0);
-}
-
-// Helper macros for hashing four vectors in parallel.
-#define DPF_AES_SELECT_KEY_4(round) \
-  DPF_AES_SELECT_KEY(0, round);     \
-  DPF_AES_SELECT_KEY(1, round);     \
-  DPF_AES_SELECT_KEY(2, round);     \
-  DPF_AES_SELECT_KEY(3, round);
-#define DPF_AES_MIDDLE_ROUND_4(round) \
-  DPF_AES_LOAD_ROUND_KEY(0, round);   \
-  DPF_AES_LOAD_ROUND_KEY(1, round);   \
-  DPF_AES_SELECT_KEY_4(round);        \
-  DPF_AES_MIDDLE_ROUND(0, round);     \
-  DPF_AES_MIDDLE_ROUND(1, round);     \
-  DPF_AES_MIDDLE_ROUND(2, round);     \
-  DPF_AES_MIDDLE_ROUND(3, round);
-
-// Hashes four vectors `in_0, ..., in_3`, writing the results to `out_0, ...,
-// out_3`. This improves pipelining of AES instructions, and improves
-// performance by about 10%. Each block is hashed using either `round_keys_0` or
-// `round_keys_1`, which both must point to a byte array containing two expanded
-// AES keys. Which key is used for each block depends on `mask_0, ... mask_3`:
-// If the mask 0, then `round_keys_0` is used, otherwise `round_keys_1`. Note
-// that the masks are masks on 64 bit integers, so there are two mask bits per
-// AES block. The caller is responsible for making sure that the masks for the
-// two halves of any given block have the same value.
-template <typename V, typename D, typename M>
-void HashFourWithKeyMask(D d, V in_0, V in_1, V in_2, V in_3, M mask_0,
-                         M mask_1, M mask_2, M mask_3,
-                         const uint8_t* HWY_RESTRICT round_keys_0,
-                         const uint8_t* HWY_RESTRICT round_keys_1, V& out_0,
-                         V& out_1, V& out_2, V& out_3) {
-  // Compute sigma(in_0), ..., sigma(in_3)
-  DPF_AES_LOAD_SIGMA_MASK();
-  DPF_AES_COMPUTE_SIGMA(0);
-  DPF_AES_COMPUTE_SIGMA(1);
-  DPF_AES_COMPUTE_SIGMA(2);
-  DPF_AES_COMPUTE_SIGMA(3);
-
-  // First AES round.
-  DPF_AES_LOAD_ROUND_KEY(0, 0);
-  DPF_AES_LOAD_ROUND_KEY(1, 0);
-  DPF_AES_SELECT_KEY_4(0)
-  DPF_AES_FIRST_ROUND(0);
-  DPF_AES_FIRST_ROUND(1);
-  DPF_AES_FIRST_ROUND(2);
-  DPF_AES_FIRST_ROUND(3);
-
-  // Middle AES rounds.
-  DPF_AES_MIDDLE_ROUND_4(1);
-  DPF_AES_MIDDLE_ROUND_4(2);
-  DPF_AES_MIDDLE_ROUND_4(3);
-  DPF_AES_MIDDLE_ROUND_4(4);
-  DPF_AES_MIDDLE_ROUND_4(5);
-  DPF_AES_MIDDLE_ROUND_4(6);
-  DPF_AES_MIDDLE_ROUND_4(7);
-  DPF_AES_MIDDLE_ROUND_4(8);
-  DPF_AES_MIDDLE_ROUND_4(9);
-
-  // Last AES round.
-  DPF_AES_LOAD_ROUND_KEY(0, 10);
-  DPF_AES_LOAD_ROUND_KEY(1, 10);
-  DPF_AES_SELECT_KEY_4(10)
-  DPF_AES_LAST_ROUND(0);
-  DPF_AES_LAST_ROUND(1);
-  DPF_AES_LAST_ROUND(2);
-  DPF_AES_LAST_ROUND(3);
-
-  // Finalize hash.
-  DPF_AES_FINALIZE_HASH(0);
-  DPF_AES_FINALIZE_HASH(1);
-  DPF_AES_FINALIZE_HASH(2);
-  DPF_AES_FINALIZE_HASH(3);
-}
-
-#endif  // HWY_TARGET != HWY_SCALAR
-
-}  // namespace HWY_NAMESPACE
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-HWY_AFTER_NAMESPACE();
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_AES_128_FIXED_KEY_HASH_HWY_H_
diff --git a/third_party/distributed_point_functions/code/dpf/internal/aes_128_fixed_key_hash_hwy_test.cc b/third_party/distributed_point_functions/code/dpf/internal/aes_128_fixed_key_hash_hwy_test.cc
deleted file mode 100644
index d581e11..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/aes_128_fixed_key_hash_hwy_test.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include <limits>
-#include <memory>
-#include <vector>
-
-#include "absl/flags/parse.h"
-#include "absl/log/absl_log.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/types/span.h"
-#include "dpf/aes_128_fixed_key_hash.h"
-#include "dpf/internal/get_hwy_mode.h"
-#include "dpf/internal/status_matchers.h"
-#include "gtest/gtest.h"
-#include "hwy/aligned_allocator.h"
-#include "hwy/detect_targets.h"
-#include "openssl/aes.h"
-
-// clang-format off
-#define HWY_IS_TEST 1
-#undef HWY_TARGET_INCLUDE
-#define HWY_TARGET_INCLUDE "dpf/internal/aes_128_fixed_key_hash_hwy_test.cc"  // NOLINT
-#include "hwy/foreach_target.h"
-// clang-format on
-
-#include "dpf/internal/aes_128_fixed_key_hash_hwy.h"
-#include "hwy/highway.h"
-#include "hwy/tests/test_util-inl.h"
-
-HWY_BEFORE_NAMESPACE();
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace HWY_NAMESPACE {
-
-#if HWY_TARGET == HWY_SCALAR
-
-void TestAllAes() {
-  return;  // HWY_SCALAR doesn't support AES instructions, so nothing to test.
-}
-
-#else
-
-namespace hn = hwy::HWY_NAMESPACE;
-
-constexpr absl::uint128 kKey0 =
-    absl::MakeUint128(0x0000000000000000, 0x0000000000000000);
-constexpr absl::uint128 kKey1 =
-    absl::MakeUint128(0x1111111111111111, 0x1111111111111111);
-constexpr int kNumBlocks = 128;  // Must be divisible by (4 * hn::Lanes(d)).
-constexpr int kNumBytes = kNumBlocks * sizeof(absl::uint128);
-
-class TestOutputMatchesOpenSSL {
- public:
-  template <typename T, typename D>
-  HWY_NOINLINE void operator()(T /*unused*/, D d) {
-    Reset();
-    EvaluateOne(d);
-    CheckResult();
-    Reset();
-    EvaluateFour(d);
-    CheckResult();
-  }
-
- private:
-  void Reset() {
-    inputs_ = hwy::AllocateAligned<absl::uint128>(kNumBlocks);
-    ASSERT_NE(inputs_, nullptr);
-    masks_ = hwy::AllocateAligned<uint64_t>(2 * kNumBlocks);
-    ASSERT_NE(masks_, nullptr);
-    for (int i = 0; i < kNumBlocks; ++i) {
-      inputs_[i] = absl::MakeUint128(i, i + 1);
-      masks_[2 * i] = masks_[2 * i + 1] =
-          (i % 3 == 0) ? std::numeric_limits<uint64_t>::max() : 0;
-    }
-    outputs_ = hwy::AllocateAligned<absl::uint128>(kNumBlocks);
-    ASSERT_NE(outputs_, nullptr);
-    ASSERT_EQ(0, AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(&kKey0),
-                                     128, &expanded_key_0_));
-    ASSERT_EQ(0, AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(&kKey1),
-                                     128, &expanded_key_1_));
-    input_ptr_ = reinterpret_cast<const uint8_t*>(inputs_.get());
-    output_ptr_ = reinterpret_cast<uint8_t*>(outputs_.get());
-  }
-
-  void CheckResult() {
-    // Check the result by comparing with OpenSSL-based AES hash.
-    DPF_ASSERT_OK_AND_ASSIGN(
-        distributed_point_functions::Aes128FixedKeyHash hash_0,
-        distributed_point_functions::Aes128FixedKeyHash::Create(kKey0));
-    DPF_ASSERT_OK_AND_ASSIGN(
-        distributed_point_functions::Aes128FixedKeyHash hash_1,
-        distributed_point_functions::Aes128FixedKeyHash::Create(kKey1));
-    std::vector<absl::uint128> wanted_0(kNumBlocks), wanted_1(kNumBlocks);
-    DPF_ASSERT_OK(
-        hash_0.Evaluate(absl::MakeConstSpan(inputs_.get(), kNumBlocks),
-                        absl::MakeSpan(wanted_0)));
-    DPF_ASSERT_OK(
-        hash_1.Evaluate(absl::MakeConstSpan(inputs_.get(), kNumBlocks),
-                        absl::MakeSpan(wanted_1)));
-    for (int i = 0; i < kNumBlocks; ++i) {
-      if (i % 3 == 0) {
-        EXPECT_EQ(wanted_1[i], outputs_.get()[i]) << "i=" << i;
-      } else {
-        EXPECT_EQ(wanted_0[i], outputs_.get()[i]) << "i=" << i;
-      }
-    }
-  }
-
-  template <typename D>
-  void EvaluateOne(D d) {
-    hn::Repartition<uint64_t, D> d64;
-    for (int i = 0; i + hn::Lanes(d) <= kNumBytes; i += hn::Lanes(d)) {
-      const auto in = hn::Load(d, input_ptr_ + i);
-      const auto mask =
-          hn::MaskFromVec(hn::Load(d64, masks_.get() + i / sizeof(uint64_t)));
-      auto out = hn::Undefined(d);
-      HashOneWithKeyMask(
-          d, in, mask, reinterpret_cast<const uint8_t*>(expanded_key_0_.rd_key),
-          reinterpret_cast<const uint8_t*>(expanded_key_1_.rd_key), out);
-      hn::Store(out, d, output_ptr_ + i);
-    }
-  }
-
-  template <typename D>
-  void EvaluateFour(D d) {
-    hn::Repartition<uint64_t, D> d64;
-    // Evaluate four vectors at once. Assumes kNumBytes is divisible by (4 *
-    // hn::Lanes(d)).
-    for (int i = 0; i < kNumBytes; i += 4 * hn::Lanes(d)) {
-      const auto in_0 = hn::Load(d, input_ptr_ + i);
-      const auto in_1 = hn::Load(d, input_ptr_ + i + 1 * hn::Lanes(d));
-      const auto in_2 = hn::Load(d, input_ptr_ + i + 2 * hn::Lanes(d));
-      const auto in_3 = hn::Load(d, input_ptr_ + i + 3 * hn::Lanes(d));
-      const auto mask_0 =
-          hn::MaskFromVec(hn::Load(d64, masks_.get() + i / sizeof(uint64_t)));
-      const auto mask_1 = hn::MaskFromVec(hn::Load(
-          d64, masks_.get() + (i + 1 * hn::Lanes(d)) / sizeof(uint64_t)));
-      const auto mask_2 = hn::MaskFromVec(hn::Load(
-          d64, masks_.get() + (i + 2 * hn::Lanes(d)) / sizeof(uint64_t)));
-      const auto mask_3 = hn::MaskFromVec(hn::Load(
-          d64, masks_.get() + (i + 3 * hn::Lanes(d)) / sizeof(uint64_t)));
-      auto out_0 = hn::Undefined(d);
-      auto out_1 = hn::Undefined(d);
-      auto out_2 = hn::Undefined(d);
-      auto out_3 = hn::Undefined(d);
-      HashFourWithKeyMask(
-          d, in_0, in_1, in_2, in_3, mask_0, mask_1, mask_2, mask_3,
-          reinterpret_cast<const uint8_t*>(expanded_key_0_.rd_key),
-          reinterpret_cast<const uint8_t*>(expanded_key_1_.rd_key), out_0,
-          out_1, out_2, out_3);
-      hn::Store(out_0, d, output_ptr_ + i);
-      hn::Store(out_1, d, output_ptr_ + i + 1 * hn::Lanes(d));
-      hn::Store(out_2, d, output_ptr_ + i + 2 * hn::Lanes(d));
-      hn::Store(out_3, d, output_ptr_ + i + 3 * hn::Lanes(d));
-    }
-
-    // Check the result by comparing with OpenSSL-based AES hash.
-    DPF_ASSERT_OK_AND_ASSIGN(
-        distributed_point_functions::Aes128FixedKeyHash hash_0,
-        distributed_point_functions::Aes128FixedKeyHash::Create(kKey0));
-    DPF_ASSERT_OK_AND_ASSIGN(
-        distributed_point_functions::Aes128FixedKeyHash hash_1,
-        distributed_point_functions::Aes128FixedKeyHash::Create(kKey1));
-    std::vector<absl::uint128> wanted_0(kNumBlocks), wanted_1(kNumBlocks);
-    DPF_ASSERT_OK(
-        hash_0.Evaluate(absl::MakeConstSpan(inputs_.get(), kNumBlocks),
-                        absl::MakeSpan(wanted_0)));
-    DPF_ASSERT_OK(
-        hash_1.Evaluate(absl::MakeConstSpan(inputs_.get(), kNumBlocks),
-                        absl::MakeSpan(wanted_1)));
-    for (int i = 0; i < kNumBlocks; ++i) {
-      if (i % 3 == 0) {
-        EXPECT_EQ(wanted_1[i], outputs_.get()[i]) << "i=" << i;
-      } else {
-        EXPECT_EQ(wanted_0[i], outputs_.get()[i]) << "i=" << i;
-      }
-    }
-  }
-
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> inputs_, outputs_;
-  hwy::AlignedFreeUniquePtr<uint64_t[]> masks_;
-  const uint8_t* input_ptr_;
-  uint8_t* output_ptr_;
-  HWY_ALIGN AES_KEY expanded_key_0_, expanded_key_1_;
-};
-
-void TestAllAes() {
-  hn::ForGE128Vectors<TestOutputMatchesOpenSSL>()(uint8_t{0});
-}
-
-#endif  // HWY_TARGET == HWY_SCALAR
-
-}  // namespace HWY_NAMESPACE
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-HWY_AFTER_NAMESPACE();
-
-#if HWY_ONCE
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-HWY_BEFORE_TEST(Aes128FixedKeyHashHwyTest);
-HWY_EXPORT_AND_TEST_P(Aes128FixedKeyHashHwyTest, TestAllAes);
-
-TEST(Aes128FixedKeyHashHwy, LogHwyMode) {
-  ABSL_LOG(INFO) << "Highway is in " << GetHwyModeAsString() << " mode";
-}
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-
-  return RUN_ALL_TESTS();
-}
-
-#endif
diff --git a/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy.cc b/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy.cc
deleted file mode 100644
index f1e9ced6..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy.cc
+++ /dev/null
@@ -1,662 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/internal/evaluate_prg_hwy.h"
-
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "absl/base/config.h"
-#include "absl/base/optimization.h"
-#include "absl/container/inlined_vector.h"
-#include "absl/log/absl_check.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/types/span.h"
-#include "dpf/aes_128_fixed_key_hash.h"
-#include "dpf/status_macros.h"
-#include "hwy/aligned_allocator.h"
-#include "openssl/aes.h"
-
-// clang-format off
-#undef HWY_TARGET_INCLUDE
-#define HWY_TARGET_INCLUDE "dpf/internal/evaluate_prg_hwy.cc"
-#include "hwy/foreach_target.h"
-// clang-format on
-
-#include "dpf/internal/aes_128_fixed_key_hash_hwy.h"
-#include "hwy/highway.h"
-
-HWY_BEFORE_NAMESPACE();
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace HWY_NAMESPACE {
-
-namespace hn = hwy::HWY_NAMESPACE;
-
-#if HWY_TARGET == HWY_SCALAR
-
-absl::Status EvaluateSeedsHwy(
-    int64_t num_seeds, int num_levels, const absl::uint128* seeds_in,
-    const bool* control_bits_in, const absl::uint128* paths,
-    const absl::uint128* correction_seeds, const bool* correction_controls_left,
-    const bool* correction_controls_right, const Aes128FixedKeyHash& prg_left,
-    const Aes128FixedKeyHash& prg_right, absl::uint128* seeds_out,
-    bool* control_bits_out) {
-  return EvaluateSeedsNoHwy(num_seeds, num_levels, seeds_in, control_bits_in,
-                            paths, correction_seeds, correction_controls_left,
-                            correction_controls_right, prg_left, prg_right,
-                            seeds_out, control_bits_out);
-}
-
-#else
-
-// Converts a bool array to a block-level mask suitable for vectors described by
-// `d`. The mask value for each integer in the i-th block is set to input[i].
-// If `max_blocks > 0`, returns after reading `max_blocks` bools from `input`.
-template <typename D>
-auto MaskFromBools(D d, const bool* input, int max_blocks = 0) {
-  using T = hn::TFromD<D>;
-  constexpr size_t ints_per_block = sizeof(absl::uint128) / sizeof(T);
-  constexpr int buffer_size = std::max(HWY_MAX_BYTES / 8, 64);
-  uint8_t mask_bits[buffer_size] = {0};
-  for (int i = 0; i < hn::Lanes(d); ++i) {
-    int block_idx = i / ints_per_block;
-    if (max_blocks > 0 && block_idx >= max_blocks) {
-      break;
-    }
-    if (input[block_idx]) {
-      mask_bits[i / 8] |= uint8_t{1} << (i % 8);
-    }
-  }
-  return hn::LoadMaskBits(d, mask_bits);
-}
-
-// Converts a mask for types `d` to a bool array. Assumes that the mask value
-// for all integers in the i-th block is equal, and writes that value to
-// output[i]. If `max_blocks > 0`, returns after writing `max_blocks` bools to
-// `output`.
-template <typename D, typename M>
-void BoolsFromMask(D d, M mask, bool* output, int max_blocks = 0) {
-  using T = hn::TFromD<D>;
-  constexpr size_t ints_per_block = sizeof(absl::uint128) / sizeof(T);
-  int num_outputs = hn::Lanes(d) / ints_per_block;
-  if (max_blocks > 0) {
-    num_outputs = max_blocks;
-  }
-  constexpr int buffer_size = std::max(HWY_MAX_BYTES / 8, 64);
-  uint8_t mask_bits[buffer_size] = {0};
-  hn::StoreMaskBits(d, mask, mask_bits);
-  for (int i = 0; i < num_outputs; ++i) {
-    int mask_idx = i * ints_per_block;
-    output[i] = (mask_bits[mask_idx / 8] & (uint8_t{1} << (mask_idx % 8))) != 0;
-  }
-}
-
-template <typename M>
-M IfThenElseMask(M condition, M true_value, M false_value) {
-  return hn::Or(hn::And(condition, true_value),
-                hn::And(hn::Not(condition), false_value));
-}
-
-// Returns a mask that is `true` on all blocks where `input[i] & (1 << index)`
-// is nonzero. The mask is a 64-bit-level mask, suitable for AES hashing.
-template <typename V, typename D>
-auto IsBitSet(D d, const V input, int index) {
-  // First create a 128-bit block with the `index`-th bit set.
-  HWY_ALIGN absl::uint128 mask = 0;
-  if (index < 128) {
-    mask = absl::uint128{1} << index;
-  }
-
-  // Now load it into a vector of 64-bit integers. Note that every second
-  // element of that vector will be 0.
-  const hn::Repartition<uint64_t, D> d64;
-  static_assert(ABSL_IS_LITTLE_ENDIAN);
-  const auto mask_64 =
-      hn::LoadDup128(d64, reinterpret_cast<const uint64_t*>(&mask));
-
-  // Compute input AND mask_64 on 64-bit integers.
-  auto input_64 = hn::BitCast(d64, input);
-  input_64 = hn::And(input_64, mask_64);
-
-  // Take the OR of every two adjacent 64-bit integers. This ensures that each
-  // half of an 128-bit block is nonzero iff at least one half was nonzero.
-  input_64 = hn::Or(input_64, hn::Shuffle01(input_64));
-
-  // Compute a 64-bit mask that checks which integers are nonzero.
-  return hn::Ne(input_64, hn::Zero(d64));
-}
-
-// Dummy struct to get HWY_ALIGN as a number, for testing if an array of
-// absl::uint128 is aligned.
-struct HWY_ALIGN Aligned128 {
-  absl::uint128 _;
-};
-
-absl::Status EvaluateSeedsHwy(
-    int64_t num_seeds, int num_levels, int num_correction_words,
-    const absl::uint128* seeds_in, const bool* control_bits_in,
-    const absl::uint128* paths, int paths_rightshift,
-    const absl::uint128* correction_seeds, const bool* correction_controls_left,
-    const bool* correction_controls_right, const Aes128FixedKeyHash& prg_left,
-    const Aes128FixedKeyHash& prg_right, absl::uint128* seeds_out,
-    bool* control_bits_out) {
-  // Exit early if inputs are empty.
-  if (num_seeds == 0 || num_levels == 0) {
-    return absl::OkStatus();
-  }
-
-  // Check if inputs and outputs are aligned.
-  constexpr size_t kHwyAlignment = alignof(Aligned128);
-  const bool is_aligned =
-      (reinterpret_cast<uintptr_t>(seeds_in) % kHwyAlignment == 0) &&
-      (reinterpret_cast<uintptr_t>(paths) % kHwyAlignment == 0) &&
-      (reinterpret_cast<uintptr_t>(correction_seeds) % kHwyAlignment == 0) &&
-      (reinterpret_cast<uintptr_t>(seeds_out) % kHwyAlignment == 0);
-  // Vector type used throughout this function: Largest byte vector available.
-  const hn::ScalableTag<uint8_t> d8;
-  // Only run the highway version if
-  // - the inputs are aligned,
-  // - the number of bytes in a vector is at least 16, and
-  // - the number of bytes in a vector is a multiple of 16.
-  if (ABSL_PREDICT_FALSE(!is_aligned || hn::Lanes(d8) < 16 ||
-                         hn::Lanes(d8) % 16 != 0)) {
-    return EvaluateSeedsNoHwy(
-        num_seeds, num_levels, num_correction_words, seeds_in, control_bits_in,
-        paths, paths_rightshift, correction_seeds, correction_controls_left,
-        correction_controls_right, prg_left, prg_right, seeds_out,
-        control_bits_out);
-  }
-
-  // Do AES key schedule.
-  HWY_ALIGN AES_KEY expanded_key_0;
-  HWY_ALIGN AES_KEY expanded_key_1;
-  int openssl_status = AES_set_encrypt_key(
-      reinterpret_cast<const uint8_t*>(&prg_left.key()), 128, &expanded_key_0);
-  if (openssl_status != 0) {
-    return absl::InternalError("Failed to set up AES key");
-  }
-  openssl_status = AES_set_encrypt_key(
-      reinterpret_cast<const uint8_t*>(&prg_right.key()), 128, &expanded_key_1);
-  if (openssl_status != 0) {
-    return absl::InternalError("Failed to set up AES key");
-  }
-
-  // Helper variables.
-  const hn::Repartition<uint64_t, decltype(d8)> d64;
-  HWY_ALIGN absl::uint128 clear_lowest_bit_128 = ~absl::uint128{1};
-  const auto clear_lowest_bit = hn::LoadDup128(
-      d8, reinterpret_cast<const uint8_t*>(&clear_lowest_bit_128));
-  const auto mask_all_zero = hn::FirstN(d64, 0);
-  const auto mask_all_one = hn::Not(mask_all_zero);
-  const int64_t num_bytes = num_seeds * sizeof(absl::uint128);
-  const int bytes_per_vec = hn::Lanes(d8);
-  const int blocks_per_vec = bytes_per_vec / sizeof(absl::uint128);
-  const int64_t correction_words_per_level = num_correction_words / num_levels;
-
-  // Pointer aliases for reading and writing data.
-  const uint8_t* seeds_in_ptr = reinterpret_cast<const uint8_t*>(seeds_in);
-  const uint8_t* paths_ptr = reinterpret_cast<const uint8_t*>(paths);
-  uint8_t* seeds_out_ptr = reinterpret_cast<uint8_t*>(seeds_out);
-  // Four vectors at a time.
-  int64_t i = 0;
-  for (; i + 4 * bytes_per_vec <= num_bytes; i += 4 * bytes_per_vec) {
-    const int64_t start_block = i / sizeof(absl::uint128);
-    // Load initial seeds and paths into vectors.
-    auto vec_0 = hn::Load(d8, seeds_in_ptr + i);
-    auto vec_1 = hn::Load(d8, seeds_in_ptr + i + 1 * bytes_per_vec);
-    auto vec_2 = hn::Load(d8, seeds_in_ptr + i + 2 * bytes_per_vec);
-    auto vec_3 = hn::Load(d8, seeds_in_ptr + i + 3 * bytes_per_vec);
-    const auto path_0 = hn::Load(d8, paths_ptr + i);
-    const auto path_1 = hn::Load(d8, paths_ptr + i + 1 * bytes_per_vec);
-    const auto path_2 = hn::Load(d8, paths_ptr + i + 2 * bytes_per_vec);
-    const auto path_3 = hn::Load(d8, paths_ptr + i + 3 * bytes_per_vec);
-    auto control_mask_0 = MaskFromBools(d64, control_bits_in + start_block);
-    auto control_mask_1 =
-        MaskFromBools(d64, control_bits_in + start_block + 1 * blocks_per_vec);
-    auto control_mask_2 =
-        MaskFromBools(d64, control_bits_in + start_block + 2 * blocks_per_vec);
-    auto control_mask_3 =
-        MaskFromBools(d64, control_bits_in + start_block + 3 * blocks_per_vec);
-    for (int j = 0; j < num_levels; ++j) {
-      // Convert path bits to masks and evaluate PRG.
-      const int bit_index = num_levels - j - 1 + paths_rightshift;
-      const auto path_mask_0 = IsBitSet(d8, path_0, bit_index);
-      const auto path_mask_1 = IsBitSet(d8, path_1, bit_index);
-      const auto path_mask_2 = IsBitSet(d8, path_2, bit_index);
-      const auto path_mask_3 = IsBitSet(d8, path_3, bit_index);
-      HashFourWithKeyMask(
-          d8, vec_0, vec_1, vec_2, vec_3, path_mask_0, path_mask_1, path_mask_2,
-          path_mask_3, reinterpret_cast<const uint8_t*>(expanded_key_0.rd_key),
-          reinterpret_cast<const uint8_t*>(expanded_key_1.rd_key), vec_0, vec_1,
-          vec_2, vec_3);
-
-      // Apply correction.
-      if (correction_words_per_level == 1) {
-        const auto correction_seed = hn::LoadDup128(
-            d64, reinterpret_cast<const uint64_t*>(correction_seeds + j));
-        vec_0 = hn::Xor(vec_0,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_0,
-                                                           correction_seed)));
-        vec_1 = hn::Xor(vec_1,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_1,
-                                                           correction_seed)));
-        vec_2 = hn::Xor(vec_2,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_2,
-                                                           correction_seed)));
-        vec_3 = hn::Xor(vec_3,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_3,
-                                                           correction_seed)));
-      } else {  // correction_words_per_level == num_seeds.
-        const uint8_t* correction_seeds_ptr = reinterpret_cast<const uint8_t*>(
-            correction_seeds + j * correction_words_per_level);
-        hn::Vec<decltype(d64)> correction_seed_0, correction_seed_1,
-            correction_seed_2, correction_seed_3;
-        if (ABSL_PREDICT_TRUE(
-                correction_words_per_level % blocks_per_vec == 0 || j == 0)) {
-          correction_seed_0 =
-              hn::BitCast(d64, hn::Load(d8, correction_seeds_ptr + i));
-          correction_seed_1 = hn::BitCast(
-              d64, hn::Load(d8, correction_seeds_ptr + i + 1 * bytes_per_vec));
-          correction_seed_2 = hn::BitCast(
-              d64, hn::Load(d8, correction_seeds_ptr + i + 2 * bytes_per_vec));
-          correction_seed_3 = hn::BitCast(
-              d64, hn::Load(d8, correction_seeds_ptr + i + 3 * bytes_per_vec));
-        } else {
-          correction_seed_0 =
-              hn::BitCast(d64, hn::LoadU(d8, correction_seeds_ptr + i));
-          correction_seed_1 = hn::BitCast(
-              d64, hn::LoadU(d8, correction_seeds_ptr + i + 1 * bytes_per_vec));
-          correction_seed_2 = hn::BitCast(
-              d64, hn::LoadU(d8, correction_seeds_ptr + i + 2 * bytes_per_vec));
-          correction_seed_3 = hn::BitCast(
-              d64, hn::LoadU(d8, correction_seeds_ptr + i + 3 * bytes_per_vec));
-        }
-        vec_0 = hn::Xor(vec_0,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_0,
-                                                           correction_seed_0)));
-        vec_1 = hn::Xor(vec_1,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_1,
-                                                           correction_seed_1)));
-        vec_2 = hn::Xor(vec_2,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_2,
-                                                           correction_seed_2)));
-        vec_3 = hn::Xor(vec_3,
-                        hn::BitCast(d8, hn::IfThenElseZero(control_mask_3,
-                                                           correction_seed_3)));
-      }
-
-      // Extract control bit for next level.
-      const auto next_control_mask_0 = IsBitSet(d8, vec_0, 0);
-      const auto next_control_mask_1 = IsBitSet(d8, vec_1, 0);
-      const auto next_control_mask_2 = IsBitSet(d8, vec_2, 0);
-      const auto next_control_mask_3 = IsBitSet(d8, vec_3, 0);
-      vec_0 = hn::And(vec_0, clear_lowest_bit);
-      vec_1 = hn::And(vec_1, clear_lowest_bit);
-      vec_2 = hn::And(vec_2, clear_lowest_bit);
-      vec_3 = hn::And(vec_3, clear_lowest_bit);
-
-      // Perform control bit correction.
-      auto correction_control_mask_0 = mask_all_zero,
-           correction_control_mask_1 = mask_all_zero,
-           correction_control_mask_2 = mask_all_zero,
-           correction_control_mask_3 = mask_all_zero;
-      if (correction_words_per_level == 1) {
-        const auto correction_control_mask_left =
-            correction_controls_left[j] ? mask_all_one : mask_all_zero;
-        const auto correction_control_mask_right =
-            correction_controls_right[j] ? mask_all_one : mask_all_zero;
-        correction_control_mask_0 =
-            IfThenElseMask(path_mask_0, correction_control_mask_right,
-                           correction_control_mask_left);
-        correction_control_mask_1 =
-            IfThenElseMask(path_mask_1, correction_control_mask_right,
-                           correction_control_mask_left);
-        correction_control_mask_2 =
-            IfThenElseMask(path_mask_2, correction_control_mask_right,
-                           correction_control_mask_left);
-        correction_control_mask_3 =
-            IfThenElseMask(path_mask_3, correction_control_mask_right,
-                           correction_control_mask_left);
-      } else {  // correction_words_per_level == num_seeds.
-        const bool* correction_controls_left_j =
-            correction_controls_left + j * correction_words_per_level +
-            start_block;
-        const bool* correction_controls_right_j =
-            correction_controls_right + j * correction_words_per_level +
-            start_block;
-        correction_control_mask_0 = IfThenElseMask(
-            path_mask_0, MaskFromBools(d64, correction_controls_right_j),
-            MaskFromBools(d64, correction_controls_left_j));
-        correction_control_mask_1 = IfThenElseMask(
-            path_mask_1,
-            MaskFromBools(d64,
-                          correction_controls_right_j + 1 * blocks_per_vec),
-            MaskFromBools(d64,
-                          correction_controls_left_j + 1 * blocks_per_vec));
-        correction_control_mask_2 = IfThenElseMask(
-            path_mask_2,
-            MaskFromBools(d64,
-                          correction_controls_right_j + 2 * blocks_per_vec),
-            MaskFromBools(d64,
-                          correction_controls_left_j + 2 * blocks_per_vec));
-        correction_control_mask_3 = IfThenElseMask(
-            path_mask_3,
-            MaskFromBools(d64,
-                          correction_controls_right_j + 3 * blocks_per_vec),
-            MaskFromBools(d64,
-                          correction_controls_left_j + 3 * blocks_per_vec));
-      }
-
-      control_mask_0 =
-          hn::Xor(next_control_mask_0,
-                  (hn::And(control_mask_0, correction_control_mask_0)));
-      control_mask_1 =
-          hn::Xor(next_control_mask_1,
-                  (hn::And(control_mask_1, correction_control_mask_1)));
-      control_mask_2 =
-          hn::Xor(next_control_mask_2,
-                  (hn::And(control_mask_2, correction_control_mask_2)));
-      control_mask_3 =
-          hn::Xor(next_control_mask_3,
-                  (hn::And(control_mask_3, correction_control_mask_3)));
-    }
-    // Write the evaluated outputs to memory.
-    hn::Store(vec_0, d8, seeds_out_ptr + i);
-    hn::Store(vec_1, d8, seeds_out_ptr + i + 1 * bytes_per_vec);
-    hn::Store(vec_2, d8, seeds_out_ptr + i + 2 * bytes_per_vec);
-    hn::Store(vec_3, d8, seeds_out_ptr + i + 3 * bytes_per_vec);
-    BoolsFromMask(d64, control_mask_0, control_bits_out + start_block);
-    BoolsFromMask(d64, control_mask_1,
-                  control_bits_out + start_block + 1 * blocks_per_vec);
-    BoolsFromMask(d64, control_mask_2,
-                  control_bits_out + start_block + 2 * blocks_per_vec);
-    BoolsFromMask(d64, control_mask_3,
-                  control_bits_out + start_block + 3 * blocks_per_vec);
-  }
-  ABSL_DCHECK_GT(i + 4 * bytes_per_vec, num_bytes);
-
-  // Single full vectors.
-  for (; i + bytes_per_vec <= num_bytes; i += bytes_per_vec) {
-    const int64_t start_block = i / sizeof(absl::uint128);
-    auto vec = hn::Load(d8, seeds_in_ptr + i);
-    const auto path = hn::Load(d8, paths_ptr + i);
-    auto control_mask = MaskFromBools(d64, control_bits_in + start_block);
-    for (int j = 0; j < num_levels; ++j) {
-      const int bit_index = num_levels - j - 1 + paths_rightshift;
-      const auto path_mask = IsBitSet(d8, path, bit_index);
-      HashOneWithKeyMask(
-          d8, vec, path_mask,
-          reinterpret_cast<const uint8_t*>(expanded_key_0.rd_key),
-          reinterpret_cast<const uint8_t*>(expanded_key_1.rd_key), vec);
-
-      // Apply correction.
-      hn::Vec<decltype(d64)> correction_seed;
-      if (correction_words_per_level == 1) {
-        correction_seed = hn::LoadDup128(
-            d64, reinterpret_cast<const uint64_t*>(correction_seeds + j));
-      } else {
-        const uint64_t* correction_seeds_ptr =
-            reinterpret_cast<const uint64_t*>(correction_seeds +
-                                              j * correction_words_per_level +
-                                              start_block);
-        if (ABSL_PREDICT_TRUE(
-                correction_words_per_level % blocks_per_vec == 0 || j == 0)) {
-          correction_seed = hn::Load(d64, correction_seeds_ptr);
-        } else {
-          correction_seed = hn::LoadU(d64, correction_seeds_ptr);
-        }
-      }
-      vec = hn::Xor(vec, hn::BitCast(d8, hn::IfThenElseZero(control_mask,
-                                                            correction_seed)));
-
-      // Extract control bit for next level.
-      const auto next_control_mask = IsBitSet(d8, vec, 0);
-      vec = hn::And(vec, clear_lowest_bit);
-
-      // Perform control bit correction.
-      auto correction_control_mask = mask_all_zero;
-      if (correction_words_per_level == 1) {
-        const auto correction_control_mask_left =
-            correction_controls_left[j] ? mask_all_one : mask_all_zero;
-        const auto correction_control_mask_right =
-            correction_controls_right[j] ? mask_all_one : mask_all_zero;
-        correction_control_mask =
-            IfThenElseMask(path_mask, correction_control_mask_right,
-                           correction_control_mask_left);
-      } else {
-        const bool* correction_controls_left_j =
-            correction_controls_left + j * correction_words_per_level +
-            start_block;
-        const bool* correction_controls_right_j =
-            correction_controls_right + j * correction_words_per_level +
-            start_block;
-        correction_control_mask = IfThenElseMask(
-            path_mask, MaskFromBools(d64, correction_controls_right_j),
-            MaskFromBools(d64, correction_controls_left_j));
-      }
-      control_mask = hn::Xor(next_control_mask,
-                             (hn::And(control_mask, correction_control_mask)));
-    }
-    hn::Store(vec, d8, seeds_out_ptr + i);
-    BoolsFromMask(d64, control_mask, control_bits_out + start_block);
-  }
-  ABSL_DCHECK_GT(i + bytes_per_vec, num_bytes);
-
-  // Elements less than a full vector.
-  int remaining_blocks = num_seeds - i / sizeof(absl::uint128);
-  if (remaining_blocks > 0) {
-    const int64_t start_block = i / sizeof(absl::uint128);
-    const int remaining_bytes = num_bytes - i;
-    // Copy to a buffer first, to ensure we have at least bytes_per_vec bytes
-    // to read. Calling MaskedLoad directly instead might lead to out-of-bounds
-    // accesses.
-    auto buffer = hwy::AllocateAligned<absl::uint128>(2 * blocks_per_vec);
-    if (buffer == nullptr) {
-      return absl::ResourceExhaustedError("Memory allocation error");
-    }
-    auto buffer_ptr = reinterpret_cast<uint8_t*>(buffer.get());
-    std::copy_n(seeds_in + start_block, remaining_blocks, buffer.get());
-    std::copy_n(paths + start_block, remaining_blocks,
-                buffer.get() + blocks_per_vec);
-    const auto load_mask = hn::FirstN(d8, remaining_bytes);
-    auto vec = hn::MaskedLoad(load_mask, d8, buffer_ptr);
-    const auto path = hn::MaskedLoad(load_mask, d8, buffer_ptr + bytes_per_vec);
-    auto control_mask =
-        MaskFromBools(d64, control_bits_in + start_block, remaining_blocks);
-    for (int j = 0; j < num_levels; ++j) {
-      const int bit_index = num_levels - j - 1 + paths_rightshift;
-      const auto path_mask = IsBitSet(d8, path, bit_index);
-      HashOneWithKeyMask(
-          d8, vec, path_mask,
-          reinterpret_cast<const uint8_t*>(expanded_key_0.rd_key),
-          reinterpret_cast<const uint8_t*>(expanded_key_1.rd_key), vec);
-
-      // Perform seed correction.
-      hn::Vec<decltype(d64)> correction_seed;
-      if (correction_words_per_level == 1) {
-        correction_seed = hn::LoadDup128(
-            d64, reinterpret_cast<const uint64_t*>(correction_seeds + j));
-      } else {
-        std::copy_n(
-            correction_seeds + j * correction_words_per_level + start_block,
-            remaining_blocks, buffer.get());
-        correction_seed =
-            hn::BitCast(d64, hn::MaskedLoad(load_mask, d8, buffer_ptr));
-      }
-      vec = hn::Xor(vec, hn::BitCast(d8, hn::IfThenElseZero(control_mask,
-                                                            correction_seed)));
-      const auto next_control_mask = IsBitSet(d8, vec, 0);
-      vec = hn::And(vec, clear_lowest_bit);
-
-      // Perform control bit correction.
-      auto correction_control_mask = mask_all_zero;
-      if (correction_words_per_level == 1) {
-        const auto correction_control_mask_left =
-            correction_controls_left[j] ? mask_all_one : mask_all_zero;
-        const auto correction_control_mask_right =
-            correction_controls_right[j] ? mask_all_one : mask_all_zero;
-        correction_control_mask =
-            IfThenElseMask(path_mask, correction_control_mask_right,
-                           correction_control_mask_left);
-      } else {
-        const bool* correction_controls_left_j =
-            correction_controls_left + j * correction_words_per_level +
-            start_block;
-        const bool* correction_controls_right_j =
-            correction_controls_right + j * correction_words_per_level +
-            start_block;
-        correction_control_mask = IfThenElseMask(
-            path_mask,
-            MaskFromBools(d64, correction_controls_right_j, remaining_blocks),
-            MaskFromBools(d64, correction_controls_left_j, remaining_blocks));
-      }
-      control_mask = hn::Xor(next_control_mask,
-                             (hn::And(control_mask, correction_control_mask)));
-    }
-    // Store back into buffer, then copy to seeds_out.
-    hn::Store(vec, d8, buffer_ptr);
-    std::copy_n(buffer.get(), remaining_blocks, seeds_out + start_block);
-    BoolsFromMask(d64, control_mask, control_bits_out + start_block,
-                  remaining_blocks);
-  }
-
-  return absl::OkStatus();
-}
-
-#endif  // HWY_TARGET == HWY_SCALAR
-
-}  // namespace HWY_NAMESPACE
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-HWY_AFTER_NAMESPACE();
-
-#if HWY_ONCE || HWY_IDE
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-absl::Status EvaluateSeedsNoHwy(
-    int64_t num_seeds, int num_levels, int num_correction_words,
-    const absl::uint128* seeds_in, const bool* control_bits_in,
-    const absl::uint128* paths, int paths_rightshift,
-    const absl::uint128* correction_seeds, const bool* correction_controls_left,
-    const bool* correction_controls_right, const Aes128FixedKeyHash& prg_left,
-    const Aes128FixedKeyHash& prg_right, absl::uint128* seeds_out,
-    bool* control_bits_out) {
-  using BitVector =
-      absl::InlinedVector<bool,
-                          std::max<size_t>(1, sizeof(bool*) / sizeof(bool))>;
-  constexpr int64_t max_batch_size = Aes128FixedKeyHash::kBatchSize;
-
-  // Allocate buffers.
-  std::vector<absl::uint128> buffer_left, buffer_right;
-  buffer_left.resize(max_batch_size);
-  buffer_right.resize(max_batch_size);
-  BitVector path_bits(max_batch_size), control_bits(max_batch_size);
-
-  // Perform DPF evaluation in blocks.
-  for (int64_t start_block = 0; start_block < num_seeds;
-       start_block += max_batch_size) {
-    int64_t current_batch_size =
-        std::min<int64_t>(num_seeds - start_block, max_batch_size);
-
-    for (int level = 0; level < num_levels; ++level) {
-      // Evaluate PRG. We evaluate both left and right expansions, but only use
-      // one of them (depending on path_bits). This seems to be faster than
-      // first sorting the seeds by path_bits and then expanding.
-      absl::Span<const absl::uint128> seeds =
-          absl::MakeConstSpan((level == 0 ? seeds_in : seeds_out) + start_block,
-                              current_batch_size);
-      DPF_RETURN_IF_ERROR(prg_left.Evaluate(
-          seeds, absl::MakeSpan(buffer_left).subspan(0, current_batch_size)));
-      DPF_RETURN_IF_ERROR(prg_right.Evaluate(
-          seeds, absl::MakeSpan(buffer_right).subspan(0, current_batch_size)));
-
-      // Merge back into result.
-      const int bit_index = num_levels - level - 1 + paths_rightshift;
-      for (int i = 0; i < current_batch_size; ++i) {
-        path_bits[i] = 0;
-        if (bit_index < 128) {
-          path_bits[i] =
-              ((paths[start_block + i]) & (absl::uint128{1} << bit_index)) != 0;
-        }
-        if (path_bits[i] == 0) {
-          seeds_out[start_block + i] = buffer_left[i];
-        } else {
-          seeds_out[start_block + i] = buffer_right[i];
-        }
-      }
-
-      // Compute correction. Making a copy here a copy here improves pipelining
-      // by not updating result.control_bits in place. Do benchmarks before
-      // removing this.
-      std::copy_n(
-          &(level == 0 ? control_bits_in : control_bits_out)[start_block],
-          current_batch_size, &control_bits[0]);
-      int correction_index = level;
-      for (int i = 0; i < current_batch_size; ++i) {
-        if (num_correction_words > num_levels) {
-          // We have num_levels * num_seeds correction words.
-          correction_index = level * num_seeds + start_block + i;
-        }
-        if (control_bits[i]) {
-          seeds_out[start_block + i] ^= correction_seeds[correction_index];
-        }
-        bool current_control_bit =
-            ExtractAndClearLowestBit(seeds_out[start_block + i]);
-        if (control_bits[i]) {
-          if (path_bits[i] == 0) {
-            current_control_bit ^= correction_controls_left[correction_index];
-          } else {
-            current_control_bit ^= correction_controls_right[correction_index];
-          }
-        }
-        control_bits_out[start_block + i] = current_control_bit;
-      }
-    }
-  }
-
-  return absl::OkStatus();
-}
-
-HWY_EXPORT(EvaluateSeedsHwy);
-
-absl::Status EvaluateSeeds(
-    int64_t num_seeds, int num_levels, int num_correction_words,
-    const absl::uint128* seeds_in, const bool* control_bits_in,
-    const absl::uint128* paths, int paths_rightshift,
-    const absl::uint128* correction_seeds, const bool* correction_controls_left,
-    const bool* correction_controls_right, const Aes128FixedKeyHash& prg_left,
-    const Aes128FixedKeyHash& prg_right, absl::uint128* seeds_out,
-    bool* control_bits_out) {
-  // Check that we either have one or `num_seeds` correction words per level.
-  if (num_correction_words != num_levels &&
-      num_correction_words != num_levels * num_seeds) {
-    return absl::InvalidArgumentError(
-        "`num_correction_words` must be equal to `num_levels` or `num_levels * "
-        "num_seeds`");
-  }
-  return HWY_DYNAMIC_DISPATCH(EvaluateSeedsHwy)(
-      num_seeds, num_levels, num_correction_words, seeds_in, control_bits_in,
-      paths, paths_rightshift, correction_seeds, correction_controls_left,
-      correction_controls_right, prg_left, prg_right, seeds_out,
-      control_bits_out);
-}
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-#endif
diff --git a/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy.h b/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy.h
deleted file mode 100644
index 866c7ebf..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_EXPAND_SEEDS_HWY_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_EXPAND_SEEDS_HWY_H_
-
-#include <stdint.h>
-
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "dpf/aes_128_fixed_key_hash.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-using distributed_point_functions::Aes128FixedKeyHash;
-
-// Extracts the lowest bit of `x` and sets it to 0 in `x`.
-inline bool ExtractAndClearLowestBit(absl::uint128& x) {
-  bool bit = ((x & absl::uint128{1}) != 0);
-  x &= ~absl::uint128{1};
-  return bit;
-}
-
-// Performs DPF evaluation of the seeds given in `seeds_in` using `prg_left` or
-// `prg_right, and the given `control_bits_in`, and correction words given by
-// `correction_seeds`, `correction_controls_left`, and
-// `correction_controls_right`. At each level `l < num_level`, the evaluation
-// for the i-th seed continues along the left or right path depending on the
-// l-th most significant bit among the lowest `num_levels` bits of `paths[i]`,
-// after right-shifting each `paths[i]` by `paths_rightshift`.
-//
-// This function takes raw pointers instead of absl::Span for performance
-// reasons. No bounds checks are performed, so it is the caller's responsibility
-// to ensure that
-// - `seeds_in`, `control_bits_in`, `seeds_out`, and `control_bits_out` have at
-//   least `num_seeds` elements, and
-// - `correction_seeds`, `correction_controls_left`, and
-//   `correction_controls_right` have at least `num_levels` elements.
-//
-// If the inputs are aligned (e.g. using HWY_ALIGN, or hwy::AllocateAligned),
-// and if SIMD operations are supported, then the evaluation will be done using
-// SIMD operations. Otherwise, falls back to `EvaluateSeedsNoHwy`, which is at
-// least 2x slower.
-//
-// `num_correction_words` can either be equal to `num_levels`, or equal to
-// `num_seeds * num_levels`. In the first case, the same correction word is used
-// for every seed at a given level. In the second case, correction word at index
-// `i * num_seeds + j` is used to correct seed `i` at level `j`.
-// If `num_correction_words == num_seeds * num_levels`, then `num_seeds` should
-// be smaller than or divisible by the size of a SIMD vector for optimal
-// performance.
-//
-// Returns OK on success, INVALID_ARGUMENT in case num_correction_words is not
-// equal to `num_levels` or `num_seeds * num_levels`, and INTERNAL in case of
-// OpenSSL errors.
-absl::Status EvaluateSeeds(
-    int64_t num_seeds, int num_levels, int num_correction_words,
-    const absl::uint128* seeds_in, const bool* control_bits_in,
-    const absl::uint128* paths, int paths_rightshift,
-    const absl::uint128* correction_seeds, const bool* correction_controls_left,
-    const bool* correction_controls_right, const Aes128FixedKeyHash& prg_left,
-    const Aes128FixedKeyHash& prg_right, absl::uint128* seeds_out,
-    bool* control_bits_out);
-
-// As `EvaluateSeeds`, but does not require any SIMD support.
-absl::Status EvaluateSeedsNoHwy(
-    int64_t num_seeds, int num_levels, int num_correction_words,
-    const absl::uint128* seeds_in, const bool* control_bits_in,
-    const absl::uint128* paths, int paths_rightshift,
-    const absl::uint128* correction_seeds, const bool* correction_controls_left,
-    const bool* correction_controls_right, const Aes128FixedKeyHash& prg_left,
-    const Aes128FixedKeyHash& prg_right, absl::uint128* seeds_out,
-    bool* control_bits_out);
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_EXPAND_SEEDS_HWY_H_
diff --git a/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy_test.cc b/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy_test.cc
deleted file mode 100644
index 8b054862..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/evaluate_prg_hwy_test.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/internal/evaluate_prg_hwy.h"
-
-#include <memory>
-
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "dpf/aes_128_fixed_key_hash.h"
-#include "dpf/internal/status_matchers.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "hwy/aligned_allocator.h"
-
-// clang-format off
-#define HWY_IS_TEST 1;
-#undef HWY_TARGET_INCLUDE
-#define HWY_TARGET_INCLUDE "dpf/internal/evaluate_prg_hwy_test.cc"  // NOLINT
-#include "hwy/foreach_target.h"
-// clang-format on
-#include "hwy/highway.h"
-#include "hwy/tests/hwy_gtest.h"
-
-HWY_BEFORE_NAMESPACE();
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace HWY_NAMESPACE {
-
-using ::testing::HasSubstr;
-
-constexpr absl::uint128 kKey0 =
-    absl::MakeUint128(0x0000000000000000, 0x0000000000000000);
-constexpr absl::uint128 kKey1 =
-    absl::MakeUint128(0x1111111111111111, 0x1111111111111111);
-
-void TestOutputMatchesNoHwyVersion(int num_seeds, int num_levels,
-                                   int num_correction_words,
-                                   int paths_rightshift) {
-  // Generate seeds.
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> seeds_in, paths;
-  hwy::AlignedFreeUniquePtr<bool[]> control_bits_in;
-  if (num_seeds > 0) {
-    seeds_in = hwy::AllocateAligned<absl::uint128>(num_seeds);
-    ASSERT_NE(seeds_in, nullptr);
-    paths = hwy::AllocateAligned<absl::uint128>(num_seeds);
-    ASSERT_NE(paths, nullptr);
-    control_bits_in = hwy::AllocateAligned<bool>(num_seeds);
-    ASSERT_NE(control_bits_in, nullptr);
-  }
-  for (int i = 0; i < num_seeds; ++i) {
-    // All of these are arbitrary.
-    seeds_in[i] = absl::MakeUint128(i, i + 1);
-    paths[i] = absl::MakeUint128(23 * i + 42, 42 * i + 23);
-    control_bits_in[i] = (i % 7 == 0);
-  }
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> seeds_out;
-  hwy::AlignedFreeUniquePtr<bool[]> control_bits_out;
-  if (num_seeds > 0) {
-    seeds_out = hwy::AllocateAligned<absl::uint128>(num_seeds);
-    ASSERT_NE(seeds_out, nullptr);
-    control_bits_out = hwy::AllocateAligned<bool>(num_seeds);
-    ASSERT_NE(control_bits_out, nullptr);
-  }
-
-  // Generate correction words.
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> correction_seeds;
-  hwy::AlignedFreeUniquePtr<bool[]> correction_controls_left,
-      correction_controls_right;
-  if (num_correction_words > 0) {
-    correction_seeds =
-        hwy::AllocateAligned<absl::uint128>(num_correction_words);
-    ASSERT_NE(correction_seeds, nullptr);
-    correction_controls_left = hwy::AllocateAligned<bool>(num_correction_words);
-    ASSERT_NE(correction_controls_left, nullptr);
-    correction_controls_right =
-        hwy::AllocateAligned<bool>(num_correction_words);
-    ASSERT_NE(correction_controls_right, nullptr);
-  }
-  for (int i = 0; i < num_correction_words; ++i) {
-    correction_seeds[i] = absl::MakeUint128(i + 1, i);
-    correction_controls_left[i] = (i % 23 == 0);
-    correction_controls_right[i] = (i % 42 != 0);
-  }
-
-  // Set up PRGs.
-  DPF_ASSERT_OK_AND_ASSIGN(
-      auto prg_left,
-      distributed_point_functions::Aes128FixedKeyHash::Create(kKey0));
-  DPF_ASSERT_OK_AND_ASSIGN(
-      auto prg_right,
-      distributed_point_functions::Aes128FixedKeyHash::Create(kKey1));
-
-  // Evaluate with Highway enabled.
-  DPF_ASSERT_OK(
-      EvaluateSeeds(num_seeds, num_levels, num_correction_words, seeds_in.get(),
-                    control_bits_in.get(), paths.get(), paths_rightshift,
-                    correction_seeds.get(), correction_controls_left.get(),
-                    correction_controls_right.get(), prg_left, prg_right,
-                    seeds_out.get(), control_bits_out.get()));
-
-  // Evaluate without highway.
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> seeds_out_wanted;
-  hwy::AlignedFreeUniquePtr<bool[]> control_bits_out_wanted;
-  if (num_seeds > 0) {
-    seeds_out_wanted = hwy::AllocateAligned<absl::uint128>(num_seeds);
-    ASSERT_NE(seeds_out_wanted, nullptr);
-    control_bits_out_wanted = hwy::AllocateAligned<bool>(num_seeds);
-    ASSERT_NE(control_bits_out_wanted, nullptr);
-  }
-  DPF_ASSERT_OK(EvaluateSeedsNoHwy(
-      num_seeds, num_levels, num_correction_words, seeds_in.get(),
-      control_bits_in.get(), paths.get(), paths_rightshift,
-      correction_seeds.get(), correction_controls_left.get(),
-      correction_controls_right.get(), prg_left, prg_right,
-      seeds_out_wanted.get(), control_bits_out_wanted.get()));
-
-  // Check that both evaluations are equal, if there was anything to evaluate.
-  if (num_levels > 0) {
-    for (int i = 0; i < num_seeds; ++i) {
-      EXPECT_EQ(seeds_out[i], seeds_out_wanted[i]);
-      EXPECT_EQ(control_bits_out[i], control_bits_out_wanted[i]);
-    }
-  }
-
-  // Evaluate without paths_rightshift
-  if (paths_rightshift != 0) {
-    hwy::AlignedFreeUniquePtr<absl::uint128[]> paths_in2;
-    hwy::AlignedFreeUniquePtr<absl::uint128[]> seeds_out_wanted2;
-    hwy::AlignedFreeUniquePtr<bool[]> control_bits_out_wanted2;
-    if (num_seeds > 0) {
-      paths_in2 = hwy::AllocateAligned<absl::uint128>(num_seeds);
-      ASSERT_NE(paths_in2, nullptr);
-      seeds_out_wanted2 = hwy::AllocateAligned<absl::uint128>(num_seeds);
-      ASSERT_NE(seeds_out_wanted2, nullptr);
-      control_bits_out_wanted2 = hwy::AllocateAligned<bool>(num_seeds);
-      ASSERT_NE(control_bits_out_wanted2, nullptr);
-    }
-    for (int i = 0; i < num_seeds; ++i) {
-      paths_in2[i] = 0;
-      if (paths_rightshift < 128) {
-        paths_in2[i] = paths[i] >> paths_rightshift;
-      }
-    }
-    DPF_ASSERT_OK(EvaluateSeedsNoHwy(
-        num_seeds, num_levels, num_correction_words, seeds_in.get(),
-        control_bits_in.get(), paths_in2.get(), 0, correction_seeds.get(),
-        correction_controls_left.get(), correction_controls_right.get(),
-        prg_left, prg_right, seeds_out_wanted2.get(),
-        control_bits_out_wanted2.get()));
-    // Check that both evaluations are equal, if there was anything to evaluate.
-    if (num_levels > 0) {
-      for (int i = 0; i < num_seeds; ++i) {
-        EXPECT_EQ(seeds_out[i], seeds_out_wanted2[i]);
-        EXPECT_EQ(control_bits_out[i], control_bits_out_wanted2[i]);
-      }
-    }
-  }
-}
-
-void TestAll() {
-  for (int num_seeds : {0, 1, 2, 101, 128, 1000}) {
-    for (int num_levels : {0, 1, 2, 32, 63, 64, 127, 128}) {
-      for (int num_correction_words : {num_levels, num_levels * num_seeds}) {
-        TestOutputMatchesNoHwyVersion(num_seeds, num_levels,
-                                      num_correction_words, 0);
-      }
-    }
-  }
-}
-
-void TestPathsRightshift() {
-  constexpr int num_levels = 128;
-  for (int num_seeds : {0, 1, 101}) {
-    for (int paths_rightshift = 0; paths_rightshift <= 128;
-         ++paths_rightshift) {
-      TestOutputMatchesNoHwyVersion(num_seeds, num_levels, num_levels,
-                                    paths_rightshift);
-    }
-  }
-}
-
-void FailsIfNumCorrectionWordsIsWrong() {
-  constexpr int num_seeds = 1000;
-  constexpr int num_levels = 10;
-  constexpr int num_correction_words = 12;
-
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> seeds_in, paths;
-  hwy::AlignedFreeUniquePtr<bool[]> control_bits_in;
-  seeds_in = hwy::AllocateAligned<absl::uint128>(num_seeds);
-  ASSERT_NE(seeds_in, nullptr);
-  paths = hwy::AllocateAligned<absl::uint128>(num_seeds);
-  ASSERT_NE(paths, nullptr);
-  control_bits_in = hwy::AllocateAligned<bool>(num_seeds);
-  ASSERT_NE(control_bits_in, nullptr);
-
-  hwy::AlignedFreeUniquePtr<absl::uint128[]> correction_seeds;
-  hwy::AlignedFreeUniquePtr<bool[]> correction_controls_left,
-      correction_controls_right;
-  correction_seeds = hwy::AllocateAligned<absl::uint128>(num_correction_words);
-  ASSERT_NE(correction_seeds, nullptr);
-  correction_controls_left = hwy::AllocateAligned<bool>(num_correction_words);
-  ASSERT_NE(correction_controls_left, nullptr);
-  correction_controls_right = hwy::AllocateAligned<bool>(num_correction_words);
-  ASSERT_NE(correction_controls_right, nullptr);
-
-  DPF_ASSERT_OK_AND_ASSIGN(
-      auto prg_left,
-      distributed_point_functions::Aes128FixedKeyHash::Create(kKey0));
-  DPF_ASSERT_OK_AND_ASSIGN(
-      auto prg_right,
-      distributed_point_functions::Aes128FixedKeyHash::Create(kKey1));
-
-  EXPECT_THAT(
-      EvaluateSeeds(num_seeds, num_levels, num_correction_words, seeds_in.get(),
-                    control_bits_in.get(), paths.get(), 0,
-                    correction_seeds.get(), correction_controls_left.get(),
-                    correction_controls_right.get(), prg_left, prg_right,
-                    seeds_in.get(), control_bits_in.get()),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               HasSubstr("num_correction_words")));
-}
-
-}  // namespace HWY_NAMESPACE
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-HWY_AFTER_NAMESPACE();
-
-#if HWY_ONCE
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-HWY_BEFORE_TEST(EvaluatePrgHwyTest);
-HWY_EXPORT_AND_TEST_P(EvaluatePrgHwyTest, TestAll);
-HWY_EXPORT_AND_TEST_P(EvaluatePrgHwyTest, TestPathsRightshift);
-HWY_EXPORT_AND_TEST_P(EvaluatePrgHwyTest, FailsIfNumCorrectionWordsIsWrong);
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
-
-#endif
diff --git a/third_party/distributed_point_functions/code/dpf/internal/get_hwy_mode.cc b/third_party/distributed_point_functions/code/dpf/internal/get_hwy_mode.cc
deleted file mode 100644
index b3d0772..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/get_hwy_mode.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2022 Google LLC
-//
-// 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.
-
-#include "dpf/internal/get_hwy_mode.h"
-
-// clang-format off
-#undef HWY_TARGET_INCLUDE
-#define HWY_TARGET_INCLUDE "dpf/internal/get_hwy_mode.cc"
-#include "absl/strings/string_view.h"
-#include "hwy/foreach_target.h"
-// clang-format on
-
-#include "hwy/highway.h"
-
-HWY_BEFORE_NAMESPACE();
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace HWY_NAMESPACE {
-
-const absl::string_view GetHwyModeAsString() {
-  return hwy::TargetName(HWY_TARGET);
-}
-
-}  // namespace HWY_NAMESPACE
-
-#if HWY_ONCE || HWY_IDE
-
-HWY_EXPORT(GetHwyModeAsString);
-const absl::string_view GetHwyModeAsString() {
-  return HWY_DYNAMIC_DISPATCH(GetHwyModeAsString)();
-}
-
-#endif
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-HWY_AFTER_NAMESPACE();
diff --git a/third_party/distributed_point_functions/code/dpf/internal/get_hwy_mode.h b/third_party/distributed_point_functions/code/dpf/internal/get_hwy_mode.h
deleted file mode 100644
index a123850..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/get_hwy_mode.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2022 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_GET_HWY_MODE_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_GET_HWY_MODE_H_
-
-#include "absl/strings/string_view.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-// Utility function for printing the mode selected by Highway. Used for
-// debugging.
-const absl::string_view GetHwyModeAsString();
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_GET_HWY_MODE_H_
diff --git a/third_party/distributed_point_functions/code/dpf/internal/maybe_deref_span.h b/third_party/distributed_point_functions/code/dpf/internal/maybe_deref_span.h
deleted file mode 100644
index 27b5d74..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/maybe_deref_span.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_ANY_SPAN_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_ANY_SPAN_H_
-
-// A class that can serve the purpose of both absl::Span<T> and absl::Span<T*>
-// at the same time. Introduces the run-time overhead of a std::variant check.
-//
-// Note that this class DOES NOT provide common container features, such as
-// iterators. It is not intended to be used by users of this library. Any
-// function that takes a MaybeDerefSpan<T> should be called with either an
-// absl::Span<T> or an absl::Span<T*>.
-
-#include <type_traits>
-
-#include "absl/meta/type_traits.h"
-#include "absl/types/span.h"
-#include "absl/types/variant.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-template <typename T>
-class MaybeDerefSpan {
- private:
-  template <typename U>
-  using EnableIfValueIsConst =
-      typename absl::enable_if_t<std::is_const<T>::value, U>;
-
-  template <typename U>
-  using EnableIfValueIsConvertibleToSpan = typename absl::enable_if_t<
-      absl::disjunction<std::is_convertible<U, absl::Span<T>>,
-                        std::is_convertible<U, absl::Span<T* const>>>::value,
-      U>;
-
- public:
-  // Implicit constructors from the underlying absl::Span.
-  MaybeDerefSpan(absl::Span<T> span)
-      : span_(span) {}  // NOLINT(runtime/explicit)
-  MaybeDerefSpan(absl::Span<T* const> span)
-      : span_(span) {}  // NOLINT(runtime/explicit)
-
-  // Implicit constructor of a const MaybeDerefSpan from a non-const one.
-  template <typename T2 = T, typename = EnableIfValueIsConst<T2>>
-  MaybeDerefSpan(
-      const MaybeDerefSpan<typename std::remove_const<T>::type>& other)
-      : span_(absl::ConvertVariantTo<decltype(span_)>(other.span_)) {
-  }  // NOLINT(runtime/explicit)
-
-  // Implicit constructor of a const MaybeDerefSpan from anything that is
-  // convertible to one of the underlying spans.
-  template <typename V, typename = EnableIfValueIsConst<V>,
-            typename = EnableIfValueIsConvertibleToSpan<V>>
-  MaybeDerefSpan(const V& span)
-      : span_(absl::MakeConstSpan(span)) {}  // NOLINT(runtime/explicit)
-
-  inline constexpr T& operator[](size_t index) const {
-    if (absl::holds_alternative<absl::Span<T* const>>(span_)) {
-      return *absl::get<absl::Span<T* const>>(span_)[index];
-    }
-    return absl::get<absl::Span<T>>(span_)[index];
-  }
-
-  inline constexpr size_t size() const {
-    return absl::visit([](auto v) { return v.size(); }, span_);
-  }
-
- private:
-  template <typename U>
-  friend class MaybeDerefSpan;
-
-  absl::variant<absl::Span<T>, absl::Span<T* const>> span_;
-};
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_ANY_SPAN_H_
diff --git a/third_party/distributed_point_functions/code/dpf/internal/maybe_deref_span_test.cc b/third_party/distributed_point_functions/code/dpf/internal/maybe_deref_span_test.cc
deleted file mode 100644
index cbcbfcc9..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/maybe_deref_span_test.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// 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.
-
-#include "dpf/internal/maybe_deref_span.h"
-
-#include <type_traits>
-#include <vector>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace {
-
-using T = int;
-
-TEST(MaybeDerefSpanTest, TestExplicitMutableDirectSpan) {
-  std::vector<T> x = {1, 2};
-  absl::Span<T> span(x);
-  MaybeDerefSpan<T> span2(span);
-
-  EXPECT_EQ(span2.size(), x.size());
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(span2[1], x[1]);
-  EXPECT_EQ(&span2[0], &x[0]);
-  EXPECT_EQ(&span2[1], &x[1]);
-
-  span2[0] = 3;
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(x[0], 3);
-}
-
-TEST(MaybeDerefSpanTest, TestExplicitMutableSpan) {
-  const std::vector<T> x = {1, 2};
-  absl::Span<const T> span(x);
-  MaybeDerefSpan<const T> span2(span);
-
-  EXPECT_EQ(span2.size(), x.size());
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(span2[1], x[1]);
-  EXPECT_EQ(&span2[0], &x[0]);
-  EXPECT_EQ(&span2[1], &x[1]);
-}
-
-TEST(MaybeDerefSpanTest, TestExplicitMutablePointerSpan) {
-  std::vector<T> x = {1, 2};
-  std::vector<T*> x2 = {&x[0], &x[1]};
-  absl::Span<T*> span(x2);
-  MaybeDerefSpan<T> span2(span);
-
-  EXPECT_EQ(span2.size(), x.size());
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(span2[1], x[1]);
-  EXPECT_EQ(&span2[0], &x[0]);
-  EXPECT_EQ(&span2[1], &x[1]);
-
-  span2[0] = 3;
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(x[0], 3);
-}
-
-TEST(MaybeDerefSpanTest, TestExplicitMutablePointerConstSpan) {
-  std::vector<T> x = {1, 2};
-  const std::vector<T*> x2 = {&x[0], &x[1]};
-  absl::Span<T* const> span(x2);
-  MaybeDerefSpan<T> span2(span);
-
-  EXPECT_EQ(span2.size(), x.size());
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(span2[1], x[1]);
-  EXPECT_EQ(&span2[0], &x[0]);
-  EXPECT_EQ(&span2[1], &x[1]);
-}
-
-TEST(MaybeDerefSpanTest, TestExplicitConstPointerConstSpan) {
-  const std::vector<T> x = {1, 2};
-  const std::vector<const T*> x2 = {&x[0], &x[1]};
-  absl::Span<const T* const> span(x2);
-  MaybeDerefSpan<const T> span2(span);
-
-  EXPECT_EQ(span2.size(), x.size());
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(span2[1], x[1]);
-  EXPECT_EQ(&span2[0], &x[0]);
-  EXPECT_EQ(&span2[1], &x[1]);
-}
-
-TEST(MaybeDerefSpanTest, TestMutableSpanToConstSpan) {
-  std::vector<T> x = {1, 2};
-  absl::Span<T> span(x);
-  MaybeDerefSpan<T> span2(span);
-  MaybeDerefSpan<const T> span3(span2);
-
-  EXPECT_EQ(span3.size(), x.size());
-  EXPECT_EQ(span3[0], x[0]);
-  EXPECT_EQ(span3[1], x[1]);
-  EXPECT_EQ(&span3[0], &x[0]);
-  EXPECT_EQ(&span3[1], &x[1]);
-}
-
-TEST(MaybeDerefSpanTest, TestImplicitConstSpan) {
-  const std::vector<T> x = {1, 2};
-  MaybeDerefSpan<const T> span2(x);
-
-  EXPECT_EQ(span2.size(), x.size());
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(span2[1], x[1]);
-  EXPECT_EQ(&span2[0], &x[0]);
-  EXPECT_EQ(&span2[1], &x[1]);
-}
-
-TEST(MaybeDerefSpanTest, TestImplicitPointerConstSpan) {
-  const std::vector<T> x = {1, 2};
-  const std::vector<const T*> x2 = {&x[0], &x[1]};
-  MaybeDerefSpan<const T> span2(x2);
-
-  EXPECT_EQ(span2.size(), x.size());
-  EXPECT_EQ(span2[0], x[0]);
-  EXPECT_EQ(span2[1], x[1]);
-  EXPECT_EQ(&span2[0], &x[0]);
-  EXPECT_EQ(&span2[1], &x[1]);
-}
-
-void TestEq(MaybeDerefSpan<const T> span, const std::vector<T>& vector) {
-  EXPECT_EQ(span.size(), vector.size());
-  EXPECT_EQ(span[0], vector[0]);
-  EXPECT_EQ(span[1], vector[1]);
-  EXPECT_EQ(&span[0], &vector[0]);
-  EXPECT_EQ(&span[1], &vector[1]);
-}
-
-TEST(MaybeDerefSpanTest, TestFunctionCallMutableVector) {
-  std::vector<T> x = {1, 2};
-
-  TestEq(x, x);
-}
-
-TEST(MaybeDerefSpanTest, TestFunctionCallMutablePointerVector) {
-  std::vector<T> x = {1, 2};
-  std::vector<T*> x2 = {&x[0], &x[1]};
-
-  TestEq(x2, x);
-}
-
-TEST(MaybeDerefSpanTest, TestFunctionCallConstVector) {
-  const std::vector<T> x = {1, 2};
-
-  TestEq(x, x);
-}
-
-TEST(MaybeDerefSpanTest, TestFunctionCallMutablePointerConstVector) {
-  std::vector<T> x = {1, 2};
-  const std::vector<T*> x2 = {&x[0], &x[1]};
-
-  TestEq(x2, x);
-}
-
-TEST(MaybeDerefSpanTest, TestFunctionCallConstPointerConstVector) {
-  const std::vector<T> x = {1, 2};
-  const std::vector<const T*> x2 = {&x[0], &x[1]};
-
-  TestEq(x2, x);
-}
-
-// Taken from https://en.cppreference.com/w/cpp/types/is_convertible.
-template <class From, class To>
-auto test_implicitly_convertible(int)
-    -> decltype(void(std::declval<void (&)(To)>()(std::declval<From>())),
-                std::true_type{});
-template <class, class>
-auto test_implicitly_convertible(...) -> std::false_type;
-
-// Test that vectors are convertible only to const spans.
-static_assert(
-    decltype(test_implicitly_convertible<std::vector<T>, MaybeDerefSpan<T>>(
-        0))::value == false);
-static_assert(decltype(test_implicitly_convertible<
-                       std::vector<T>, MaybeDerefSpan<const T>>(0))::value ==
-              true);
-
-}  // namespace
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/internal/proto_validator.cc b/third_party/distributed_point_functions/code/dpf/internal/proto_validator.cc
deleted file mode 100644
index 678b3de..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/proto_validator.cc
+++ /dev/null
@@ -1,336 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/internal/proto_validator.h"
-
-#include <algorithm>
-#include <cmath>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "absl/container/flat_hash_map.h"
-#include "absl/log/absl_check.h"
-#include "absl/memory/memory.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/str_format.h"
-#include "absl/types/span.h"
-#include "dpf/distributed_point_function.pb.h"
-#include "dpf/internal/value_type_helpers.h"
-#include "dpf/status_macros.h"
-#include "google/protobuf/repeated_field.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-namespace {
-
-inline double GetDefaultSecurityParameter(const DpfParameters& parameters) {
-  return ProtoValidator::kDefaultSecurityParameter +
-         parameters.log_domain_size();
-}
-
-inline bool AlmostEqual(double a, double b) {
-  return std::abs(a - b) <= ProtoValidator::kSecurityParameterEpsilon;
-}
-
-absl::StatusOr<bool> ParametersAreEqual(const DpfParameters& lhs,
-                                        const DpfParameters& rhs) {
-  if (lhs.log_domain_size() != rhs.log_domain_size()) {
-    return false;
-  }
-  if (!(
-          // There are three ways that security parameters can be equivalent.
-          // Both equal.
-          AlmostEqual(lhs.security_parameter(), rhs.security_parameter()) ||
-          // lhs is zero and rhs has the default value.
-          (lhs.security_parameter() == 0 &&
-           AlmostEqual(rhs.security_parameter(),
-                       GetDefaultSecurityParameter(rhs))) ||
-          // rhs is zero and lhs has the default value.
-          (rhs.security_parameter() == 0 &&
-           AlmostEqual(lhs.security_parameter(),
-                       GetDefaultSecurityParameter(lhs))))) {
-    return false;
-  }
-  return ValueTypesAreEqual(lhs.value_type(), rhs.value_type());
-}
-
-absl::Status ValidateIntegerType(const ValueType::Integer& type) {
-  int bitsize = type.bitsize();
-  if (bitsize < 1) {
-    return absl::InvalidArgumentError("`bitsize` must be positive");
-  }
-  if (bitsize > 128) {
-    return absl::InvalidArgumentError(
-        "`bitsize` must be less than or equal to 128");
-  }
-  if ((bitsize & (bitsize - 1)) != 0) {
-    return absl::InvalidArgumentError("`bitsize` must be a power of 2");
-  }
-  return absl::OkStatus();
-}
-
-absl::Status ValidateIntegerValue(const Value::Integer& value,
-                                  const ValueType::Integer& type) {
-  if (type.bitsize() < 128) {
-    DPF_ASSIGN_OR_RETURN(absl::uint128 value_128, ValueIntegerToUint128(value));
-    if (value_128 >= absl::uint128{1} << type.bitsize()) {
-      return absl::InvalidArgumentError(absl::StrFormat(
-          "Value (= %d) too large for ValueType with bitsize = %d", value_128,
-          type.bitsize()));
-    }
-  }
-  return absl::OkStatus();
-}
-
-}  // namespace
-
-ProtoValidator::ProtoValidator(std::vector<DpfParameters> parameters,
-                               int tree_levels_needed,
-                               absl::flat_hash_map<int, int> tree_to_hierarchy,
-                               std::vector<int> hierarchy_to_tree)
-    : parameters_(std::move(parameters)),
-      tree_levels_needed_(tree_levels_needed),
-      tree_to_hierarchy_(std::move(tree_to_hierarchy)),
-      hierarchy_to_tree_(std::move(hierarchy_to_tree)) {}
-
-absl::StatusOr<std::unique_ptr<ProtoValidator>> ProtoValidator::Create(
-    absl::Span<const DpfParameters> parameters_in) {
-  DPF_RETURN_IF_ERROR(ValidateParameters(parameters_in));
-
-  // Set default values of security_parameter for all parameters.
-  std::vector<DpfParameters> parameters(parameters_in.begin(),
-                                        parameters_in.end());
-  for (int i = 0; i < static_cast<int>(parameters.size()); ++i) {
-    if (parameters[i].security_parameter() == 0) {
-      parameters[i].set_security_parameter(
-          GetDefaultSecurityParameter(parameters[i]));
-    }
-  }
-
-  // Map hierarchy levels to levels in the evaluation tree for value correction,
-  // and vice versa.
-  absl::flat_hash_map<int, int> tree_to_hierarchy;
-  std::vector<int> hierarchy_to_tree(parameters.size());
-  // Also keep track of the height needed for the evaluation tree so far.
-  int tree_levels_needed = 0;
-  for (int i = 0; i < static_cast<int>(parameters.size()); ++i) {
-    int log_bits_needed;
-    DPF_ASSIGN_OR_RETURN(int bits_needed,
-                         BitsNeeded(parameters[i].value_type(),
-                                    parameters[i].security_parameter()));
-    log_bits_needed = static_cast<int>(std::ceil(std::log2(bits_needed)));
-
-    // The tree level depends on the domain size and the element size. A single
-    // AES block can fit 128 = 2^7 bits, so usually tree_level ==
-    // log_domain_size iff log_element_size >= 7. For smaller element sizes, we
-    // can reduce the tree_level (and thus the height of the tree) by the
-    // difference between log_element_size and 7. However, since the minimum
-    // tree level is 0, we have to ensure that no two hierarchy levels map to
-    // the same tree_level, hence the std::max.
-    int tree_level =
-        std::max(tree_levels_needed, parameters[i].log_domain_size() - 7 +
-                                         std::min(log_bits_needed, 7));
-    tree_to_hierarchy[tree_level] = i;
-    hierarchy_to_tree[i] = tree_level;
-    tree_levels_needed = std::max(tree_levels_needed, tree_level + 1);
-  }
-
-  return absl::WrapUnique(new ProtoValidator(
-      std::move(parameters), tree_levels_needed, std::move(tree_to_hierarchy),
-      std::move(hierarchy_to_tree)));
-}
-
-absl::Status ProtoValidator::ValidateParameters(
-    absl::Span<const DpfParameters> parameters) {
-  // Check that parameters are valid.
-  if (parameters.empty()) {
-    return absl::InvalidArgumentError("`parameters` must not be empty");
-  }
-  // Sentinel value for checking that domain sizes are increasing.
-  int previous_log_domain_size = 0;
-  for (int i = 0; i < static_cast<int>(parameters.size()); ++i) {
-    // Check log_domain_size.
-    int log_domain_size = parameters[i].log_domain_size();
-    if (log_domain_size < 0) {
-      return absl::InvalidArgumentError(
-          "`log_domain_size` must be non-negative");
-    }
-    if (log_domain_size > 128) {
-      return absl::InvalidArgumentError("`log_domain_size` must be <= 128");
-    }
-    if (i > 0 && log_domain_size <= previous_log_domain_size) {
-      return absl::InvalidArgumentError(
-          "`log_domain_size` fields must be in ascending order in "
-          "`parameters`");
-    }
-    previous_log_domain_size = log_domain_size;
-
-    if (parameters[i].has_value_type()) {
-      DPF_RETURN_IF_ERROR(ValidateValueType(parameters[i].value_type()));
-    } else {
-      return absl::InvalidArgumentError("`value_type` is required");
-    }
-
-    if (std::isnan(parameters[i].security_parameter())) {
-      return absl::InvalidArgumentError("`security_parameter` must not be NaN");
-    }
-    if (parameters[i].security_parameter() < 0 ||
-        parameters[i].security_parameter() > 128) {
-      // Since we use AES-128 for the PRG, a security parameter of > 128 is not
-      // possible.
-      return absl::InvalidArgumentError(
-          "`security_parameter` must be in [0, 128]");
-    }
-  }
-  return absl::OkStatus();
-}
-
-absl::Status ProtoValidator::ValidateDpfKey(const DpfKey& key) const {
-  // Check that `key` has the seed and last_level_output_correction set.
-  if (!key.has_seed()) {
-    return absl::InvalidArgumentError("key.seed must be present");
-  }
-  if (key.last_level_value_correction().empty()) {
-    return absl::InvalidArgumentError(
-        "key.last_level_value_correction must be present");
-  }
-  // Check that `key` is valid for the DPF defined by `parameters_`.
-  if (key.correction_words_size() != tree_levels_needed_ - 1) {
-    return absl::InvalidArgumentError(absl::StrCat(
-        "Malformed DpfKey: expected ", tree_levels_needed_ - 1,
-        " correction words, but got ", key.correction_words_size()));
-  }
-  for (int i = 0; i < static_cast<int>(hierarchy_to_tree_.size()); ++i) {
-    if (hierarchy_to_tree_[i] == tree_levels_needed_ - 1) {
-      // The output correction of the last tree level is always stored in
-      // last_level_output_correction.
-      continue;
-    }
-    ABSL_DCHECK(hierarchy_to_tree_[i] < key.correction_words_size());
-    if (key.correction_words(hierarchy_to_tree_[i])
-            .value_correction()
-            .empty()) {
-      return absl::InvalidArgumentError(absl::StrCat(
-          "Malformed DpfKey: expected correction_words[", hierarchy_to_tree_[i],
-          "] to contain the value correction of hierarchy level ", i));
-    }
-  }
-  return absl::OkStatus();
-}
-
-absl::Status ProtoValidator::ValidateEvaluationContext(
-    const EvaluationContext& ctx) const {
-  if (ctx.parameters_size() != static_cast<int>(parameters_.size())) {
-    return absl::InvalidArgumentError(
-        "Number of parameters in `ctx` doesn't match");
-  }
-  for (int i = 0; i < ctx.parameters_size(); ++i) {
-    DPF_ASSIGN_OR_RETURN(bool parameters_are_equal,
-                         ParametersAreEqual(parameters_[i], ctx.parameters(i)));
-    if (!parameters_are_equal) {
-      return absl::InvalidArgumentError(
-          absl::StrCat("Parameter ", i, " in `ctx` doesn't match"));
-    }
-  }
-  if (!ctx.has_key()) {
-    return absl::InvalidArgumentError("ctx.key must be present");
-  }
-  DPF_RETURN_IF_ERROR(ValidateDpfKey(ctx.key()));
-  if (ctx.previous_hierarchy_level() >= ctx.parameters_size() - 1) {
-    return absl::InvalidArgumentError(
-        "This context has already been fully evaluated");
-  }
-  if (!ctx.partial_evaluations().empty() &&
-      ctx.partial_evaluations_level() > ctx.previous_hierarchy_level()) {
-    return absl::InvalidArgumentError(
-        "ctx.partial_evaluations_level must be less than or equal to "
-        "ctx.previous_hierarchy_level");
-  }
-  return absl::OkStatus();
-}
-
-absl::Status ProtoValidator::ValidateValueType(const ValueType& value_type) {
-  if (value_type.type_case() == ValueType::kInteger) {
-    return ValidateIntegerType(value_type.integer());
-  } else if (value_type.type_case() == ValueType::kTuple) {
-    for (const ValueType& el : value_type.tuple().elements()) {
-      DPF_RETURN_IF_ERROR(ValidateValueType(el));
-    }
-    return absl::OkStatus();
-  } else if (value_type.type_case() == ValueType::kIntModN) {
-    const ValueType::Integer& base_integer =
-        value_type.int_mod_n().base_integer();
-    DPF_RETURN_IF_ERROR(ValidateIntegerType(base_integer));
-    return ValidateIntegerValue(value_type.int_mod_n().modulus(), base_integer);
-  } else if (value_type.type_case() == ValueType::kXorWrapper) {
-    return ValidateIntegerType(value_type.xor_wrapper());
-  }
-  return absl::InvalidArgumentError(absl::StrCat(
-      "ValidateValueType: Unsupported ValueType:\n", value_type.DebugString()));
-}
-
-absl::Status ProtoValidator::ValidateValue(const Value& value,
-                                           const ValueType& type) {
-  if (type.type_case() == ValueType::kInteger) {
-    // Integers.
-    if (value.value_case() != Value::kInteger) {
-      return absl::InvalidArgumentError("Expected integer value");
-    }
-    return ValidateIntegerValue(value.integer(), type.integer());
-  } else if (type.type_case() == ValueType::kTuple) {
-    // Tuples.
-    if (value.value_case() != Value::kTuple) {
-      return absl::InvalidArgumentError("Expected tuple value");
-    }
-    if (value.tuple().elements_size() != type.tuple().elements_size()) {
-      return absl::InvalidArgumentError(absl::StrCat(
-          "Expected tuple value of size ", type.tuple().elements_size(),
-          " but got size ", value.tuple().elements_size()));
-    }
-    for (int i = 0; i < type.tuple().elements_size(); ++i) {
-      DPF_RETURN_IF_ERROR(
-          ValidateValue(value.tuple().elements(i), type.tuple().elements(i)));
-    }
-    return absl::OkStatus();
-  } else if (type.type_case() == ValueType::kIntModN) {
-    DPF_RETURN_IF_ERROR(ValidateIntegerValue(value.int_mod_n(),
-                                             type.int_mod_n().base_integer()));
-    DPF_ASSIGN_OR_RETURN(absl::uint128 value_128,
-                         ValueIntegerToUint128(value.int_mod_n()));
-    DPF_ASSIGN_OR_RETURN(absl::uint128 modulus_128,
-                         ValueIntegerToUint128(type.int_mod_n().modulus()));
-    if (value_128 >= modulus_128) {
-      return absl::InvalidArgumentError(
-          absl::StrFormat("Value (= %d) is too large for modulus (= %d)",
-                          value_128, modulus_128));
-    }
-    return absl::OkStatus();
-  } else if (type.type_case() == ValueType::kXorWrapper) {
-    if (value.value_case() != Value::kXorWrapper) {
-      return absl::InvalidArgumentError("Expected XorWrapper value");
-    }
-    return ValidateIntegerValue(value.xor_wrapper(), type.xor_wrapper());
-  }
-  return absl::InvalidArgumentError(absl::StrCat(
-      "ValidateValue: Unsupported ValueType:\n", type.DebugString()));
-}
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/internal/proto_validator.h b/third_party/distributed_point_functions/code/dpf/internal/proto_validator.h
deleted file mode 100644
index e6e63dd8..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/proto_validator.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_PROTO_VALIDATOR_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_PROTO_VALIDATOR_H_
-
-#include <memory>
-#include <vector>
-
-#include "absl/container/flat_hash_map.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/types/span.h"
-#include "dpf/distributed_point_function.pb.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-// ProtoValidator is used to validate protos for DPF parameters, keys, and
-// evaluation contexts. Also holds information computed from the DPF parameters,
-// such as the mappings between hierarchy and tree levels.
-class ProtoValidator {
- public:
-  // The negative logarithm of the total variation distance from uniform that a
-  // *full* evaluation of a hierarchy level is allowed to have. Used as the
-  // default value for DpfParameters that don't have an explicit per-element
-  // security parameter set.
-  static constexpr double kDefaultSecurityParameter = 40;
-
-  // Security parameters that differ by less than this are considered equal.
-  static constexpr double kSecurityParameterEpsilon = 0.0001;
-
-  // Checks the validity of `parameters` and returns a ProtoValidator, which
-  // will be used to validate DPF keys and evaluation contexts afterwards.
-  //
-  // Returns INVALID_ARGUMENT if `parameters` are invalid.
-  static absl::StatusOr<std::unique_ptr<ProtoValidator>> Create(
-      absl::Span<const DpfParameters> parameters);
-
-  // Checks the validity of `parameters`.
-  // Returns OK on success, and INVALID_ARGUMENT otherwise.
-  static absl::Status ValidateParameters(
-      absl::Span<const DpfParameters> parameters);
-
-  // Checks that `key` is valid for the `parameters` passed at construction.
-  // Returns OK on success, and INVALID_ARGUMENT otherwise.
-  absl::Status ValidateDpfKey(const DpfKey& key) const;
-
-  // Checks that `ctx` is valid for the `parameters` passed at construction.
-  // Returns OK on success, and INVALID_ARGUMENT otherwise.
-  absl::Status ValidateEvaluationContext(const EvaluationContext& ctx) const;
-
-  // Checks that the given ValueType is valid.
-  // Returns OK on success and INVALID_ARGUMENT otherwise.
-  static absl::Status ValidateValueType(const ValueType& value_type);
-
-  // Checks that `value` is valid for `type`.
-  // Returns OK on success and INVALID_ARGUMENT otherwise.
-  static absl::Status ValidateValue(const Value& value, const ValueType& type);
-
-  // Checks that `value` is valid for `parameters[i]` passed at construction.
-  // Returns OK on success and INVALID_ARGUMENT otherwise.
-  inline absl::Status ValidateValue(const Value& value, int i) const {
-    return ValidateValue(value, parameters_[i].value_type());
-  }
-
-  // ProtoValidator is not copyable.
-  ProtoValidator(const ProtoValidator&) = delete;
-  ProtoValidator& operator=(const ProtoValidator&) = delete;
-
-  // ProtoValidator is movable.
-  ProtoValidator(ProtoValidator&&) = default;
-  ProtoValidator& operator=(ProtoValidator&&) = default;
-
-  // Getters.
-  absl::Span<const DpfParameters> parameters() const { return parameters_; }
-  int tree_levels_needed() const { return tree_levels_needed_; }
-  const absl::flat_hash_map<int, int>& tree_to_hierarchy() const {
-    return tree_to_hierarchy_;
-  }
-  const std::vector<int>& hierarchy_to_tree() const {
-    return hierarchy_to_tree_;
-  }
-
- private:
-  ProtoValidator(std::vector<DpfParameters> parameters, int tree_levels_needed,
-                 absl::flat_hash_map<int, int> tree_to_hierarchy,
-                 std::vector<int> hierarchy_to_tree);
-
-  // The DpfParameters passed at construction.
-  std::vector<DpfParameters> parameters_;
-
-  // Number of levels in the evaluation tree. This is always less than or equal
-  // to the largest log_domain_size in parameters_.
-  int tree_levels_needed_;
-
-  // Maps levels of the FSS evaluation tree to hierarchy levels (i.e., elements
-  // of parameters_).
-  absl::flat_hash_map<int, int> tree_to_hierarchy_;
-
-  // The inverse of tree_to_hierarchy_.
-  std::vector<int> hierarchy_to_tree_;
-};
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_PROTO_VALIDATOR_H_
diff --git a/third_party/distributed_point_functions/code/dpf/internal/proto_validator_test.cc b/third_party/distributed_point_functions/code/dpf/internal/proto_validator_test.cc
deleted file mode 100644
index 62e9d70..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/proto_validator_test.cc
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/internal/proto_validator.h"
-
-#include <stdint.h>
-
-#include <cmath>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/str_format.h"
-#include "dpf/distributed_point_function.pb.h"
-#include "dpf/internal/proto_validator_test_textproto_embed.h"
-#include "dpf/internal/status_matchers.h"
-#include "dpf/tuple.h"
-#include "gmock/gmock.h"
-#include "google/protobuf/repeated_field.h"
-#include "google/protobuf/text_format.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace {
-
-using ::testing::Ne;
-using ::testing::StartsWith;
-
-class ProtoValidatorTest : public testing::Test {
- protected:
-  void SetUp() override {
-    const auto* const toc = proto_validator_test_textproto_embed_create();
-    ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
-        std::string(toc->data, toc->size), &ctx_));
-    parameters_ = std::vector<DpfParameters>(ctx_.parameters().begin(),
-                                             ctx_.parameters().end());
-    dpf_key_ = ctx_.key();
-    DPF_ASSERT_OK_AND_ASSIGN(proto_validator_,
-                             ProtoValidator::Create(parameters_));
-  }
-
-  std::vector<DpfParameters> parameters_;
-  DpfKey dpf_key_;
-  EvaluationContext ctx_;
-  std::unique_ptr<dpf_internal::ProtoValidator> proto_validator_;
-};
-
-TEST_F(ProtoValidatorTest, CreateFailsWithoutParameters) {
-  EXPECT_THAT(ProtoValidator::Create({}),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`parameters` must not be empty"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsWhenParametersNotSorted) {
-  parameters_.resize(2);
-  parameters_[0].set_log_domain_size(10);
-  parameters_[1].set_log_domain_size(8);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`log_domain_size` fields must be in ascending order in "
-                       "`parameters`"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsWhenDomainSizeNegative) {
-  parameters_.resize(1);
-  parameters_[0].set_log_domain_size(-1);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`log_domain_size` must be non-negative"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsWhenDomainSizeTooLarge) {
-  parameters_.resize(1);
-  parameters_[0].set_log_domain_size(129);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`log_domain_size` must be <= 128"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsWhenElementBitsizeNegative) {
-  parameters_.resize(1);
-  parameters_[0].mutable_value_type()->mutable_integer()->set_bitsize(-1);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`bitsize` must be positive"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsWhenElementBitsizeZero) {
-  parameters_.resize(1);
-  parameters_[0].mutable_value_type()->mutable_integer()->set_bitsize(0);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`bitsize` must be positive"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsWhenElementBitsizeTooLarge) {
-  parameters_.resize(1);
-  parameters_[0].mutable_value_type()->mutable_integer()->set_bitsize(256);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`bitsize` must be less than or equal to 128"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsWhenElementBitsizeNotAPowerOfTwo) {
-  parameters_.resize(1);
-  parameters_[0].mutable_value_type()->mutable_integer()->set_bitsize(23);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`bitsize` must be a power of 2"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsIfSecurityParameterIsNaN) {
-  parameters_.resize(1);
-  parameters_[0].set_security_parameter(std::nan(""));
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`security_parameter` must not be NaN"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsIfSecurityParameterIsNegative) {
-  parameters_.resize(1);
-  parameters_[0].set_security_parameter(-0.01);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`security_parameter` must be in [0, 128]"));
-}
-
-TEST_F(ProtoValidatorTest, CreateFailsIfSecurityParameterIsTooLarge) {
-  parameters_.resize(1);
-  parameters_[0].set_security_parameter(128.01);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`security_parameter` must be in [0, 128]"));
-}
-
-TEST_F(ProtoValidatorTest, CreateWorksWhenElementBitsizesDecrease) {
-  parameters_.resize(2);
-  parameters_[0].mutable_value_type()->mutable_integer()->set_bitsize(64);
-  parameters_[1].mutable_value_type()->mutable_integer()->set_bitsize(32);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_), IsOkAndHolds(Ne(nullptr)));
-}
-
-TEST_F(ProtoValidatorTest, CreateWorksWhenHierarchiesAreFarApart) {
-  parameters_.resize(2);
-  parameters_[0].set_log_domain_size(10);
-  parameters_[1].set_log_domain_size(128);
-
-  EXPECT_THAT(ProtoValidator::Create(parameters_), IsOkAndHolds(Ne(nullptr)));
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateDpfKeyFailsIfNumberOfCorrectionWordsDoesntMatch) {
-  dpf_key_.add_correction_words();
-
-  EXPECT_THAT(proto_validator_->ValidateDpfKey(dpf_key_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       absl::StrCat("Malformed DpfKey: expected ",
-                                    dpf_key_.correction_words_size() - 1,
-                                    " correction words, but got ",
-                                    dpf_key_.correction_words_size())));
-}
-
-TEST_F(ProtoValidatorTest, ValidateDpfKeyFailsIfSeedIsMissing) {
-  dpf_key_.clear_seed();
-
-  EXPECT_THAT(
-      proto_validator_->ValidateDpfKey(dpf_key_),
-      StatusIs(absl::StatusCode::kInvalidArgument, "key.seed must be present"));
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateDpfKeyFailsIfLastLevelOutputCorrectionIsMissing) {
-  dpf_key_.clear_last_level_value_correction();
-
-  EXPECT_THAT(proto_validator_->ValidateDpfKey(dpf_key_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "key.last_level_value_correction must be present"));
-}
-
-TEST_F(ProtoValidatorTest, ValidateDpfKeyFailsIfOutputCorrectionIsMissing) {
-  for (CorrectionWord& cw : *(dpf_key_.mutable_correction_words())) {
-    cw.clear_value_correction();
-  }
-
-  EXPECT_THAT(
-      proto_validator_->ValidateDpfKey(dpf_key_),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               StartsWith("Malformed DpfKey: expected correction_words")));
-}
-
-TEST_F(ProtoValidatorTest, ValidateEvaluationContextFailsIfKeyIsMissing) {
-  ctx_.clear_key();
-
-  EXPECT_THAT(
-      proto_validator_->ValidateEvaluationContext(ctx_),
-      StatusIs(absl::StatusCode::kInvalidArgument, "ctx.key must be present"));
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateEvaluationContextFailsIfParameterSizeDoesntMatch) {
-  ctx_.mutable_parameters()->erase(ctx_.parameters().end() - 1);
-
-  EXPECT_THAT(proto_validator_->ValidateEvaluationContext(ctx_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Number of parameters in `ctx` doesn't match"));
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateEvaluationContextFailsIfLogDomainSizeDoesntMatch) {
-  ctx_.mutable_parameters(0)->set_log_domain_size(
-      ctx_.parameters(0).log_domain_size() + 1);
-
-  EXPECT_THAT(proto_validator_->ValidateEvaluationContext(ctx_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Parameter 0 in `ctx` doesn't match"));
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateEvaluationContextSucceedsIfSecurityParameterIsDefault) {
-  parameters_[0].set_security_parameter(0);
-  DPF_ASSERT_OK_AND_ASSIGN(proto_validator_,
-                           ProtoValidator::Create(parameters_));
-
-  ctx_.mutable_parameters(0)->set_security_parameter(0);
-
-  EXPECT_THAT(proto_validator_->ValidateEvaluationContext(ctx_), IsOk());
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateEvaluationContextFailsIfSecurityParameterDoesntMatch) {
-  ctx_.mutable_parameters(0)->set_security_parameter(
-      ctx_.parameters(0).security_parameter() + 1);
-
-  EXPECT_THAT(proto_validator_->ValidateEvaluationContext(ctx_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Parameter 0 in `ctx` doesn't match"));
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateEvaluationContextFailsIfContextFullyEvaluated) {
-  ctx_.set_previous_hierarchy_level(parameters_.size() - 1);
-
-  EXPECT_THAT(proto_validator_->ValidateEvaluationContext(ctx_),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "This context has already been fully evaluated"));
-}
-
-TEST_F(ProtoValidatorTest,
-       ValidateEvaluationContextFailsIfPartialEvaluationsLevelTooLarge) {
-  ctx_.set_previous_hierarchy_level(0);
-  ctx_.set_partial_evaluations_level(1);
-  ctx_.add_partial_evaluations();
-
-  EXPECT_THAT(
-      proto_validator_->ValidateEvaluationContext(ctx_),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               "ctx.partial_evaluations_level must be less than or equal to "
-               "ctx.previous_hierarchy_level"));
-}
-
-TEST_F(ProtoValidatorTest, ValidateValueFailsIfTypeNotInteger) {
-  ValueType type;
-  type.mutable_integer()->set_bitsize(32);
-  Value value;
-  value.mutable_tuple()->add_elements()->mutable_integer()->set_value_uint64(
-      23);
-
-  EXPECT_THAT(
-      proto_validator_->ValidateValue(value, type),
-      StatusIs(absl::StatusCode::kInvalidArgument, "Expected integer value"));
-}
-
-TEST_F(ProtoValidatorTest, ValidateValueFailsIfIntegerTooLarge) {
-  ValueType type;
-  Value value;
-
-  int element_bitsize = 32;
-  type.mutable_integer()->set_bitsize(element_bitsize);
-  auto value_64 = uint64_t{1} << element_bitsize;
-  value.mutable_integer()->set_value_uint64(value_64);
-
-  EXPECT_THAT(
-      proto_validator_->ValidateValue(value, type),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               absl::StrFormat(
-                   "Value (= %d) too large for ValueType with bitsize = %d",
-                   value_64, element_bitsize)));
-}
-
-TEST_F(ProtoValidatorTest, ValidateValueFailsIfTypeNotTuple) {
-  ValueType type;
-  type.mutable_tuple()->add_elements()->mutable_integer()->set_bitsize(32);
-  Value value;
-  value.mutable_integer()->set_value_uint64(23);
-
-  EXPECT_THAT(
-      proto_validator_->ValidateValue(value, type),
-      StatusIs(absl::StatusCode::kInvalidArgument, "Expected tuple value"));
-}
-
-TEST_F(ProtoValidatorTest, ValidateValueFailsIfTupleSizeDoesntMatch) {
-  ValueType type;
-  type.mutable_tuple()->add_elements()->mutable_integer()->set_bitsize(32);
-  Value value;
-
-  value.mutable_tuple()->add_elements()->mutable_integer()->set_value_uint64(
-      23);
-  value.mutable_tuple()->add_elements()->mutable_integer()->set_value_uint64(
-      42);
-
-  EXPECT_THAT(proto_validator_->ValidateValue(value, type),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Expected tuple value of size 1 but got size 2"));
-}
-
-TEST_F(ProtoValidatorTest, ValidateValueFailsIfValueLargerThanModulus) {
-  constexpr uint64_t kModulus = 3;
-  ValueType type;
-  type.mutable_int_mod_n()->mutable_base_integer()->set_bitsize(64);
-  type.mutable_int_mod_n()->mutable_modulus()->set_value_uint64(kModulus);
-  Value value;
-
-  value.mutable_int_mod_n()->set_value_uint64(kModulus);
-
-  EXPECT_THAT(proto_validator_->ValidateValue(value, type),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Value (= 3) is too large for modulus (= 3)"));
-}
-
-TEST_F(ProtoValidatorTest, ValidateValueFailsIfTypeNotXorWrapper) {
-  ValueType type;
-  type.mutable_xor_wrapper()->set_bitsize(32);
-  Value value;
-  value.mutable_integer()->set_value_uint64(23);
-
-  EXPECT_THAT(proto_validator_->ValidateValue(value, type),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Expected XorWrapper value"));
-}
-
-TEST_F(ProtoValidatorTest, ValidateValueFailsIfValueIsUnknown) {
-  ValueType type;
-  Value value;
-
-  EXPECT_THAT(
-      proto_validator_->ValidateValue(value, type),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               testing::StartsWith("ValidateValue: Unsupported ValueType:")));
-}
-
-TEST(ProtoValidator, ValidateValueTypeFailsIfBitsizeNotPositive) {
-  ValueType type;
-
-  type.mutable_integer()->set_bitsize(0);
-
-  EXPECT_THAT(ProtoValidator::ValidateValueType(type),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`bitsize` must be positive"));
-}
-
-TEST(ProtoValidator, ValidateValueTypeFailsIfBitsizeTooLarge) {
-  ValueType type;
-
-  type.mutable_integer()->set_bitsize(256);
-
-  EXPECT_THAT(ProtoValidator::ValidateValueType(type),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`bitsize` must be less than or equal to 128"));
-}
-
-TEST(ProtoValidator, ValidateValueTypeFailsIfBitsizeNotPowerOfTwo) {
-  ValueType type;
-
-  type.mutable_integer()->set_bitsize(17);
-
-  EXPECT_THAT(ProtoValidator::ValidateValueType(type),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "`bitsize` must be a power of 2"));
-}
-
-TEST(ProtoValidator, ValidateValueTypeFailsIfNoTypeChosen) {
-  ValueType type;
-
-  EXPECT_THAT(ProtoValidator::ValidateValueType(type),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       StartsWith("ValidateValueType: Unsupported ValueType")));
-}
-
-}  // namespace
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/internal/proto_validator_test.textproto b/third_party/distributed_point_functions/code/dpf/internal/proto_validator_test.textproto
deleted file mode 100644
index 5e411d7..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/proto_validator_test.textproto
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-# proto-file dpf/distributed_point_function.proto
-# proto-message: EvaluationContext
-
-parameters {
-  log_domain_size: 4
-  value_type {
-    integer {
-      bitsize: 32
-    }
-  }
-  security_parameter: 44
-}
-parameters {
-  log_domain_size: 6
-  value_type {
-    integer {
-      bitsize: 32
-    }
-  }
-  security_parameter: 46
-}
-parameters {
-  log_domain_size: 8
-  value_type {
-    integer {
-      bitsize: 32
-    }
-  }
-  security_parameter: 48
-}
-key {
-  seed {
-    high: 11559904407150645412
-    low: 10793182457266619527
-  }
-  correction_words {
-    seed {
-      high: 17231204231811741091
-      low: 13184625655696690000
-    }
-    control_left: true
-  }
-  correction_words {
-    seed {
-      high: 3072212389250066354
-      low: 1361245143349174348
-    }
-  }
-  correction_words {
-    seed {
-      high: 2882988684359810666
-      low: 16992210518729579018
-    }
-    control_right: true
-    value_correction: {
-      integer: {
-        value_uint64: 536412310
-      }
-    }
-  }
-  correction_words {
-    seed {
-      high: 4993590839844520517
-      low: 13033365507284852634
-    }
-    control_right: true
-  }
-  correction_words {
-    seed {
-      high: 10673753674550143002
-      low: 3019916643383017704
-    }
-    control_left: true
-    control_right: true
-    value_correction: {
-      integer: {
-        value_uint64: 841224518
-      }
-    }
-  }
-  correction_words {
-    seed {
-      high: 2423099213299230757
-      low: 12788496417753523946
-    }
-    control_right: true
-  }
-  last_level_value_correction: {
-    integer: {
-      value_uint64: 8471844854
-    }
-  }
-}
-previous_hierarchy_level: -1
diff --git a/third_party/distributed_point_functions/code/dpf/internal/status_matchers.cc b/third_party/distributed_point_functions/code/dpf/internal/status_matchers.cc
deleted file mode 100644
index 62317bc..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/status_matchers.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/internal/status_matchers.h"
-
-#include <ostream>
-#include <string>
-
-#include "absl/status/status.h"
-#include "absl/strings/string_view.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-void StatusIsMatcherCommonImpl::DescribeTo(std::ostream* os) const {
-  *os << "has a status code that ";
-  code_matcher_.DescribeTo(os);
-  *os << ", and has an error message that ";
-  message_matcher_.DescribeTo(os);
-}
-
-void StatusIsMatcherCommonImpl::DescribeNegationTo(std::ostream* os) const {
-  *os << "has a status code that ";
-  code_matcher_.DescribeNegationTo(os);
-  *os << ", or has an error message that ";
-  message_matcher_.DescribeNegationTo(os);
-}
-
-bool StatusIsMatcherCommonImpl::MatchAndExplain(
-    const ::absl::Status& status,
-    ::testing::MatchResultListener* result_listener) const {
-  ::testing::StringMatchResultListener inner_listener;
-  if (!code_matcher_.MatchAndExplain(status.code(), &inner_listener)) {
-    *result_listener << (inner_listener.str().empty()
-                             ? "whose status code is wrong"
-                             : "which has a status code " +
-                                   inner_listener.str());
-    return false;
-  }
-
-  if (!message_matcher_.Matches(std::string(status.message()))) {
-    *result_listener << "whose error message is wrong: " << status.message();
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/internal/status_matchers.h b/third_party/distributed_point_functions/code/dpf/internal/status_matchers.h
deleted file mode 100644
index fa15a02..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/status_matchers.h
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-// Testing utilities for working with absl::Status and absl::StatusOr.
-//
-// Defines the following utilities:
-//
-//   =================
-//   DPF_EXPECT_OK(s)
-//
-//   DPF_ASSERT_OK(s)
-//   =================
-//   Convenience macros for `EXPECT_THAT(s, IsOk())`, where `s` is either
-//   a `Status` or a `StatusOr<T>`.
-//
-//   There are no EXPECT_NOT_OK/ASSERT_NOT_OK macros since they would not
-//   provide much value (when they fail, they would just print the OK status
-//   which conveys no more information than `EXPECT_FALSE(s.ok())`. You can
-//   of course use `EXPECT_THAT(s, Not(IsOk()))` if you prefer _THAT style.
-//
-//   If you want to check for particular errors, better alternatives are:
-//   EXPECT_THAT(s, StatusIs(expected_error));
-//   EXPECT_THAT(s, StatusIs(_, HasSubstr("expected error")));
-//
-//   ===============
-//   IsOkAndHolds(m)
-//   ===============
-//
-//   This gMock matcher matches a StatusOr<T> value whose status is OK
-//   and whose inner value matches matcher m.  Example:
-//
-//     using ::testing::MatchesRegex;
-//     using distributed_point_functions::IsOkAndHolds;
-//     ...
-//     absl::StatusOr<string> maybe_name = ...;
-//     EXPECT_THAT(maybe_name, IsOkAndHolds(MatchesRegex("John .*")));
-//
-//   ===============================
-//   StatusIs(status_code_matcher,
-//            error_message_matcher)
-//   ===============================
-//
-//   This gMock matcher matches a Status or StatusOr<T> value if all of the
-//   following are true:
-//
-//     - the status' error_code() matches status_code_matcher, and
-//     - the status' error_message() matches error_message_matcher.
-//
-//   Example:
-//
-//     enum FooErrorCode {
-//       ...
-//       kServerError
-//     };
-//
-//     using ::testing::HasSubstr;
-//     using ::testing::MatchesRegex;
-//     using ::testing::Ne;
-//     using ::testing::_;
-//     using distributed_point_functions::StatusIs;
-//     absl::StatusOr<string> GetName(int id);
-//     ...
-//
-//     // The status code must be kServerError; the error message can be
-//     // anything.
-//     EXPECT_THAT(GetName(42),
-//                 StatusIs(kServerError, _));
-//     // The status code can be anything; the error message must match the
-//     // regex.
-//     EXPECT_THAT(GetName(43),
-//                 StatusIs(_, MatchesRegex("server.*time-out")));
-//
-//     // The status code should not be kServerError; the error message can be
-//     // anything with "client" in it.
-//     EXPECT_CALL(mock_env, HandleStatus(
-//         StatusIs(Ne(kServerError), HasSubstr("client"))));
-//
-//   ===============================
-//   StatusIs(status_code_matcher)
-//   ===============================
-//
-//   This is a shorthand for
-//     StatusIs(status_code_matcher,
-//              testing::_)
-//   In other words, it's like the two-argument StatusIs(), except that it
-//   ignores error message.
-//
-//   ===============
-//   IsOk()
-//   ===============
-//
-//   Matches an absl::Status or absl::StatusOr<T> value whose status value is
-//   absl::StatusCode::kOk. Equivalent to 'StatusIs(absl::StatusCode::kOk)'.
-//   Example:
-//     using distributed_point_functions::IsOk;
-//     ...
-//     absl::StatusOr<string> maybe_name = ...;
-//     EXPECT_THAT(maybe_name, IsOk());
-//     Status s = ...;
-//     EXPECT_THAT(s, IsOk());
-//
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_UTIL_STATUS_MATCHERS_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_UTIL_STATUS_MATCHERS_H_
-
-#include <ostream>
-#include <string>
-#include <type_traits>
-#include <utility>
-
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "dpf/status_macros.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-inline const absl::Status& GetStatus(const absl::Status& status) {
-  return status;
-}
-
-template <typename T>
-inline const absl::Status& GetStatus(const absl::StatusOr<T>& status) {
-  return status.status();
-}
-
-////////////////////////////////////////////////////////////
-// Implementation of IsOkAndHolds().
-
-// Monomorphic implementation of matcher IsOkAndHolds(m).  StatusOrType is a
-// reference to StatusOr<T>.
-template <typename StatusOrType>
-class IsOkAndHoldsMatcherImpl
-    : public ::testing::MatcherInterface<StatusOrType> {
- public:
-  typedef
-      typename std::remove_reference<StatusOrType>::type::value_type value_type;
-
-  template <typename InnerMatcher>
-  explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
-      : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
-            std::forward<InnerMatcher>(inner_matcher))) {}
-
-  void DescribeTo(std::ostream* os) const override {
-    *os << "is OK and has a value that ";
-    inner_matcher_.DescribeTo(os);
-  }
-
-  void DescribeNegationTo(std::ostream* os) const override {
-    *os << "isn't OK or has a value that ";
-    inner_matcher_.DescribeNegationTo(os);
-  }
-
-  bool MatchAndExplain(
-      StatusOrType actual_value,
-      ::testing::MatchResultListener* result_listener) const override {
-    if (!actual_value.ok()) {
-      *result_listener << "which has status " << actual_value.status();
-      return false;
-    }
-
-    ::testing::StringMatchResultListener inner_listener;
-    const bool matches =
-        inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
-    const std::string inner_explanation = inner_listener.str();
-    if (!inner_explanation.empty()) {
-      *result_listener << "which contains value "
-                       << ::testing::PrintToString(*actual_value) << ", "
-                       << inner_explanation;
-    }
-    return matches;
-  }
-
- private:
-  const ::testing::Matcher<const value_type&> inner_matcher_;
-};
-
-// Implements IsOkAndHolds(m) as a polymorphic matcher.
-template <typename InnerMatcher>
-class IsOkAndHoldsMatcher {
- public:
-  explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
-      : inner_matcher_(std::move(inner_matcher)) {}
-
-  // Converts this polymorphic matcher to a monomorphic matcher of the
-  // given type.  StatusOrType can be either StatusOr<T> or a
-  // reference to StatusOr<T>.
-  template <typename StatusOrType>
-  operator ::testing::Matcher<StatusOrType>() const {  // NOLINT
-    return ::testing::Matcher<StatusOrType>(
-        new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
-  }
-
- private:
-  const InnerMatcher inner_matcher_;
-};
-
-////////////////////////////////////////////////////////////
-// Implementation of StatusIs().
-
-// StatusIs() is a polymorphic matcher.  This class is the common
-// implementation of it shared by all types T where StatusIs() can be
-// used as a Matcher<T>.
-class StatusIsMatcherCommonImpl {
- public:
-  StatusIsMatcherCommonImpl(
-      ::testing::Matcher<absl::StatusCode> code_matcher,
-      ::testing::Matcher<const std::string&> message_matcher)
-      : code_matcher_(std::move(code_matcher)),
-        message_matcher_(std::move(message_matcher)) {}
-
-  void DescribeTo(std::ostream* os) const;
-
-  void DescribeNegationTo(std::ostream* os) const;
-
-  bool MatchAndExplain(const absl::Status& status,
-                       ::testing::MatchResultListener* result_listener) const;
-
- private:
-  const ::testing::Matcher<absl::StatusCode> code_matcher_;
-  const ::testing::Matcher<const std::string&> message_matcher_;
-};
-
-// Monomorphic implementation of matcher StatusIs() for a given type
-// T.  T can be Status, StatusOr<>, or a reference to either of them.
-template <typename T>
-class MonoStatusIsMatcherImpl : public ::testing::MatcherInterface<T> {
- public:
-  explicit MonoStatusIsMatcherImpl(StatusIsMatcherCommonImpl common_impl)
-      : common_impl_(std::move(common_impl)) {}
-
-  void DescribeTo(std::ostream* os) const override {
-    common_impl_.DescribeTo(os);
-  }
-
-  void DescribeNegationTo(std::ostream* os) const override {
-    common_impl_.DescribeNegationTo(os);
-  }
-
-  bool MatchAndExplain(
-      T actual_value,
-      ::testing::MatchResultListener* result_listener) const override {
-    return common_impl_.MatchAndExplain(GetStatus(actual_value),
-                                        result_listener);
-  }
-
- private:
-  StatusIsMatcherCommonImpl common_impl_;
-};
-
-// Implements StatusIs() as a polymorphic matcher.
-class StatusIsMatcher {
- public:
-  template <typename StatusCodeMatcher, typename StatusMessageMatcher>
-  StatusIsMatcher(StatusCodeMatcher&& code_matcher,
-                  StatusMessageMatcher&& message_matcher)
-      : common_impl_(::testing::MatcherCast<absl::StatusCode>(
-                         std::forward<StatusCodeMatcher>(code_matcher)),
-                     ::testing::MatcherCast<const std::string&>(
-                         std::forward<StatusMessageMatcher>(message_matcher))) {
-  }
-
-  // Converts this polymorphic matcher to a monomorphic matcher of the
-  // given type.  T can be StatusOr<>, Status, or a reference to
-  // either of them.
-  template <typename T>
-  operator ::testing::Matcher<T>() const {  // NOLINT
-    return ::testing::Matcher<T>(
-        new MonoStatusIsMatcherImpl<const T&>(common_impl_));
-  }
-
- private:
-  const StatusIsMatcherCommonImpl common_impl_;
-};
-
-// Monomorphic implementation of matcher IsOk() for a given type T.
-// T can be Status, StatusOr<>, or a reference to either of them.
-template <typename T>
-class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
- public:
-  void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
-  void DescribeNegationTo(std::ostream* os) const override {
-    *os << "is not OK";
-  }
-  bool MatchAndExplain(
-      T actual_value,
-      ::testing::MatchResultListener* result_listener) const override {
-    if (!actual_value.ok()) {
-      *result_listener << "whose status is "
-                       << GetStatus(actual_value).message();
-      return false;
-    }
-    return true;
-  }
-};
-
-// Implements IsOk() as a polymorphic matcher.
-class IsOkMatcher {
- public:
-  template <typename T>
-  operator ::testing::Matcher<T>() const {  // NOLINT
-    return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<const T&>());
-  }
-};
-
-// Macros for testing the results of functions that return absl::Status or
-// absl::StatusOr<T> (for any type T).
-#define DPF_EXPECT_OK(expression) \
-  EXPECT_THAT(expression, distributed_point_functions::dpf_internal::IsOk())
-#define DPF_ASSERT_OK(expression) \
-  ASSERT_THAT(expression, distributed_point_functions::dpf_internal::IsOk())
-
-// Executes an expression that returns an absl::StatusOr, and assigns the
-// contained variable to lhs if the error code is OK.
-// If the Status is non-OK, generates a test failure and returns from the
-// current function, which must have a void return type.
-//
-// Example: Declaring and initializing a new value
-//   DPF_ASSERT_OK_AND_ASSIGN(const ValueType& value, MaybeGetValue(arg));
-//
-// Example: Assigning to an existing value
-//   ValueType value;
-//   DPF_ASSERT_OK_AND_ASSIGN(value, MaybeGetValue(arg));
-//
-// The value assignment example would expand into something like:
-//   auto status_or_value = MaybeGetValue(arg);
-//   DPF_ASSERT_OK(status_or_value.status());
-//   value = std::move(status_or_value).ValueOrDie();
-//
-// WARNING: Like ASSIGN_OR_RETURN, DPF_ASSERT_OK_AND_ASSIGN expands into
-// multiple statements; it cannot be used in a single statement (e.g. as the
-// body of an if statement without {})!
-#define DPF_ASSERT_OK_AND_ASSIGN(lhs, rexpr) \
-  DPF_ASSERT_OK_AND_ASSIGN_IMPL_(            \
-      DPF_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), lhs, rexpr)
-
-#define DPF_ASSERT_OK_AND_ASSIGN_IMPL_(statusor, lhs, rexpr) \
-  auto statusor = (rexpr);                                   \
-  DPF_ASSERT_OK(statusor);                                   \
-  lhs = std::move(statusor).value();
-
-// Returns a gMock matcher that matches a StatusOr<> whose status is
-// OK and whose value matches the inner matcher.
-template <typename InnerMatcher>
-dpf_internal::IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>
-IsOkAndHolds(InnerMatcher&& inner_matcher) {
-  return dpf_internal::IsOkAndHoldsMatcher<
-      typename std::decay<InnerMatcher>::type>(
-      std::forward<InnerMatcher>(inner_matcher));
-}
-
-// Returns a gMock matcher that matches a Status or StatusOr<> whose status code
-// matches code_matcher, and whose error message matches message_matcher.
-template <typename StatusCodeMatcher, typename StatusMessageMatcher>
-dpf_internal::StatusIsMatcher StatusIs(StatusCodeMatcher&& code_matcher,
-                                       StatusMessageMatcher&& message_matcher) {
-  return dpf_internal::StatusIsMatcher(
-      std::forward<StatusCodeMatcher>(code_matcher),
-      std::forward<StatusMessageMatcher>(message_matcher));
-}
-
-// Returns a gMock matcher that matches a Status or StatusOr<> whose status code
-// matches code_matcher.
-template <typename StatusCodeMatcher>
-dpf_internal::StatusIsMatcher StatusIs(StatusCodeMatcher&& code_matcher) {
-  return StatusIs(std::forward<StatusCodeMatcher>(code_matcher), ::testing::_);
-}
-
-// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
-inline dpf_internal::IsOkMatcher IsOk() { return dpf_internal::IsOkMatcher(); }
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_UTIL_STATUS_MATCHERS_H_
diff --git a/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers.cc b/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers.cc
deleted file mode 100644
index 0704cce..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/internal/value_type_helpers.h"
-
-#include <stdint.h>
-
-#include <cmath>
-#include <string>
-
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "dpf/distributed_point_function.pb.h"
-#include "dpf/int_mod_n.h"
-#include "dpf/status_macros.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-absl::StatusOr<bool> ValueTypesAreEqual(const ValueType& lhs,
-                                        const ValueType& rhs) {
-  if (lhs.type_case() == ValueType::TypeCase::TYPE_NOT_SET ||
-      rhs.type_case() == ValueType::TypeCase::TYPE_NOT_SET) {
-    return absl::InvalidArgumentError(
-        "Both arguments must be valid ValueTypes");
-  } else if (lhs.type_case() == ValueType::kInteger &&
-             rhs.type_case() == ValueType::kInteger) {
-    return lhs.integer().bitsize() == rhs.integer().bitsize();
-  } else if (lhs.type_case() == ValueType::kTuple &&
-             rhs.type_case() == ValueType::kTuple &&
-             lhs.tuple().elements_size() == rhs.tuple().elements_size()) {
-    bool result = true;
-    for (int i = 0; i < static_cast<int>(lhs.tuple().elements_size()); ++i) {
-      DPF_ASSIGN_OR_RETURN(
-          bool element_result,
-          ValueTypesAreEqual(lhs.tuple().elements(i), rhs.tuple().elements(i)));
-      result &= element_result;
-    }
-    return result;
-  } else if (lhs.type_case() == ValueType::kIntModN &&
-             rhs.type_case() == ValueType::kIntModN) {
-    const Value::Integer &lhs_modulus = lhs.int_mod_n().modulus(),
-                         &rhs_modulus = rhs.int_mod_n().modulus();
-    DPF_ASSIGN_OR_RETURN(absl::uint128 lhs_modulus_128,
-                         ValueIntegerToUint128(lhs_modulus));
-    DPF_ASSIGN_OR_RETURN(absl::uint128 rhs_modulus_128,
-                         ValueIntegerToUint128(rhs_modulus));
-    return lhs.int_mod_n().base_integer().bitsize() ==
-               rhs.int_mod_n().base_integer().bitsize() &&
-           lhs_modulus_128 == rhs_modulus_128;
-  } else if (lhs.type_case() == ValueType::kXorWrapper &&
-             rhs.type_case() == ValueType::kXorWrapper) {
-    return lhs.xor_wrapper().bitsize() == rhs.xor_wrapper().bitsize();
-  }
-  return false;
-}
-
-absl::StatusOr<int> BitsNeeded(const ValueType& value_type,
-                               double security_parameter) {
-  if (value_type.type_case() == ValueType::kInteger) {
-    return value_type.integer().bitsize();
-  } else if (value_type.type_case() == ValueType::kTuple) {
-    // We handle elements of type IntModN separately, since we can sample them
-    // together.
-    int num_ints_mod_n = 0;
-    int num_other = 0;
-    const ValueType* int_mod_n = nullptr;
-    int bitsize_ints_mod_n = 0;
-    int bitsize_other = 0;
-    for (const ValueType& el : value_type.tuple().elements()) {
-      if (el.type_case() == ValueType::kIntModN) {
-        // Element is integer mod N -> check if it is the same as the others in
-        // this tuple and increase counter.
-        if (!int_mod_n) {
-          int_mod_n = &el;
-        } else {
-          absl::StatusOr<bool> types_are_equal =
-              ValueTypesAreEqual(el, *int_mod_n);
-          if (!types_are_equal.ok()) {
-            return types_are_equal.status();
-          }
-          if (!*types_are_equal) {
-            return absl::UnimplementedError(
-                "All elements of type IntModN in a tuple must be the same");
-          }
-        }
-        ++num_ints_mod_n;
-      } else {
-        ++num_other;
-      }
-    }
-    if (num_other > 0) {
-      for (int i = 0; i < num_other; ++i) {
-        double per_element_security_parameter =
-            security_parameter + std::log2(static_cast<double>(num_other));
-        DPF_ASSIGN_OR_RETURN(int el_bitsize,
-                             BitsNeeded(value_type.tuple().elements(i),
-                                        per_element_security_parameter));
-        bitsize_other += el_bitsize;
-      }
-    }
-    if (num_ints_mod_n > 0) {
-      DPF_ASSIGN_OR_RETURN(
-          absl::uint128 modulus,
-          ValueIntegerToUint128(int_mod_n->int_mod_n().modulus()));
-      DPF_ASSIGN_OR_RETURN(
-          int64_t bytes_needed_ints_mod_n,
-          dpf_internal::IntModNBase::GetNumBytesRequired(
-              num_ints_mod_n, int_mod_n->int_mod_n().base_integer().bitsize(),
-              modulus, security_parameter));
-      bitsize_ints_mod_n = bytes_needed_ints_mod_n * 8;
-    }
-    return bitsize_ints_mod_n + bitsize_other;
-  } else if (value_type.type_case() == ValueType::kIntModN) {
-    DPF_ASSIGN_OR_RETURN(
-        absl::uint128 modulus,
-        ValueIntegerToUint128(value_type.int_mod_n().modulus()));
-    DPF_ASSIGN_OR_RETURN(int64_t bytes_needed_ints_mod_n,
-                         dpf_internal::IntModNBase::GetNumBytesRequired(
-                             1, value_type.int_mod_n().base_integer().bitsize(),
-                             modulus, security_parameter));
-    return 8 * bytes_needed_ints_mod_n;
-  } else if (value_type.type_case() == ValueType::kXorWrapper) {
-    return value_type.xor_wrapper().bitsize();
-  }
-  return absl::InvalidArgumentError(absl::StrCat(
-      "BitsNeeded: Unsupported ValueType:\n", value_type.DebugString()));
-}
-
-// Integer Helpers
-
-Value::Integer Uint128ToValueInteger(absl::uint128 input) {
-  Value::Integer result;
-  if (absl::Uint128High64(input) == 0) {
-    result.set_value_uint64(absl::Uint128Low64(input));
-  } else {
-    Block& block = *(result.mutable_value_uint128());
-    block.set_high(absl::Uint128High64(input));
-    block.set_low(absl::Uint128Low64(input));
-  }
-  return result;
-}
-
-absl::StatusOr<absl::uint128> ValueIntegerToUint128(const Value::Integer& in) {
-  if (in.value_case() == Value::Integer::kValueUint128) {
-    return absl::MakeUint128(in.value_uint128().high(),
-                             in.value_uint128().low());
-  } else if (in.value_case() == Value::Integer::kValueUint64) {
-    return in.value_uint64();
-  }
-  return absl::InvalidArgumentError(
-      "Unknown value case for the given integer Value");
-}
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers.h b/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers.h
deleted file mode 100644
index 1e283487..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers.h
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_VALUE_TYPE_HELPERS_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_VALUE_TYPE_HELPERS_H_
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <array>
-#include <limits>
-#include <string>
-#include <tuple>
-#include <type_traits>
-#include <vector>
-
-#include "absl/base/config.h"
-#include "absl/log/absl_check.h"
-#include "absl/meta/type_traits.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/str_format.h"
-#include "absl/strings/string_view.h"
-#include "absl/utility/utility.h"
-#include "dpf/distributed_point_function.pb.h"
-#include "dpf/int_mod_n.h"
-#include "dpf/tuple.h"
-#include "dpf/xor_wrapper.h"
-#include "google/protobuf/repeated_field.h"
-
-// Contains a collection of helper functions for different DPF value types. This
-// includes functions for converting between Value protos and the corresponding
-// C++ objects, as well as functions for sampling values from uniformly random
-// byte strings.
-//
-// This file contains the templated declarations, instantiations for all
-// supported types, as well as type-independent function declarations.
-namespace distributed_point_functions {
-namespace dpf_internal {
-
-// A helper struct containing declarations for all templated functions we need.
-// This is needed since C++ doesn't support partial function template
-// specialization, and should be specialized for all supported types.
-template <typename T, typename = void>
-struct ValueTypeHelper {
-  // General type traits and conversion functions. Should be implemented by all
-  // types.
-
-  // Type trait for all supported types. Used to provide meaningful error
-  // messages in std::enable_if template guards.
-  static constexpr bool IsSupportedType() { return false; }
-
-  // Checks if the template parameter can be converted directly from a string of
-  // bytes.
-  static constexpr bool CanBeConvertedDirectly();
-
-  // Converts a given Value to the template parameter T.
-  static absl::StatusOr<T> FromValue(const Value& value);
-
-  // ToValue Converts the argument to a Value proto.
-  static Value ToValue(const T& input);
-
-  // ToValueType<T> Returns a `ValueType` message describing T.
-  static ValueType ToValueType();
-
-  // Functions for converting from a byte string to T. There are two approaches:
-  // Either converting directly (i.e., each byte is copied 1-to-1 into the
-  // result), or by sampling (when a direct conversion is not possible). Types
-  // for which CanBeConvertedDirectly() can be true should implement the former,
-  // and all types should implement the latter (to support types composed of
-  // directly-convertible and not-directly-convertible types).
-
-  // Functions for direct conversions from bytes. Should be implemented when
-  // CanBeConvertedDirectly() can be true.
-
-  // Returns the total number of bits in a T.
-  static constexpr int TotalBitSize();
-
-  static T DirectlyFromBytes(absl::string_view bytes);
-
-  // Functions for sampling from a string of bytes. Should be implemented by all
-  // types.
-
-  // Converts `block` to type T. Then, if `update == true`, fills up `block`
-  // from `remaining_bytes` and advances `remaining_bytes` by the amount of
-  // bytes read.
-  static T SampleAndUpdateBytes(bool update, absl::uint128& block,
-                                absl::string_view& remaining_bytes);
-};
-
-/******************************************************************************/
-// Type traits                                                                //
-/******************************************************************************/
-
-// Type trait for all supported types. Used to provide meaningful error messages
-// in std::enable_if template guards.
-template <typename T>
-struct is_supported_type {
-  static constexpr bool value =
-      dpf_internal::ValueTypeHelper<T>::IsSupportedType();
-};
-template <typename T>
-constexpr bool is_supported_type_v = is_supported_type<T>::value;
-
-// Checks if the template parameter can be converted directly from a string of
-// bytes.
-template <typename T>
-struct can_be_converted_directly {
-  static constexpr bool value =
-      dpf_internal::ValueTypeHelper<T>::CanBeConvertedDirectly();
-};
-template <typename T>
-constexpr bool can_be_converted_directly_v =
-    can_be_converted_directly<T>::value;
-
-// Returns the total number of bits in a T.
-template <typename T,
-          typename = absl::enable_if_t<can_be_converted_directly_v<T>>>
-static constexpr int TotalBitSize() {
-  return ValueTypeHelper<T>::TotalBitSize();
-}
-
-/******************************************************************************/
-// Integer Helpers                                                            //
-/******************************************************************************/
-
-// Type trait for all integer types we support, i.e., 8 to 128 bit types.
-template <typename T>
-using is_unsigned_integer =
-    absl::disjunction<std::is_same<T, uint8_t>, std::is_same<T, uint16_t>,
-                      std::is_same<T, uint32_t>, std::is_same<T, uint64_t>,
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-                      std::is_same<T, unsigned __int128>,
-#endif
-                      std::is_same<T, absl::uint128>>;
-template <typename T>
-constexpr bool is_unsigned_integer_v = is_unsigned_integer<T>::value;
-
-// Converts the given Value::Integer to an absl::uint128. Used as a helper
-// function in `ConvertValueTo` and `ValueTypesAreEqual`.
-//
-// Returns INVALID_ARGUMENT if `in` is not a simple integer or IntModN.
-absl::StatusOr<absl::uint128> ValueIntegerToUint128(const Value::Integer& in);
-
-// Converts an absl::uint128 to a Value::Integer. Used as a helper function in
-// ToValue.
-Value::Integer Uint128ToValueInteger(absl::uint128 input);
-
-// Checks if the given value is in range of T, and if so, returns it converted
-// to T.
-//
-// Otherwise returns INVALID_ARGUMENT.
-template <typename T, typename = absl::enable_if_t<is_unsigned_integer_v<T>>>
-absl::StatusOr<T> Uint128To(absl::uint128 in) {
-  // Check whether value is in range if it's smaller than 128 bits.
-  if (!std::is_same<T, absl::uint128>::value &&
-      absl::Uint128Low64(in) >
-          static_cast<uint64_t>(std::numeric_limits<T>::max())) {
-    return absl::InvalidArgumentError(absl::StrCat(
-        "Value (= ", absl::Uint128Low64(in),
-        ") too large for the given type T (size ", sizeof(T), ")"));
-  }
-  return static_cast<T>(in);
-}
-
-// Implementation of ValueTypeHelper for integers.
-template <typename T>
-struct ValueTypeHelper<T, absl::enable_if_t<is_unsigned_integer_v<T>>> {
-  static constexpr bool IsSupportedType() { return true; }
-
-  static constexpr bool CanBeConvertedDirectly() { return true; }
-
-  static absl::StatusOr<T> FromValue(const Value& value) {
-    if (value.value_case() != Value::kInteger) {
-      return absl::InvalidArgumentError("The given Value is not an integer");
-    }
-    // We first parse the value into an absl::uint128, then check its range if
-    // it is supposed to be smaller than 128 bits.
-    absl::StatusOr<absl::uint128> value_128 =
-        ValueIntegerToUint128(value.integer());
-    if (!value_128.ok()) {
-      return value_128.status();
-    }
-    return Uint128To<T>(*value_128);
-  }
-
-  static Value ToValue(T input) {
-    Value result;
-    *(result.mutable_integer()) = Uint128ToValueInteger(input);
-    return result;
-  }
-
-  static ValueType ToValueType() {
-    ValueType result;
-    result.mutable_integer()->set_bitsize(8 * sizeof(T));
-    return result;
-  }
-
-  static constexpr int TotalBitSize() { return sizeof(T) * 8; }
-
-  static T DirectlyFromBytes(absl::string_view bytes) {
-    ABSL_CHECK(bytes.size() == sizeof(T));
-    T out{0};
-#ifdef ABSL_IS_LITTLE_ENDIAN
-    std::copy_n(bytes.begin(), sizeof(T), reinterpret_cast<char*>(&out));
-#else
-    for (int i = sizeof(T) - 1; i >= 0; --i) {
-      out |= absl::bit_cast<uint8_t>(bytes[i]);
-      out <<= 8;
-    }
-#endif
-    return out;
-  }
-
-  static T SampleAndUpdateBytes(bool update, absl::uint128& block,
-                                absl::string_view& remaining_bytes) {
-    T result = static_cast<T>(block);
-
-    if (update) {
-      // Set sizeof(T) least significant bytes to 0.
-      if (sizeof(T) < sizeof(block)) {
-        constexpr absl::uint128 mask =
-            ~absl::uint128{std::numeric_limits<T>::max()};
-        block &= mask;
-      } else {
-        block = 0;
-      }
-
-      // Fill up with `bytes` and advance `bytes` by sizeof(T).
-      ABSL_DCHECK(remaining_bytes.size() >= sizeof(T));
-      block |= DirectlyFromBytes(remaining_bytes.substr(0, sizeof(T)));
-      remaining_bytes = remaining_bytes.substr(sizeof(T));
-    }
-
-    return result;
-  }
-};
-
-/******************************************************************************/
-// IntModN Helpers                                                            //
-/******************************************************************************/
-
-template <typename BaseInteger, typename ModulusType, ModulusType kModulus>
-struct ValueTypeHelper<
-    dpf_internal::IntModNImpl<BaseInteger, ModulusType, kModulus>, void> {
-  using IntModNType =
-      dpf_internal::IntModNImpl<BaseInteger, ModulusType, kModulus>;
-
-  static constexpr bool IsSupportedType() {
-    return is_unsigned_integer_v<BaseInteger> &&
-           is_unsigned_integer_v<ModulusType>;
-  }
-
-  static constexpr bool CanBeConvertedDirectly() { return false; }
-
-  static absl::StatusOr<IntModNType> FromValue(const Value& value) {
-    if (value.value_case() != Value::kIntModN) {
-      return absl::InvalidArgumentError("The given Value is not an IntModN");
-    }
-    absl::StatusOr<absl::uint128> value_128 =
-        ValueIntegerToUint128(value.int_mod_n());
-    if (!value_128.ok()) {
-      return value_128.status();
-    }
-    if (*value_128 >= absl::uint128{kModulus}) {
-      return absl::InvalidArgumentError(absl::StrFormat(
-          "The given value (= %d) is larger than kModulus (= %d)", *value_128,
-          absl::uint128{kModulus}));
-    }
-    return IntModNType(static_cast<BaseInteger>(*value_128));
-  }
-
-  static Value ToValue(IntModNType input) {
-    Value result;
-    *(result.mutable_int_mod_n()) = Uint128ToValueInteger(input.value());
-    return result;
-  }
-
-  static ValueType ToValueType() {
-    ValueType result;
-    *(result.mutable_int_mod_n()->mutable_base_integer()) =
-        ValueTypeHelper<BaseInteger>::ToValueType().integer();
-    *(result.mutable_int_mod_n()->mutable_modulus()) =
-        ValueTypeHelper<ModulusType>::ToValue(kModulus).integer();
-    return result;
-  }
-
-  static IntModNType SampleAndUpdateBytes(bool update, absl::uint128& block,
-                                          absl::string_view& remaining_bytes) {
-    // Optimization for native uint128. This is equivalent to what's done in
-    // int128.cc, but since division is not defined in the header, the compiler
-    // cannot optimize the division and modulus into a single operation.
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-    absl::uint128 quotient = static_cast<unsigned __int128>(block) / kModulus,
-                  remainder = static_cast<unsigned __int128>(block) % kModulus;
-#else
-    absl::uint128 quotient = block / kModulus, remainder = block % kModulus;
-#endif
-    IntModNType result(static_cast<BaseInteger>(remainder));
-
-    if (update) {
-      if (sizeof(BaseInteger) < sizeof(block)) {
-        block = quotient << (sizeof(BaseInteger) * 8);
-      } else {
-        block = 0;
-      }
-      block |= ValueTypeHelper<BaseInteger>::DirectlyFromBytes(
-          remaining_bytes.substr(0, sizeof(BaseInteger)));
-      remaining_bytes = remaining_bytes.substr(sizeof(BaseInteger));
-    }
-
-    return result;
-  }
-};
-
-/******************************************************************************/
-// Tuple Helpers                                                              //
-/******************************************************************************/
-
-// Helper struct for computing the bit size of a tuple type at compile time
-// without C++17 fold expressions.
-template <typename FirstElementType, typename... ElementType>
-struct TupleBitSizeHelper {
-  static constexpr int TotalBitSize() {
-    return TupleBitSizeHelper<FirstElementType>::TotalBitSize() +
-           TupleBitSizeHelper<ElementType...>::TotalBitSize();
-  }
-};
-template <typename ElementType>
-struct TupleBitSizeHelper<ElementType> {
-  static constexpr int TotalBitSize() {
-    return ValueTypeHelper<ElementType>::TotalBitSize();
-  }
-};
-
-template <typename... ElementType>
-struct ValueTypeHelper<Tuple<ElementType...>, void> {
-  using TupleType = Tuple<ElementType...>;
-
-  static constexpr bool IsSupportedType() {
-    return absl::conjunction<is_supported_type<ElementType>...>::value;
-  }
-
-  static constexpr bool CanBeConvertedDirectly() {
-    return absl::conjunction<can_be_converted_directly<ElementType>...>::value;
-  }
-
-  static absl::StatusOr<TupleType> FromValue(const Value& value) {
-    if (value.value_case() != Value::kTuple) {
-      return absl::InvalidArgumentError("The given Value is not a tuple");
-    }
-    constexpr auto tuple_size =
-        static_cast<int>(std::tuple_size<typename TupleType::Base>());
-    if (value.tuple().elements_size() != tuple_size) {
-      return absl::InvalidArgumentError(
-          "The tuple in the given Value has the wrong number of elements");
-    }
-
-    // Create a Tuple by unpacking value.tuple().elements(). If we encounter an
-    // error, return it at the end.
-    absl::Status status = absl::OkStatus();
-    int element_index = 0;
-    // The braced initializer list ensures elements are created in the correct
-    // order (unlike std::make_tuple).
-    TupleType result = {[&value, &status, &element_index] {
-      if (status.ok()) {
-        absl::StatusOr<ElementType> element =
-            ValueTypeHelper<ElementType>::FromValue(
-                value.tuple().elements(element_index));
-        element_index++;
-        if (element.ok()) {
-          return *element;
-        } else {
-          status = element.status();
-        }
-      }
-      return ElementType{};
-    }()...};
-    if (status.ok()) {
-      return result;
-    } else {
-      return status;
-    }
-  }
-
-  static Value ToValue(const TupleType& input) {
-    Value result;
-    absl::apply(
-        [&result](const ElementType&... elements) {
-          // Create an unused std::tuple to iterate over `elements` in its
-          // constructor. This can be replaced by a fold expression in C++17.
-          std::tuple<ElementType...>{
-              (*(result.mutable_tuple()->add_elements()) =
-                   ValueTypeHelper<ElementType>::ToValue(elements),
-               ElementType{})...};
-        },
-        input.value());
-    return result;
-  }
-
-  static ValueType ToValueType() {
-    ValueType result;
-    ValueType::Tuple* tuple = result.mutable_tuple();
-    // Create an unused std::tuple to iterate over `elements` in its
-    // constructor. This can be replaced by a fold expression in C++17.
-    std::tuple<ElementType...>{
-        (*(tuple->add_elements()) = ValueTypeHelper<ElementType>::ToValueType(),
-         ElementType{})...};
-    return result;
-  }
-
-  static constexpr int TotalBitSize() {
-    // This helper can be replaced by a fold expression in C++17.
-    return TupleBitSizeHelper<ElementType...>::TotalBitSize();
-  }
-
-  static TupleType DirectlyFromBytes(absl::string_view bytes) {
-    ABSL_CHECK(8 * bytes.size() >= TotalBitSize());
-    int offset = 0;
-    absl::Status status = absl::OkStatus();
-    // Braced-init-list ensures the elements are constructed in-order.
-    return TupleType{[&bytes, &offset, &status] {
-      constexpr int element_size_bytes =
-          (ValueTypeHelper<ElementType>::TotalBitSize() + 7) / 8;
-      ElementType element = ValueTypeHelper<ElementType>::DirectlyFromBytes(
-          bytes.substr(offset, element_size_bytes));
-      offset += element_size_bytes;
-      return element;
-    }()...};
-  }
-
-  static TupleType SampleAndUpdateBytes(bool update, absl::uint128& block,
-                                        absl::string_view& remaining_bytes) {
-    int element_counter = 0;
-    // Braced-init-list ensures the elements are constructed in-order.
-    return TupleType{[update, &element_counter, &block,
-                      &remaining_bytes]() -> ElementType {
-      // If `update` is true, update after all elements. Otherwise, don't update
-      // after the last one.
-      constexpr int num_elements = std::tuple_size<typename TupleType::Base>();
-      bool update2 = update || (++element_counter < num_elements);
-      return ValueTypeHelper<ElementType>::SampleAndUpdateBytes(
-          update2, block, remaining_bytes);
-    }()...};
-  }
-};
-
-/******************************************************************************/
-// XorWrapper Helpers                                                         //
-/******************************************************************************/
-
-template <typename T>
-struct ValueTypeHelper<XorWrapper<T>, void> {
-  static constexpr bool IsSupportedType() {
-    return ValueTypeHelper<T>::IsSupportedType();
-  }
-
-  static constexpr bool CanBeConvertedDirectly() {
-    return ValueTypeHelper<T>::CanBeConvertedDirectly();
-  }
-
-  static absl::StatusOr<XorWrapper<T>> FromValue(const Value& value) {
-    absl::StatusOr<absl::uint128> wrapped128 =
-        ValueIntegerToUint128(value.xor_wrapper());
-    if (!wrapped128.ok()) {
-      return wrapped128.status();
-    }
-    absl::StatusOr<T> wrapped = Uint128To<T>(*wrapped128);
-    if (!wrapped.ok()) {
-      return wrapped.status();
-    }
-    return XorWrapper<T>(*wrapped);
-  }
-
-  static Value ToValue(const XorWrapper<T>& input) {
-    Value result;
-    *(result.mutable_xor_wrapper()) = Uint128ToValueInteger(input.value());
-    return result;
-  }
-
-  static ValueType ToValueType() {
-    ValueType result;
-    *(result.mutable_xor_wrapper()) =
-        ValueTypeHelper<T>::ToValueType().integer();
-    return result;
-  }
-
-  static constexpr int TotalBitSize() {
-    return ValueTypeHelper<T>::TotalBitSize();
-  }
-
-  static XorWrapper<T> DirectlyFromBytes(absl::string_view bytes) {
-    return XorWrapper<T>(ValueTypeHelper<T>::DirectlyFromBytes(bytes));
-  }
-
-  static XorWrapper<T> SampleAndUpdateBytes(
-      bool update, absl::uint128& block, absl::string_view& remaining_bytes) {
-    return XorWrapper<T>(ValueTypeHelper<T>::SampleAndUpdateBytes(
-        update, block, remaining_bytes));
-  }
-};
-
-/******************************************************************************/
-// Free standing helpers. These should always come last. When adding          //
-// additional types, add them above.                                          //
-/******************************************************************************/
-
-// Computes the number of values of type T that fit into an absl::uint128.
-// Returns a value >= 1 if batching is supported, and 1 otherwise.
-template <typename T,
-          absl::enable_if_t<can_be_converted_directly_v<T>, int> = 0>
-constexpr int ElementsPerBlock() {
-  if (TotalBitSize<T>() <= 128) {
-    return static_cast<int>(8 * sizeof(absl::uint128)) / TotalBitSize<T>();
-  }
-  return 1;
-}
-template <typename T,
-          absl::enable_if_t<!can_be_converted_directly_v<T>, int> = 0>
-constexpr int ElementsPerBlock() {
-  return 1;
-}
-
-// Creates a value of type T from the given `bytes`. If possible, converts bytes
-// directly using DirectlyFromBytes. Otherwise, uses SampleAndUpdateBytes.
-//
-// Crashes if `bytes.size()` is too small for the output type.
-template <typename T,
-          absl::enable_if_t<can_be_converted_directly_v<T>, int> = 0>
-T FromBytes(absl::string_view bytes) {
-  return ValueTypeHelper<T>::DirectlyFromBytes(bytes);
-}
-template <typename T,
-          absl::enable_if_t<!can_be_converted_directly_v<T>, int> = 0>
-T FromBytes(absl::string_view bytes) {
-  absl::uint128 block =
-      FromBytes<absl::uint128>(bytes.substr(0, sizeof(absl::uint128)));
-  bytes = bytes.substr(sizeof(absl::uint128));
-  return ValueTypeHelper<T>::SampleAndUpdateBytes(false, block, bytes);
-}
-
-// Converts a `repeated Value` proto field to a std::array with element type T.
-//
-// Returns INVALID_ARGUMENT in case the input has the wrong size, or if the
-// conversion fails.
-template <typename T>
-absl::StatusOr<std::array<T, ElementsPerBlock<T>()>> ValuesToArray(
-    const ::google::protobuf::RepeatedPtrField<Value>& values) {
-  if (values.size() != ElementsPerBlock<T>()) {
-    return absl::InvalidArgumentError(absl::StrCat(
-        "values.size() (= ", values.size(),
-        ") does not match ElementsPerBlock<T>() (= ", ElementsPerBlock<T>(),
-        ")"));
-  }
-  std::array<T, ElementsPerBlock<T>()> result;
-  for (int i = 0; i < ElementsPerBlock<T>(); ++i) {
-    absl::StatusOr<T> element = ValueTypeHelper<T>::FromValue(values[i]);
-    if (element.ok()) {
-      result[i] = std::move(*element);
-    } else {
-      return element.status();
-    }
-  }
-  return result;
-}
-
-// Converts a given string to an array of exactly ElementsPerBlock<T>() elements
-// of type T.
-//
-// Crashes if `bytes.size()` is too small for the output type.
-template <typename T,
-          absl::enable_if_t<can_be_converted_directly_v<T>, int> = 0>
-std::array<T, ElementsPerBlock<T>()> ConvertBytesToArrayOf(
-    absl::string_view bytes) {
-  std::array<T, ElementsPerBlock<T>()> out;
-  const int element_size_bytes = (TotalBitSize<T>() + 7) / 8;
-  ABSL_CHECK(bytes.size() >= ElementsPerBlock<T>() * element_size_bytes);
-  for (int i = 0; i < ElementsPerBlock<T>(); ++i) {
-    out[i] =
-        FromBytes<T>(bytes.substr(i * element_size_bytes, element_size_bytes));
-  }
-  return out;
-}
-template <typename T,
-          absl::enable_if_t<!can_be_converted_directly_v<T>, int> = 0>
-std::array<T, ElementsPerBlock<T>()> ConvertBytesToArrayOf(
-    absl::string_view bytes) {
-  static_assert(ElementsPerBlock<T>() == 1,
-                "T does not support batching, but ElementsPerBlock<T> != 1");
-  return {FromBytes<T>(bytes)};
-}
-
-// Computes the value correction word given two seeds `seed_a`, `seed_b` for
-// parties a and b, such that the element at `block_index` is equal to `beta`.
-// If `invert` is true, the result is multiplied element-wise by -1. Templated
-// to use the correct integer type without needing modular reduction.
-//
-// Returns multiple values in case of packing, and a single value otherwise.
-template <typename T>
-absl::StatusOr<std::vector<Value>> ComputeValueCorrectionFor(
-    absl::string_view seed_a, absl::string_view seed_b, int block_index,
-    const Value& beta, bool invert) {
-  absl::StatusOr<T> beta_T = ValueTypeHelper<T>::FromValue(beta);
-  if (!beta_T.ok()) {
-    return beta_T.status();
-  }
-
-  constexpr int elements_per_block = ElementsPerBlock<T>();
-
-  // Compute values from seeds. Both arrays will have multiple elements if T
-  // supports batching, and a single one otherwise.
-  std::array<T, elements_per_block> ints_a = ConvertBytesToArrayOf<T>(seed_a),
-                                    ints_b = ConvertBytesToArrayOf<T>(seed_b);
-
-  // Add beta to the right position.
-  ints_b[block_index] += *beta_T;
-
-  // Add up shares, invert if needed.
-  for (int i = 0; i < elements_per_block; i++) {
-    ints_b[i] = ints_b[i] - ints_a[i];
-    if (invert) {
-      ints_b[i] = -ints_b[i];
-    }
-  }
-
-  // Convert to a vector of Value protos and return.
-  std::vector<Value> result;
-  result.reserve(ints_b.size());
-  for (const T& element : ints_b) {
-    result.push_back(ValueTypeHelper<T>::ToValue(element));
-  }
-  return result;
-}
-
-// Computes the number of pseudorandom bits needed to get a uniform element of
-// the given `ValueType`. For types whose elements can be bijectively mapped to
-// strings (e.g., unsigned integers and tuples of integers), this is equivalent
-// to the bit size of the value type. For all other types, returns the number of
-// bits needed so that converting a uniform string with the given number of bits
-// to an element of `value_type` results in a distribution with total variation
-// distance < 2^(-`security_parameter`) from uniform.
-//
-// Returns INVALID_ARGUMENT in case value_type does not represent a known type,
-// or if sampling with the required security parameter is not possible.
-absl::StatusOr<int> BitsNeeded(const ValueType& value_type,
-                               double security_parameter);
-
-// Returns `true` if `lhs` and `rhs` describe the same types, and `false`
-// otherwise.
-//
-// Returns INVALID_ARGUMENT if an error occurs while parsing either argument.
-absl::StatusOr<bool> ValueTypesAreEqual(const ValueType& lhs,
-                                        const ValueType& rhs);
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_INTERNAL_VALUE_TYPE_HELPERS_H_
diff --git a/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers_test.cc b/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers_test.cc
deleted file mode 100644
index 1abec0af..0000000
--- a/third_party/distributed_point_functions/code/dpf/internal/value_type_helpers_test.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/internal/value_type_helpers.h"
-
-#include <stdint.h>
-
-#include <array>
-#include <string>
-#include <tuple>
-
-#include "absl/base/config.h"
-#include "absl/numeric/int128.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/str_cat.h"
-#include "dpf/distributed_point_function.pb.h"
-#include "dpf/int_mod_n.h"
-#include "dpf/internal/status_matchers.h"
-#include "dpf/tuple.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-namespace dpf_internal {
-namespace {
-
-constexpr int kDefaultSecurityParameter = 40;
-
-TEST(ValueTypeHelperTest, ValueTypesAreEqualFailsOnInvalidValueTypes) {
-  ValueType type1, type2;
-
-  EXPECT_THAT(ValueTypesAreEqual(type1, type2),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Both arguments must be valid ValueTypes"));
-}
-
-TEST(ValueTypeHelperTest, BitsNeededFailsOnInvalidValueType) {
-  EXPECT_THAT(
-      BitsNeeded(ValueType{}, kDefaultSecurityParameter),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               testing::StartsWith("BitsNeeded: Unsupported ValueType")));
-}
-
-template <typename T>
-class ValueTypeIntegerTest : public testing::Test {};
-using IntegerTypes =
-    ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, absl::uint128>;
-TYPED_TEST_SUITE(ValueTypeIntegerTest, IntegerTypes);
-
-TYPED_TEST(ValueTypeIntegerTest, ToValueTypeIntegers) {
-  ValueType value_type = ValueTypeHelper<TypeParam>::ToValueType();
-
-  EXPECT_TRUE(value_type.has_integer());
-  EXPECT_EQ(value_type.integer().bitsize(), sizeof(TypeParam) * 8);
-}
-
-TYPED_TEST(ValueTypeIntegerTest, TestValueTypesAreEqual) {
-  ValueType value_type_1 = ValueTypeHelper<TypeParam>::ToValueType(),
-            value_type_2;
-  value_type_2.mutable_integer()->set_bitsize(sizeof(TypeParam) * 8);
-
-  DPF_ASSERT_OK_AND_ASSIGN(bool equal,
-                           ValueTypesAreEqual(value_type_1, value_type_2));
-  EXPECT_TRUE(equal);
-  DPF_ASSERT_OK_AND_ASSIGN(equal,
-                           ValueTypesAreEqual(value_type_2, value_type_1));
-  EXPECT_TRUE(equal);
-}
-
-TYPED_TEST(ValueTypeIntegerTest, TestValueTypesAreNotEqual) {
-  ValueType value_type_1 = ValueTypeHelper<TypeParam>::ToValueType(),
-            value_type_2;
-  value_type_2.mutable_integer()->set_bitsize(sizeof(TypeParam) * 8 * 2);
-
-  DPF_ASSERT_OK_AND_ASSIGN(bool equal,
-                           ValueTypesAreEqual(value_type_1, value_type_2));
-  EXPECT_FALSE(equal);
-  DPF_ASSERT_OK_AND_ASSIGN(equal,
-                           ValueTypesAreEqual(value_type_2, value_type_1));
-  EXPECT_FALSE(equal);
-}
-
-TYPED_TEST(ValueTypeIntegerTest, ValueConversionFailsIfNotInteger) {
-  Value value;
-  value.mutable_tuple();
-
-  EXPECT_THAT(ValueTypeHelper<TypeParam>::FromValue(value),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "The given Value is not an integer"));
-}
-
-TYPED_TEST(ValueTypeIntegerTest, ValueConversionFailsIfInvalidIntegerCase) {
-  Value value;
-  value.mutable_integer();
-
-  EXPECT_THAT(ValueTypeHelper<TypeParam>::FromValue(value),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Unknown value case for the given integer Value"));
-}
-
-TYPED_TEST(ValueTypeIntegerTest, ValueConversionFailsIfValueOutOfRange) {
-  Value value;
-  auto value_64 = uint64_t{1} << 32;
-  value.mutable_integer()->set_value_uint64(value_64);
-
-  if (sizeof(TypeParam) >= sizeof(uint64_t)) {
-    DPF_EXPECT_OK(ValueTypeHelper<TypeParam>::FromValue(value));
-  } else {
-    EXPECT_THAT(ValueTypeHelper<TypeParam>::FromValue(value),
-                StatusIs(absl::StatusCode::kInvalidArgument,
-                         absl::StrCat("Value (= ", value_64,
-                                      ") too large for the given type T (size ",
-                                      sizeof(TypeParam), ")")));
-  }
-}
-
-template <typename T>
-class ValueTypeTupleTest : public testing::Test {};
-
-template <typename T, int... bits>
-struct TupleTestParam {
-  using Tuple = T;
-  static constexpr int ExpectedNumElements() { return sizeof...(bits); };
-  static constexpr std::array<int, ExpectedNumElements()> ExpectedBitSizes() {
-    return {bits...};
-  }
-};
-
-// We only test tuples consisting of integers here.
-using TupleTypes = ::testing::Types<
-    TupleTestParam<Tuple<uint64_t>, 64>,
-    TupleTestParam<Tuple<uint64_t, uint64_t>, 64, 64>,
-    TupleTestParam<Tuple<uint32_t, absl::uint128, uint8_t>, 32, 128, 8>,
-    TupleTestParam<Tuple<uint8_t, uint8_t, uint8_t, uint8_t>, 8, 8, 8, 8>>;
-TYPED_TEST_SUITE(ValueTypeTupleTest, TupleTypes);
-
-TYPED_TEST(ValueTypeTupleTest, ToValueTypeTuples) {
-  ValueType value_type =
-      ValueTypeHelper<typename TypeParam::Tuple>::ToValueType();
-
-  constexpr int expected_num_elements = TypeParam::ExpectedNumElements();
-  EXPECT_TRUE(value_type.has_tuple());
-  ASSERT_EQ(std::tuple_size<typename TypeParam::Tuple::Base>(),
-            expected_num_elements);  // Sanity check for test parameters.
-  EXPECT_EQ(value_type.tuple().elements_size(), expected_num_elements);
-
-  std::array<int, expected_num_elements> expected_bit_sizes =
-      TypeParam::ExpectedBitSizes();
-  for (int i = 0; i < expected_num_elements; ++i) {
-    EXPECT_TRUE(value_type.tuple().elements(i).has_integer());
-    EXPECT_EQ(value_type.tuple().elements(i).integer().bitsize(),
-              expected_bit_sizes[i]);
-  }
-}
-
-TYPED_TEST(ValueTypeTupleTest, BitsNeededEqualsCompileTimeTypeSize) {
-  ValueType value_type =
-      ValueTypeHelper<typename TypeParam::Tuple>::ToValueType();
-
-  DPF_ASSERT_OK_AND_ASSIGN(int bitsize,
-                           BitsNeeded(value_type, kDefaultSecurityParameter));
-
-  EXPECT_EQ(bitsize, TotalBitSize<typename TypeParam::Tuple>());
-}
-
-TYPED_TEST(ValueTypeTupleTest, ValueConversionFailsIfValueIsNotATuple) {
-  Value value;
-  value.mutable_integer();
-
-  EXPECT_THAT(ValueTypeHelper<Tuple<uint32_t>>::FromValue(value),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "The given Value is not a tuple"));
-}
-
-TEST(ValueTypeTupleTest, ValueConversionFailsIfValueSizeDoesntMatchTupleSize) {
-  Value value;
-  value.mutable_tuple()->add_elements()->mutable_integer()->set_value_uint64(
-      1234);
-
-  using TupleType = Tuple<uint32_t, uint32_t>;
-  EXPECT_THAT(
-      ValueTypeHelper<TupleType>::FromValue(value),
-      StatusIs(
-          absl::StatusCode::kInvalidArgument,
-          "The tuple in the given Value has the wrong number of elements"));
-}
-
-TEST(ValueTypeTupleTest, TestValueTypesAreEqual) {
-  using T1 = Tuple<uint32_t, absl::uint128, uint8_t>;
-  using T2 = Tuple<uint32_t, absl::uint128, uint8_t>;
-
-  ValueType value_type_1 = ValueTypeHelper<T1>::ToValueType();
-  ValueType value_type_2 = ValueTypeHelper<T2>::ToValueType();
-
-  DPF_ASSERT_OK_AND_ASSIGN(bool equal,
-                           ValueTypesAreEqual(value_type_1, value_type_2));
-  EXPECT_TRUE(equal);
-  DPF_ASSERT_OK_AND_ASSIGN(equal,
-                           ValueTypesAreEqual(value_type_2, value_type_1));
-  EXPECT_TRUE(equal);
-}
-
-TEST(ValueTypeTupleTest, TestValueTypesAreNotEqual) {
-  using T1 = Tuple<uint32_t, absl::uint128, uint8_t>;
-  using T2 = Tuple<uint32_t, absl::uint128, uint16_t>;
-
-  ValueType value_type_1 = ValueTypeHelper<T1>::ToValueType();
-  ValueType value_type_2 = ValueTypeHelper<T2>::ToValueType();
-
-  DPF_ASSERT_OK_AND_ASSIGN(bool equal,
-                           ValueTypesAreEqual(value_type_1, value_type_2));
-  EXPECT_FALSE(equal);
-  DPF_ASSERT_OK_AND_ASSIGN(equal,
-                           ValueTypesAreEqual(value_type_2, value_type_1));
-  EXPECT_FALSE(equal);
-}
-
-TEST(ValueTypeTupleTest, TestFromBytesWithConcreteExample) {
-  std::string bytes = "A 128 bit string";
-
-  auto tuple = FromBytes<Tuple<uint64_t, uint64_t>>(bytes);
-  EXPECT_EQ(std::get<0>(tuple.value()), FromBytes<uint64_t>("A 128 bi"));
-  EXPECT_EQ(std::get<1>(tuple.value()), FromBytes<uint64_t>("t string"));
-}
-
-TEST(ValueTypeTupleTest, TestFromBytesWithConcreteExampleForIntModN) {
-  constexpr uint32_t kModulus = 4294967291u;
-  using MyIntModN = IntModN<uint32_t, kModulus>;
-  std::string bytes = "A 128+32 bit string.";
-
-  absl::uint128 block = FromBytes<absl::uint128>("A 128+32 bit str");
-  MyIntModN expected_0(static_cast<uint32_t>(block % kModulus));
-  block /= kModulus;
-  block <<= (8 * sizeof(uint32_t));
-  block |= FromBytes<uint32_t>("ing.");
-  MyIntModN expected_1(static_cast<uint32_t>(block % kModulus));
-
-  auto tuple = FromBytes<Tuple<MyIntModN, MyIntModN>>(bytes).value();
-  EXPECT_EQ(std::get<0>(tuple), expected_0);
-  EXPECT_EQ(std::get<1>(tuple), expected_1);
-}
-
-template <typename T>
-class ValueTypeIntModNTest : public testing::Test {};
-using IntModNTypes = ::testing::Types<
-    IntModN<uint32_t, 4>, IntModN<uint32_t, 4294967291u>,
-    IntModN<uint64_t, 4294967291ull>, IntModN<uint64_t, 1000000000000ull>
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-    ,
-    IntModN<absl::uint128, (unsigned __int128)(absl::MakeUint128(
-                               65535u, 18446744073709551551ull))>  // 2**80-65
-#endif
-    >;
-TYPED_TEST_SUITE(ValueTypeIntModNTest, IntModNTypes);
-
-TYPED_TEST(ValueTypeIntModNTest, ToValueType) {
-  ValueType value_type = ValueTypeHelper<TypeParam>::ToValueType();
-
-  EXPECT_TRUE(value_type.type_case() == ValueType::kIntModN);
-  EXPECT_EQ(value_type.int_mod_n().base_integer().bitsize(),
-            sizeof(typename TypeParam::Base) * 8);
-  DPF_ASSERT_OK_AND_ASSIGN(
-      absl::uint128 modulus,
-      ValueIntegerToUint128(value_type.int_mod_n().modulus()));
-  EXPECT_EQ(modulus, absl::uint128{TypeParam::modulus()});
-}
-
-TYPED_TEST(ValueTypeIntModNTest, TestValueTypesAreEqual) {
-  ValueType value_type_1 = ValueTypeHelper<TypeParam>::ToValueType(),
-            value_type_2;
-
-  value_type_2.mutable_int_mod_n()->mutable_base_integer()->set_bitsize(
-      sizeof(TypeParam) * 8);
-  *(value_type_2.mutable_int_mod_n()->mutable_modulus()) =
-      Uint128ToValueInteger(TypeParam::modulus());
-
-  DPF_ASSERT_OK_AND_ASSIGN(bool equal,
-                           ValueTypesAreEqual(value_type_1, value_type_2));
-  EXPECT_TRUE(equal);
-  DPF_ASSERT_OK_AND_ASSIGN(equal,
-                           ValueTypesAreEqual(value_type_2, value_type_1));
-  EXPECT_TRUE(equal);
-}
-
-TYPED_TEST(ValueTypeIntModNTest, TestValueTypesAreDifferentBase) {
-  ValueType value_type_1 = ValueTypeHelper<TypeParam>::ToValueType(),
-            value_type_2 = value_type_1;
-
-  value_type_2.mutable_int_mod_n()->mutable_base_integer()->set_bitsize(
-      sizeof(TypeParam) * 8 * 2);
-
-  DPF_ASSERT_OK_AND_ASSIGN(bool equal,
-                           ValueTypesAreEqual(value_type_1, value_type_2));
-  EXPECT_FALSE(equal);
-  DPF_ASSERT_OK_AND_ASSIGN(equal,
-                           ValueTypesAreEqual(value_type_2, value_type_1));
-  EXPECT_FALSE(equal);
-};
-
-TYPED_TEST(ValueTypeIntModNTest, TestValueTypesAreDifferentModulus) {
-  ValueType value_type_1 = ValueTypeHelper<TypeParam>::ToValueType(),
-            value_type_2 = value_type_1;
-
-  *(value_type_2.mutable_int_mod_n()->mutable_modulus()) =
-      Uint128ToValueInteger(TypeParam::modulus() - 1);
-
-  DPF_ASSERT_OK_AND_ASSIGN(bool equal,
-                           ValueTypesAreEqual(value_type_1, value_type_2));
-  EXPECT_FALSE(equal);
-  DPF_ASSERT_OK_AND_ASSIGN(equal,
-                           ValueTypesAreEqual(value_type_2, value_type_1));
-  EXPECT_FALSE(equal);
-}
-
-TYPED_TEST(ValueTypeIntModNTest, ValueTypesAreEqualFailsWhenModulusInvalid) {
-  ValueType value_type_1 = ValueTypeHelper<TypeParam>::ToValueType(),
-            value_type_2 = value_type_1;
-
-  value_type_2.mutable_int_mod_n()->clear_modulus();
-
-  EXPECT_THAT(ValueTypesAreEqual(value_type_1, value_type_2),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "Unknown value case for the given integer Value"));
-}
-
-TYPED_TEST(ValueTypeIntModNTest, ValueConversionFailsIfNotInteger) {
-  Value value;
-  value.mutable_tuple();
-
-  EXPECT_THAT(ValueTypeHelper<TypeParam>::FromValue(value),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       "The given Value is not an IntModN"));
-}
-
-TYPED_TEST(ValueTypeIntModNTest, ValueConversionFailsIfTooLargeForModulus) {
-  Value value;
-  *(value.mutable_int_mod_n()) = Uint128ToValueInteger(TypeParam::modulus());
-
-  EXPECT_THAT(ValueTypeHelper<TypeParam>::FromValue(value),
-              StatusIs(absl::StatusCode::kInvalidArgument,
-                       testing::HasSubstr("is larger than kModulus")));
-}
-
-}  // namespace
-
-}  // namespace dpf_internal
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/status_macros.h b/third_party/distributed_point_functions/code/dpf/status_macros.h
deleted file mode 100644
index 9949ec4..0000000
--- a/third_party/distributed_point_functions/code/dpf/status_macros.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_UTIL_STATUS_MACROS_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_UTIL_STATUS_MACROS_H_
-
-// Helper macro that checks if the right hand side (rexpression) evaluates to a
-// StatusOr with Status OK, and if so assigns the value to the value on the left
-// hand side (lhs), otherwise returns the error status. Example:
-//   DPF_ASSIGN_OR_RETURN(lhs, rexpression);
-#define DPF_ASSIGN_OR_RETURN(lhs, rexpr) \
-  DPF_ASSIGN_OR_RETURN_IMPL_(            \
-      DPF_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), lhs, rexpr)
-
-// Internal helper.
-#define DPF_ASSIGN_OR_RETURN_IMPL_(statusor, lhs, rexpr) \
-  auto statusor = (rexpr);                               \
-  if (ABSL_PREDICT_FALSE(!statusor.ok())) {              \
-    return std::move(statusor).status();                 \
-  }                                                      \
-  lhs = std::move(statusor).value()
-
-// Internal helper for concatenating macro values.
-#define DPF_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y) x##y
-#define DPF_STATUS_MACROS_IMPL_CONCAT_(x, y) \
-  DPF_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y)
-
-#define DPF_RETURN_IF_ERROR(expr)                                              \
-  DPF_RETURN_IF_ERROR_IMPL_(DPF_STATUS_MACROS_IMPL_CONCAT_(_status, __LINE__), \
-                            expr)
-
-#define DPF_RETURN_IF_ERROR_IMPL_(status, expr) \
-  auto status = (expr);                         \
-  if (ABSL_PREDICT_FALSE(!status.ok())) {       \
-    return status;                              \
-  }
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_UTIL_STATUS_MACROS_H_
diff --git a/third_party/distributed_point_functions/code/dpf/tuple.h b/third_party/distributed_point_functions/code/dpf/tuple.h
deleted file mode 100644
index 48627b38..0000000
--- a/third_party/distributed_point_functions/code/dpf/tuple.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_TUPLE_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_TUPLE_H_
-
-#include <stddef.h>
-
-#include <tuple>
-#include <utility>
-
-namespace distributed_point_functions {
-
-// A Tuple class with added element-wise addition, subtraction, and negation
-// operators.
-template <typename... T>
-class Tuple {
- public:
-  using Base = std::tuple<T...>;
-
-  Tuple() {}
-  Tuple(T... elements) : value_(elements...) {}
-  explicit Tuple(Base t) : value_(std::move(t)) {}
-
-  // Copy constructor.
-  Tuple(const Tuple& t) = default;
-  Tuple& operator=(const Tuple& t) = default;
-
-  // Getters for the base tuple type.
-  Base& value() { return value_; }
-  const Base& value() const { return value_; }
-
- private:
-  Base value_;
-};
-
-namespace dpf_internal {
-
-// Implementation of addition and negation. See
-// https://stackoverflow.com/a/50815143.
-// We declare the templates here, but define them at the end of this header
-// because the definitions need to make use of operator+ and operator-.
-template <typename... T, std::size_t... I>
-constexpr Tuple<T...> add(const Tuple<T...>& lhs, const Tuple<T...>& rhs,
-                          std::index_sequence<I...>);
-
-template <typename... T, std::size_t... I>
-constexpr Tuple<T...> negate(const Tuple<T...>& t, std::index_sequence<I...>);
-
-}  // namespace dpf_internal
-
-template <typename... T>
-constexpr Tuple<T...> operator+(const Tuple<T...>& lhs,
-                                const Tuple<T...>& rhs) {
-  return dpf_internal::add(lhs, rhs, std::make_index_sequence<sizeof...(T)>{});
-}
-
-template <typename... T>
-constexpr Tuple<T...>& operator+=(Tuple<T...>& lhs, const Tuple<T...>& rhs) {
-  lhs = lhs + rhs;
-  return lhs;
-}
-
-template <typename... T>
-constexpr Tuple<T...> operator-(const Tuple<T...>& t) {
-  return dpf_internal::negate(t, std::make_index_sequence<sizeof...(T)>{});
-}
-
-template <typename... T>
-constexpr Tuple<T...> operator-(const Tuple<T...>& lhs,
-                                const Tuple<T...>& rhs) {
-  return lhs + (-rhs);
-}
-
-template <typename... T>
-constexpr Tuple<T...>& operator-=(Tuple<T...>& lhs, const Tuple<T...>& rhs) {
-  lhs = lhs - rhs;
-  return lhs;
-}
-
-// Equality and inequality operators.
-template <typename... T>
-constexpr bool operator==(const Tuple<T...>& lhs, const Tuple<T...>& rhs) {
-  return lhs.value() == rhs.value();
-}
-
-template <typename... T>
-constexpr bool operator!=(const Tuple<T...>& lhs, const Tuple<T...>& rhs) {
-  return lhs.value() != rhs.value();
-}
-
-namespace dpf_internal {
-template <typename... T, std::size_t... I>
-constexpr Tuple<T...> add(const Tuple<T...>& lhs, const Tuple<T...>& rhs,
-                          std::index_sequence<I...>) {
-  return Tuple<T...>{std::get<I>(lhs.value()) + std::get<I>(rhs.value())...};
-}
-
-template <typename... T, std::size_t... I>
-constexpr Tuple<T...> negate(const Tuple<T...>& t, std::index_sequence<I...>) {
-  return Tuple<T...>{
-      // Explicitly cast to T to avoid -Wnarrowing warnings for small integers.
-      T(-std::get<I>(t.value()))...};
-}
-}  // namespace dpf_internal
-
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_TUPLE_H_
diff --git a/third_party/distributed_point_functions/code/dpf/tuple_test.cc b/third_party/distributed_point_functions/code/dpf/tuple_test.cc
deleted file mode 100644
index 993a9984..0000000
--- a/third_party/distributed_point_functions/code/dpf/tuple_test.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/tuple.h"
-
-#include <tuple>
-
-#include "absl/numeric/int128.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-
-namespace {
-
-using T = Tuple<int, double, absl::uint128>;
-
-TEST(TupleTest, TestAddition) {
-  T a(std::make_tuple(1, 2, 3));
-  T b(std::make_tuple(4, 5, 6));
-
-  T c = a + b;
-
-  EXPECT_EQ(std::get<0>(c.value()),
-            std::get<0>(a.value()) + std::get<0>(b.value()));
-  EXPECT_EQ(std::get<1>(c.value()),
-            std::get<1>(a.value()) + std::get<1>(b.value()));
-  EXPECT_EQ(std::get<2>(c.value()),
-            std::get<2>(a.value()) + std::get<2>(b.value()));
-}
-
-TEST(TupleTest, TestAdditionInplace) {
-  T a(std::make_tuple(1, 2, 3));
-  T b(std::make_tuple(4, 5, 6));
-
-  T a2 = a;
-  a += b;
-
-  EXPECT_EQ(std::get<0>(a.value()),
-            std::get<0>(a2.value()) + std::get<0>(b.value()));
-  EXPECT_EQ(std::get<1>(a.value()),
-            std::get<1>(a2.value()) + std::get<1>(b.value()));
-  EXPECT_EQ(std::get<2>(a.value()),
-            std::get<2>(a2.value()) + std::get<2>(b.value()));
-}
-TEST(TupleTest, TestSubtraction) {
-  T a(std::make_tuple(1, 2, 3));
-  T b(std::make_tuple(4, 5, 6));
-
-  T c = a - b;
-
-  EXPECT_EQ(std::get<0>(c.value()),
-            std::get<0>(a.value()) - std::get<0>(b.value()));
-  EXPECT_EQ(std::get<1>(c.value()),
-            std::get<1>(a.value()) - std::get<1>(b.value()));
-  EXPECT_EQ(std::get<2>(c.value()),
-            std::get<2>(a.value()) - std::get<2>(b.value()));
-}
-
-TEST(TupleTest, TestSubtractionInplace) {
-  T a(std::make_tuple(1, 2, 3));
-  T b(std::make_tuple(4, 5, 6));
-
-  T a2 = a;
-  a -= b;
-
-  EXPECT_EQ(std::get<0>(a.value()),
-            std::get<0>(a2.value()) - std::get<0>(b.value()));
-  EXPECT_EQ(std::get<1>(a.value()),
-            std::get<1>(a2.value()) - std::get<1>(b.value()));
-  EXPECT_EQ(std::get<2>(a.value()),
-            std::get<2>(a2.value()) - std::get<2>(b.value()));
-}
-
-TEST(TupleTest, TestNegation) {
-  T a(std::make_tuple(1, 2, 3));
-
-  T a2 = -a;
-
-  EXPECT_EQ(std::get<0>(a2.value()), -std::get<0>(a.value()));
-  EXPECT_EQ(std::get<1>(a2.value()), -std::get<1>(a.value()));
-  EXPECT_EQ(std::get<2>(a2.value()), -std::get<2>(a.value()));
-}
-
-}  // namespace
-
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/code/dpf/xor_wrapper.h b/third_party/distributed_point_functions/code/dpf/xor_wrapper.h
deleted file mode 100644
index 31166be8..0000000
--- a/third_party/distributed_point_functions/code/dpf/xor_wrapper.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * 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.
- */
-
-#ifndef DISTRIBUTED_POINT_FUNCTIONS_DPF_XOR_WRAPPER_H_
-#define DISTRIBUTED_POINT_FUNCTIONS_DPF_XOR_WRAPPER_H_
-
-#include <utility>
-
-namespace distributed_point_functions {
-
-// Wraps the given type, replacing additions and subtractions by XOR.
-template <typename T>
-class XorWrapper {
- public:
-  using WrappedType = T;
-
-  constexpr XorWrapper() : wrapped_{} {}
-  explicit constexpr XorWrapper(T wrapped) : wrapped_(std::move(wrapped)) {}
-
-  // XorWrapper is copyable and movable.
-  constexpr XorWrapper(const XorWrapper&) = default;
-  constexpr XorWrapper& operator=(const XorWrapper&) = default;
-  constexpr XorWrapper(XorWrapper&&) = default;
-  constexpr XorWrapper& operator=(XorWrapper&&) = default;
-
-  // Assignment operators.
-  constexpr XorWrapper& operator+=(const XorWrapper& rhs) {
-    wrapped_ ^= rhs.value();
-    return *this;
-  }
-  constexpr XorWrapper& operator-=(const XorWrapper& rhs) {
-    wrapped_ ^= rhs.value();
-    return *this;
-  }
-
-  // Returns a reference to the wrapped object.
-  constexpr T& value() { return wrapped_; }
-  constexpr const T& value() const { return wrapped_; }
-
- private:
-  T wrapped_;
-};
-
-template <typename T>
-constexpr XorWrapper<T> operator+(XorWrapper<T> a, const XorWrapper<T>& b) {
-  a += b;
-  return a;
-}
-
-template <typename T>
-constexpr XorWrapper<T> operator-(XorWrapper<T> a, const XorWrapper<T>& b) {
-  a -= b;
-  return a;
-}
-
-// Negation does nothing in XOR sharing, since -a = 0-a.
-template <typename T>
-constexpr XorWrapper<T> operator-(const XorWrapper<T>& a) {
-  return a;
-}
-
-template <typename T>
-constexpr bool operator==(const XorWrapper<T>& a, const XorWrapper<T>& b) {
-  return a.value() == b.value();
-}
-
-template <typename T>
-constexpr bool operator!=(const XorWrapper<T>& a, const XorWrapper<T>& b) {
-  return !(a == b);
-}
-
-}  // namespace distributed_point_functions
-
-#endif  // DISTRIBUTED_POINT_FUNCTIONS_DPF_XOR_WRAPPER_H_
diff --git a/third_party/distributed_point_functions/code/dpf/xor_wrapper_test.cc b/third_party/distributed_point_functions/code/dpf/xor_wrapper_test.cc
deleted file mode 100644
index b5fda9e..0000000
--- a/third_party/distributed_point_functions/code/dpf/xor_wrapper_test.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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.
-
-#include "dpf/xor_wrapper.h"
-
-#include <stdint.h>
-
-#include "absl/numeric/int128.h"
-#include "gtest/gtest.h"
-
-namespace distributed_point_functions {
-
-namespace {
-
-template <typename T>
-class XorWrapperTest : public testing::Test {};
-using XorWrapperTypes =
-    testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, absl::uint128>;
-
-TYPED_TEST_SUITE(XorWrapperTest, XorWrapperTypes);
-
-TYPED_TEST(XorWrapperTest, TestConstructor) {
-  TypeParam value{42};
-
-  XorWrapper<TypeParam> wrapper(value);
-
-  EXPECT_EQ(wrapper.value(), value);
-}
-
-TYPED_TEST(XorWrapperTest, TestAddition) {
-  TypeParam a{42}, b{23};
-  XorWrapper<TypeParam> wrapped_a(a), wrapped_b(b);
-
-  EXPECT_EQ((wrapped_a + wrapped_b).value(), a ^ b);
-}
-
-TYPED_TEST(XorWrapperTest, TestSubtraction) {
-  TypeParam a{42}, b{23};
-  XorWrapper<TypeParam> wrapped_a(a), wrapped_b(b);
-
-  EXPECT_EQ((wrapped_a - wrapped_b).value(), a ^ b);
-}
-
-TYPED_TEST(XorWrapperTest, TestNegation) {
-  TypeParam value{42};
-  XorWrapper<TypeParam> wrapper(value);
-
-  EXPECT_EQ((-wrapper).value(), value);
-}
-
-TYPED_TEST(XorWrapperTest, TestEquality) {
-  TypeParam a{42}, b{23};
-  XorWrapper<TypeParam> wrapped_a(a), wrapped_b(b);
-
-  EXPECT_EQ(wrapped_a, XorWrapper<TypeParam>(a));
-  EXPECT_NE(wrapped_a, XorWrapper<TypeParam>(b));
-}
-
-}  // namespace
-
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/features.gni b/third_party/distributed_point_functions/features.gni
deleted file mode 100644
index fd6f285f..0000000
--- a/third_party/distributed_point_functions/features.gni
+++ /dev/null
@@ -1,9 +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.
-
-declare_args() {
-  use_distributed_point_functions = is_debug
-  dpf_abseil_cpp_dir = "//third_party/abseil-cpp"
-  dpf_highway_cpp_dir = "//third_party/highway"
-}
diff --git a/third_party/distributed_point_functions/fuzz/dpf_fuzzer.cc b/third_party/distributed_point_functions/fuzz/dpf_fuzzer.cc
deleted file mode 100644
index 8589935..0000000
--- a/third_party/distributed_point_functions/fuzz/dpf_fuzzer.cc
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/distributed_point_functions/code/dpf/distributed_point_function.h"
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <fuzzer/FuzzedDataProvider.h>
-
-#include <algorithm>
-#include <memory>
-
-#define DPF_FUZZER_ASSERT(x)                                         \
-  if (!(x)) {                                                        \
-    printf("DPF assertion failed: function %s, file %s, line %d.\n", \
-           __PRETTY_FUNCTION__, __FILE__, __LINE__);                 \
-    abort();                                                         \
-  }
-
-namespace {
-
-const size_t UINT128_SIZE = 2 * sizeof(uint64_t);
-
-// Constructs a `uint128` numeric value from two 64-bit unsigned integers
-// consumed from the data provider.
-absl::uint128 ConsumeUint128(FuzzedDataProvider& data_provider) {
-  uint64_t high = data_provider.ConsumeIntegral<uint64_t>();
-  uint64_t low = data_provider.ConsumeIntegral<uint64_t>();
-  return absl::MakeUint128(high, low);
-}
-
-// Returns the prefix of `index` for the domain of `hierarchy_level`.
-// Adapted from `DpfEvaluationTest::GetPrefixForLevel()`.
-absl::uint128 GetPrefixForLevel(
-    int hierarchy_level,
-    absl::uint128 index,
-    const std::vector<distributed_point_functions::DpfParameters>& parameters) {
-  absl::uint128 result = 0;
-  int shift_amount = parameters.back().log_domain_size() -
-                     parameters[hierarchy_level].log_domain_size();
-  if (shift_amount < 128)
-    result = index >> shift_amount;
-  return result;
-}
-
-// Evaluates both contexts `ctx0` and `ctx1` at `hierarchy level`, using the
-// appropriate prefixes of `evaluation_points`. Checks that the expansion of
-// both keys from correct DPF shares, i.e., they add up to
-// `beta[ctx.hierarchy_level()]` under prefixes of `alpha`, and to 0 otherwise.
-// Adapted from `DpfEvaluationTest::EvaluateAndCheckLevel()`.
-template <typename T>
-void EvaluateAndCheckLevel(
-    int hierarchy_level,
-    absl::Span<const absl::uint128> evaluation_points,
-    absl::uint128 alpha,
-    const std::vector<absl::uint128>& beta,
-    distributed_point_functions::EvaluationContext& ctx0,
-    distributed_point_functions::EvaluationContext& ctx1,
-    const std::vector<distributed_point_functions::DpfParameters>& parameters,
-    const distributed_point_functions::DistributedPointFunction& dpf) {
-  int previous_hierarchy_level = ctx0.previous_hierarchy_level();
-  int current_log_domain_size = parameters[hierarchy_level].log_domain_size();
-  int previous_log_domain_size = 0;
-  int num_expansions = 1;
-  bool is_first_evaluation = previous_hierarchy_level < 0;
-  // Generate prefixes if we're not on the first level.
-  std::vector<absl::uint128> prefixes;
-  if (!is_first_evaluation) {
-    num_expansions = static_cast<int>(evaluation_points.size());
-    prefixes.resize(evaluation_points.size());
-    previous_log_domain_size =
-        parameters[previous_hierarchy_level].log_domain_size();
-    for (int i = 0; i < static_cast<int>(evaluation_points.size()); ++i)
-      prefixes[i] = GetPrefixForLevel(previous_hierarchy_level,
-                                      evaluation_points[i], parameters);
-  }
-
-  // Evaluating a key with N correction words leads to an O(2^N) malloc, which
-  // will unsurprisingly cause a fuzzer crash. See <https://crbug.com/1494260>.
-  constexpr size_t kMaxCorrectionWords = 30;
-  if (ctx0.key().correction_words().size() > kMaxCorrectionWords) {
-    return;
-  }
-  absl::StatusOr<std::vector<T>> result_0 =
-      dpf.EvaluateUntil<T>(hierarchy_level, prefixes, ctx0);
-  DPF_FUZZER_ASSERT(result_0.ok());
-  if (ctx1.key().correction_words().size() > kMaxCorrectionWords) {
-    return;
-  }
-  absl::StatusOr<std::vector<T>> result_1 =
-      dpf.EvaluateUntil<T>(hierarchy_level, prefixes, ctx1);
-  DPF_FUZZER_ASSERT(result_1.ok());
-
-  DPF_FUZZER_ASSERT(result_0->size() == result_1->size());
-  int64_t outputs_per_prefix =
-      int64_t{1} << (current_log_domain_size - previous_log_domain_size);
-  int64_t expected_output_size = num_expansions * outputs_per_prefix;
-  DPF_FUZZER_ASSERT(static_cast<int64_t>(result_0->size()) ==
-                    expected_output_size);
-
-  // Iterator over the outputs and check that they sum up to 0 or to
-  // `beta[current_hierarchy_level]`;
-  absl::uint128 previous_alpha_prefix = 0;
-  if (!is_first_evaluation)
-    previous_alpha_prefix =
-        GetPrefixForLevel(previous_hierarchy_level, alpha, parameters);
-
-  absl::uint128 current_alpha_prefix =
-      GetPrefixForLevel(hierarchy_level, alpha, parameters);
-  for (int64_t i = 0; i < expected_output_size; ++i) {
-    int prefix_index = i / outputs_per_prefix;
-    int prefix_expansion_index = i % outputs_per_prefix;
-    // The output is on the path to `alpha`, if we're at the first level or
-    // under a prefix of `alpha`, and the current block in the expansion of the
-    // prefix is also on the path to `alpha`.
-    if ((is_first_evaluation ||
-         prefixes[prefix_index] == previous_alpha_prefix) &&
-        prefix_expansion_index == (current_alpha_prefix % outputs_per_prefix)) {
-      // We need to static_cast here since otherwise operator+ returns an
-      // unsigned int without doing a modular reduction, which causes the test
-      // to fail on types with sizeof(T) < sizeof(unsigned).
-      DPF_FUZZER_ASSERT(
-          absl::uint128{static_cast<T>((*result_0)[i] + (*result_1)[i])} ==
-          beta[hierarchy_level]);
-    } else {
-      DPF_FUZZER_ASSERT(static_cast<T>((*result_0)[i] + (*result_1)[i]) == 0U);
-    }
-  }
-}
-
-}  // namespace
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  // Use magic separator to split the input into two parts. The first part will
-  // generate alpha, and an array of parameters and betas. The second part will
-  // generate level step and an array of evaluation points.
-  const uint8_t separator[] = {0xDE, 0xAD, 0xBE, 0xEF};
-
-  const uint8_t* pos =
-      std::search(data, data + size, separator, separator + sizeof(separator));
-
-  const uint8_t* data1 = data;
-  size_t size1 = pos - data;
-
-  const uint8_t* data2 =
-      (pos == data + size) ? nullptr : pos + sizeof(separator);
-  size_t size2 = data2 ? (data + size) - (pos + sizeof(separator)) : 0;
-
-  FuzzedDataProvider data_provider1(data1, size1);
-
-  if (data_provider1.remaining_bytes() < UINT128_SIZE)
-    return 0;
-
-  absl::uint128 alpha = ConsumeUint128(data_provider1);
-
-  std::vector<int32_t> log_domain_sizes;
-  std::vector<int32_t> element_bitsizes;
-  std::vector<distributed_point_functions::DpfParameters> parameters;
-  std::vector<absl::uint128> beta;
-
-  // log_domain_size(int32_t), element_bitsize(int32_t),
-  // beta(uint128)
-  while (data_provider1.remaining_bytes() >=
-         (2 * sizeof(int32_t) + UINT128_SIZE)) {
-    int32_t log_domain_size = data_provider1.ConsumeIntegral<int32_t>();
-    int32_t element_bitsize = data_provider1.ConsumeIntegral<int32_t>();
-    log_domain_sizes.push_back(log_domain_size);
-    element_bitsizes.push_back(element_bitsize);
-
-    distributed_point_functions::DpfParameters parameter;
-    parameter.set_log_domain_size(log_domain_size);
-    parameter.mutable_value_type()->mutable_integer()->set_bitsize(
-        element_bitsize);
-    parameters.push_back(parameter);
-
-    beta.push_back(ConsumeUint128(data_provider1));
-  }
-
-  absl::StatusOr<
-      std::unique_ptr<distributed_point_functions::DistributedPointFunction>>
-      status_or_dpf = distributed_point_functions::DistributedPointFunction::
-          CreateIncremental(parameters);
-
-  size_t num_levels = parameters.size();
-
-  if (!status_or_dpf.ok()) {
-    // `log_domain_size` is expected to be in ascending order and
-    // `element_bitsize` is expected to be non-decreasing. As it is hard for the
-    // fuzzer to land upon a valid input, we sort the parameters and try again
-    // if the construction fails.
-    std::sort(log_domain_sizes.begin(), log_domain_sizes.end());
-    std::sort(element_bitsizes.begin(), element_bitsizes.end());
-    for (size_t i = 0; i < num_levels; ++i) {
-      parameters[i].set_log_domain_size(log_domain_sizes[i]);
-      parameters[i].mutable_value_type()->mutable_integer()->set_bitsize(
-          element_bitsizes[i]);
-    }
-
-    status_or_dpf = distributed_point_functions::DistributedPointFunction::
-        CreateIncremental(parameters);
-  }
-
-  if (!status_or_dpf.ok())
-    return 0;
-
-  std::unique_ptr<distributed_point_functions::DistributedPointFunction> dpf =
-      std::move(status_or_dpf).value();
-
-  absl::StatusOr<std::pair<distributed_point_functions::DpfKey,
-                           distributed_point_functions::DpfKey>>
-      status_or_keys = dpf->GenerateKeysIncremental(alpha, beta);
-  if (!status_or_keys.ok())
-    return 0;
-
-  std::pair<distributed_point_functions::DpfKey,
-            distributed_point_functions::DpfKey>
-      keys = std::move(status_or_keys).value();
-
-  // Adapted from `DpfEvaluationTest.TestCorrectness()`.
-  absl::StatusOr<distributed_point_functions::EvaluationContext>
-      status_or_ctx0 = dpf->CreateEvaluationContext(keys.first);
-  DPF_FUZZER_ASSERT(status_or_ctx0.ok());
-
-  absl::StatusOr<distributed_point_functions::EvaluationContext>
-      status_or_ctx1 = dpf->CreateEvaluationContext(keys.second);
-  DPF_FUZZER_ASSERT(status_or_ctx1.ok());
-
-  distributed_point_functions::EvaluationContext ctx0 =
-      std::move(status_or_ctx0).value();
-  distributed_point_functions::EvaluationContext ctx1 =
-      std::move(status_or_ctx1).value();
-
-  // Generate evaluation points.
-  FuzzedDataProvider data_provider2(data2, size2);
-  if (data_provider2.remaining_bytes() < sizeof(int))
-    return 0;
-
-  int level_step = data_provider2.ConsumeIntegralInRange<int>(1, 10);
-
-  std::vector<absl::uint128> evaluation_points;
-  while (data_provider2.remaining_bytes() >= UINT128_SIZE) {
-    evaluation_points.push_back(ConsumeUint128(data_provider2));
-    if (parameters.back().log_domain_size() < 128)
-      evaluation_points.back() %=
-          (absl::uint128{1} << parameters.back().log_domain_size());
-  }
-
-  // Always evaluate on alpha.
-  evaluation_points.push_back(alpha);
-
-  int32_t previous_log_domain_size = 0;
-  for (int i = level_step - 1; i < static_cast<int>(num_levels);
-       i += level_step) {
-    // If any gap in the log_domain_sizes used in successive evaluations is
-    // larger than 62, validation will fail in `EvaluateAndCheckLevel`.
-    int32_t current_log_domain_size = parameters[i].log_domain_size();
-    if (current_log_domain_size - previous_log_domain_size > 62)
-      return 0;
-    previous_log_domain_size = current_log_domain_size;
-
-    switch (parameters[i].value_type().integer().bitsize()) {
-      case 8:
-        EvaluateAndCheckLevel<uint8_t>(i, evaluation_points, alpha, beta, ctx0,
-                                       ctx1, parameters, *dpf);
-        break;
-      case 16:
-        EvaluateAndCheckLevel<uint16_t>(i, evaluation_points, alpha, beta, ctx0,
-                                        ctx1, parameters, *dpf);
-        break;
-      case 32:
-        EvaluateAndCheckLevel<uint32_t>(i, evaluation_points, alpha, beta, ctx0,
-                                        ctx1, parameters, *dpf);
-        break;
-      case 64:
-        EvaluateAndCheckLevel<uint64_t>(i, evaluation_points, alpha, beta, ctx0,
-                                        ctx1, parameters, *dpf);
-        break;
-      case 128:
-        EvaluateAndCheckLevel<absl::uint128>(i, evaluation_points, alpha, beta,
-                                             ctx0, ctx1, parameters, *dpf);
-        break;
-      default:
-        // DPF construction should've failed if the parameters were invalid.
-        DPF_FUZZER_ASSERT(false);
-        break;
-    }
-  }
-
-  return 0;
-}
diff --git a/third_party/distributed_point_functions/shim/BUILD.gn b/third_party/distributed_point_functions/shim/BUILD.gn
deleted file mode 100644
index f2ce4cd..0000000
--- a/third_party/distributed_point_functions/shim/BUILD.gn
+++ /dev/null
@@ -1,48 +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.
-
-import("//build/buildflag_header.gni")
-import("//testing/test.gni")
-import("//third_party/distributed_point_functions/features.gni")
-
-source_set("shim") {
-  public_deps = [ ":buildflags" ]
-
-  if (use_distributed_point_functions) {
-    sources = [
-      "distributed_point_function_shim.cc",
-      "distributed_point_function_shim.h",
-    ]
-    deps = [
-      "$dpf_abseil_cpp_dir:absl",
-      "//base",
-      "//third_party/distributed_point_functions:internal",
-    ]
-    public_deps += [ "//third_party/distributed_point_functions:proto" ]
-    configs += [ "//third_party/distributed_point_functions:includes" ]
-  }
-}
-
-# External targets may depend on :buildflags directly without pulling in
-# :distributed_point_functions. For instance, tests may set different
-# expectations when the dpf library is omitted from the build.
-buildflag_header("buildflags") {
-  header = "buildflags.h"
-  flags = [ "USE_DISTRIBUTED_POINT_FUNCTIONS=$use_distributed_point_functions" ]
-}
-
-test("distributed_point_functions_shim_unittests") {
-  deps = [
-    "//testing/gtest",
-    "//testing/gtest:gtest_main",
-  ]
-  if (use_distributed_point_functions) {
-    sources = [ "distributed_point_function_shim_unittest.cc" ]
-    deps += [
-      ":shim",
-      "$dpf_abseil_cpp_dir:absl",
-      "//third_party/protobuf:protobuf_lite",
-    ]
-  }
-}
diff --git a/third_party/distributed_point_functions/shim/DEPS b/third_party/distributed_point_functions/shim/DEPS
deleted file mode 100644
index 5cd0867..0000000
--- a/third_party/distributed_point_functions/shim/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+base",
-]
diff --git a/third_party/distributed_point_functions/shim/distributed_point_function_shim.cc b/third_party/distributed_point_functions/shim/distributed_point_function_shim.cc
deleted file mode 100644
index 4cbf927c..0000000
--- a/third_party/distributed_point_functions/shim/distributed_point_function_shim.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-#include <optional>
-#include <utility>
-#include <vector>
-
-#include "base/check_op.h"
-#include "base/logging.h"
-#include "third_party/abseil-cpp/absl/numeric/int128.h"
-#include "third_party/abseil-cpp/absl/status/status.h"
-#include "third_party/abseil-cpp/absl/status/statusor.h"
-#include "third_party/distributed_point_functions/code/dpf/distributed_point_function.h"
-#include "third_party/distributed_point_functions/dpf/distributed_point_function.pb.h"
-#include "third_party/distributed_point_functions/shim/distributed_point_function_shim.h"
-
-namespace distributed_point_functions {
-std::optional<std::pair<DpfKey, DpfKey>> GenerateKeysIncremental(
-    std::vector<DpfParameters> parameters,
-    absl::uint128 alpha,
-    std::vector<absl::uint128> beta) {
-  // absl::StatusOr is not allowed in the codebase, but this minimal usage is
-  // necessary to interact with //third_party/distributed_point_functions/.
-  absl::StatusOr<std::unique_ptr<DistributedPointFunction>> dpf_result =
-      DistributedPointFunction::CreateIncremental(std::move(parameters));
-  if (!dpf_result.ok()) {
-    LOG(ERROR) << "CreateIncremental() failed: " << dpf_result.status();
-    return std::nullopt;
-  }
-  CHECK_NE(*dpf_result, nullptr);
-
-  absl::StatusOr<std::pair<DpfKey, DpfKey>> keys_result =
-      (*dpf_result)->GenerateKeysIncremental(alpha, std::move(beta));
-  if (!keys_result.ok()) {
-    LOG(ERROR) << "GenerateKeysIncremental() failed: " << keys_result.status();
-    return std::nullopt;
-  }
-  return std::move(*keys_result);
-}
-}  // namespace distributed_point_functions
diff --git a/third_party/distributed_point_functions/shim/distributed_point_function_shim.h b/third_party/distributed_point_functions/shim/distributed_point_function_shim.h
deleted file mode 100644
index 9165d9c..0000000
--- a/third_party/distributed_point_functions/shim/distributed_point_function_shim.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_AGGREGATION_SERVICE_DISTRIBUTED_POINT_FUNCTION_SHIM_H_
-#define CONTENT_BROWSER_AGGREGATION_SERVICE_DISTRIBUTED_POINT_FUNCTION_SHIM_H_
-
-#include "third_party/distributed_point_functions/shim/buildflags.h"
-
-static_assert(BUILDFLAG(USE_DISTRIBUTED_POINT_FUNCTIONS),
-              "This header must not be included when "
-              "distributed_point_functions is omitted from the build");
-
-#include <optional>
-#include <utility>
-#include <vector>
-
-#include "third_party/abseil-cpp/absl/numeric/int128.h"
-#include "third_party/distributed_point_functions/dpf/distributed_point_function.pb.h"
-
-namespace distributed_point_functions {
-
-// Generates a pair of keys for a DPF that evaluates to `beta` when given
-// `alpha`. On failure, returns std::nullopt.
-std::optional<std::pair<DpfKey, DpfKey>> GenerateKeysIncremental(
-    std::vector<DpfParameters> parameters,
-    absl::uint128 alpha,
-    std::vector<absl::uint128> beta);
-
-}  // namespace distributed_point_functions
-
-#endif  // CONTENT_BROWSER_AGGREGATION_SERVICE_DISTRIBUTED_POINT_FUNCTION_SHIM_H_
diff --git a/third_party/distributed_point_functions/shim/distributed_point_function_shim_unittest.cc b/third_party/distributed_point_functions/shim/distributed_point_function_shim_unittest.cc
deleted file mode 100644
index d39dcb9..0000000
--- a/third_party/distributed_point_functions/shim/distributed_point_function_shim_unittest.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-
-#include <optional>
-#include <utility>
-#include <vector>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/abseil-cpp/absl/numeric/int128.h"
-#include "third_party/distributed_point_functions/dpf/distributed_point_function.pb.h"
-#include "third_party/distributed_point_functions/shim/distributed_point_function_shim.h"
-
-namespace distributed_point_functions {
-
-// The shim's GenerateKeysIncremental() can return a value besides std::nullopt.
-TEST(DistributedPointFunctionShimTest, GenerateKeysIncrementalConstructsKeys) {
-  constexpr size_t kBitLength = 32;
-  std::vector<DpfParameters> parameters(kBitLength);
-  for (size_t i = 0; i < parameters.size(); ++i) {
-    parameters[i].set_log_domain_size(i + 1);
-    parameters[i].mutable_value_type()->mutable_integer()->set_bitsize(
-        parameters.size());
-  }
-  std::optional<std::pair<DpfKey, DpfKey>> maybe_dpf_keys =
-      GenerateKeysIncremental(
-          std::move(parameters),
-          /*alpha=*/absl::uint128{1},
-          /*beta=*/std::vector<absl::uint128>(kBitLength, absl::uint128{1}));
-  EXPECT_TRUE(maybe_dpf_keys.has_value());
-}
-
-// When DistributedPointFunction::CreateIncremental() fails, the shim's
-// GenerateKeysIncremental() should return std::nullopt.
-TEST(DistributedPointFunctionShimTest, GenerateKeysIncrementalEmptyParameters) {
-  EXPECT_FALSE(GenerateKeysIncremental(/*parameters=*/{},
-                                       /*alpha=*/absl::uint128{}, /*beta=*/{}));
-}
-
-// When the length of beta does not match the number of parameters, the internal
-// call to DistributedPointFunction::GenerateKeysIncremental() will fail, and
-// the shim's GenerateKeysIncremental() should return std::nullopt.
-TEST(DistributedPointFunctionShimTest, GenerateKeysIncrementalBetaWrongSize) {
-  std::vector<DpfParameters> parameters(3);
-  EXPECT_FALSE(
-      GenerateKeysIncremental(/*parameters=*/std::vector<DpfParameters>(3),
-                              /*alpha=*/absl::uint128{}, /*beta=*/{1, 2, 3}));
-}
-
-}  // namespace distributed_point_functions
diff --git a/third_party/highway/OWNERS b/third_party/highway/OWNERS
index 3216b48..cf40f20c 100644
--- a/third_party/highway/OWNERS
+++ b/third_party/highway/OWNERS
@@ -1 +1,2 @@
-file://third_party/distributed_point_functions/OWNERS
\ No newline at end of file
+bikineev@chromium.org
+file://third_party/blink/renderer/core/html/parser/OWNERS
diff --git a/third_party/jni_zero/codegen/natives_header.py b/third_party/jni_zero/codegen/natives_header.py
index 356b81a..2980233c 100644
--- a/third_party/jni_zero/codegen/natives_header.py
+++ b/third_party/jni_zero/codegen/natives_header.py
@@ -164,7 +164,7 @@
       return
 
     with sb.statement():
-      sb('jobject converted_ret = ')
+      sb('auto converted_ret = ')
       if native.needs_implicit_array_element_class_param:
         clazz_snippet = f'static_cast<jclass>({native.proxy_params[-1].name})'
       else:
@@ -173,7 +173,8 @@
                                      '_ret',
                                      return_type,
                                      clazz_snippet=clazz_snippet)
-      sb('.Release()')
+      if not return_type.is_primitive():
+        sb('.Release()')
 
     with sb.statement():
       sb('return ')
diff --git a/third_party/jni_zero/test/golden/testBidirectionalClass-Final-GEN_JNI.java.golden b/third_party/jni_zero/test/golden/testBidirectionalClass-Final-GEN_JNI.java.golden
index 1f9e453..54f527e 100644
--- a/third_party/jni_zero/test/golden/testBidirectionalClass-Final-GEN_JNI.java.golden
+++ b/third_party/jni_zero/test/golden/testBidirectionalClass-Final-GEN_JNI.java.golden
@@ -64,6 +64,8 @@
   public static native Object org_jni_1zero_SampleForTests_returnAString(
       long nativeCPPClass,
       Object caller);
+  // Hashed name: Java_J_N_MzWiT6ZI
+  public static native int org_jni_1zero_SampleForTests_returnFromEnum();
   // Hashed name: Java_J_N_MtJ0n$3y
   public static native void org_jni_1zero_SampleForTests_setNonPODDatatype(
       Object obj,
diff --git a/third_party/jni_zero/test/golden/testBidirectionalClass-Placeholder-GEN_JNI.java.golden b/third_party/jni_zero/test/golden/testBidirectionalClass-Placeholder-GEN_JNI.java.golden
index 8fcec3ba2..710aaa8e 100644
--- a/third_party/jni_zero/test/golden/testBidirectionalClass-Placeholder-GEN_JNI.java.golden
+++ b/third_party/jni_zero/test/golden/testBidirectionalClass-Placeholder-GEN_JNI.java.golden
@@ -27,5 +27,6 @@
   public static native double org_jni_1zero_SampleForTests_methodOtherP0(long nativePtr, Object caller);
   public static native Object org_jni_1zero_SampleForTests_primitiveArrays(Object b, Object c, Object s, Object i, Object l, Object f, Object d);
   public static native Object org_jni_1zero_SampleForTests_returnAString(long nativeCPPClass, Object caller);
+  public static native int org_jni_1zero_SampleForTests_returnFromEnum();
   public static native void org_jni_1zero_SampleForTests_setNonPODDatatype(Object obj, Object rect);
 }
diff --git a/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTestsJni.java.golden b/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTestsJni.java.golden
index cc5087e2..64760fc 100644
--- a/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTestsJni.java.golden
+++ b/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTestsJni.java.golden
@@ -156,6 +156,11 @@
   }
 
   @Override
+  public int returnFromEnum() {
+    return (int) GEN_JNI.org_jni_1zero_SampleForTests_returnFromEnum();
+  }
+
+  @Override
   public void setNonPODDatatype(SampleForTests obj, Rect rect) {
     assert obj != null : "Parameter \"obj\" was null. Add @Nullable to it?";
     assert rect != null : "Parameter \"rect\" was null. Add @Nullable to it?";
diff --git a/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden b/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden
index a811eaa..0182594 100644
--- a/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden
+++ b/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden
@@ -211,7 +211,7 @@
       env,
       jni_zero::JavaParamRef<jobject>(env, items));
   auto _ret = JNI_SampleForTests_ListTest2(env, items_converted);
-  jobject converted_ret = jni_zero::ToJniList(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniList(env, _ret).Release();
   return converted_ret;
 }
 
@@ -228,7 +228,7 @@
       env,
       jni_zero::JavaParamRef<jobject>(env, arg0));
   auto _ret = JNI_SampleForTests_MapTest2(env, arg0_converted);
-  jobject converted_ret = jni_zero::ToJniType(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniType(env, _ret).Release();
   return converted_ret;
 }
 
@@ -310,7 +310,7 @@
       l_converted,
       f_converted,
       d_converted);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret).Release();
   return converted_ret;
 }
 
@@ -326,6 +326,17 @@
 }
 
 // Forward declaration. To be implemented by the including .cc file.
+static MyEnum JNI_SampleForTests_ReturnFromEnum(JNIEnv* env);
+
+JNI_ZERO_BOUNDARY_EXPORT jint Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1SampleForTests_1returnFromEnum(
+    JNIEnv* env,
+    jclass jcaller) {
+  auto _ret = JNI_SampleForTests_ReturnFromEnum(env);
+  auto converted_ret = jni_zero::internal::PrimitiveConvert<MyEnum, jint>::ToJniType(env, _ret);
+  return static_cast<jint>(converted_ret);
+}
+
+// Forward declaration. To be implemented by the including .cc file.
 static void JNI_SampleForTests_SetNonPODDatatype(
     JNIEnv* env,
     const jni_zero::JavaParamRef<jobject>& obj,
diff --git a/third_party/jni_zero/test/golden/testEndToEndProxyHashed-SampleForAnnotationProcessor_jni.h.golden b/third_party/jni_zero/test/golden/testEndToEndProxyHashed-SampleForAnnotationProcessor_jni.h.golden
index b946bdb..31d6e1a0 100644
--- a/third_party/jni_zero/test/golden/testEndToEndProxyHashed-SampleForAnnotationProcessor_jni.h.golden
+++ b/third_party/jni_zero/test/golden/testEndToEndProxyHashed-SampleForAnnotationProcessor_jni.h.golden
@@ -90,7 +90,7 @@
     jclass jcaller,
     jobject __arrayClazz) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedAppObjects(env);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret, static_cast<jclass>(__arrayClazz)).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret, static_cast<jclass>(__arrayClazz)).Release();
   return converted_ret;
 }
 
@@ -101,7 +101,7 @@
     JNIEnv* env,
     jclass jcaller) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedInts(env);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret).Release();
   return converted_ret;
 }
 
@@ -112,7 +112,7 @@
     JNIEnv* env,
     jclass jcaller) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedString(env);
-  jobject converted_ret = jni_zero::ToJniType(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniType(env, _ret).Release();
   return converted_ret;
 }
 
@@ -124,7 +124,7 @@
     JNIEnv* env,
     jclass jcaller) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedStrings(env);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret, jni_zero::g_string_class).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret, jni_zero::g_string_class).Release();
   return converted_ret;
 }
 
@@ -323,7 +323,7 @@
       jni_zero::JavaParamRef<jfloatArray>(env, static_cast<jfloatArray>(floats)),
       zbool,
       jni_zero::JavaParamRef<jbooleanArray>(env, static_cast<jbooleanArray>(bools)));
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret).Release();
   return converted_ret;
 }
 
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-Placeholder-GEN_JNI.java.golden b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-Placeholder-GEN_JNI.java.golden
index aad48c72..124c3cd 100644
--- a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-Placeholder-GEN_JNI.java.golden
+++ b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-Placeholder-GEN_JNI.java.golden
@@ -27,5 +27,6 @@
   public static native double this_is_a_package_prefix_org_jni_1zero_SampleForTests_methodOtherP0(long nativePtr, Object caller);
   public static native Object this_is_a_package_prefix_org_jni_1zero_SampleForTests_primitiveArrays(Object b, Object c, Object s, Object i, Object l, Object f, Object d);
   public static native Object this_is_a_package_prefix_org_jni_1zero_SampleForTests_returnAString(long nativeCPPClass, Object caller);
+  public static native int this_is_a_package_prefix_org_jni_1zero_SampleForTests_returnFromEnum();
   public static native void this_is_a_package_prefix_org_jni_1zero_SampleForTests_setNonPODDatatype(Object obj, Object rect);
 }
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTestsJni.java.golden b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTestsJni.java.golden
index 69330e3..9e1418b 100644
--- a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTestsJni.java.golden
+++ b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTestsJni.java.golden
@@ -181,6 +181,11 @@
   }
 
   @Override
+  public int returnFromEnum() {
+    return (int) GEN_JNI.this_is_a_package_prefix_org_jni_1zero_SampleForTests_returnFromEnum();
+  }
+
+  @Override
   public void setNonPODDatatype(SampleForTests obj, Rect rect) {
     assert obj != null : "Parameter \"obj\" was null. Add @Nullable to it?";
     assert rect != null : "Parameter \"rect\" was null. Add @Nullable to it?";
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden
index 55f8927..c9ab5ab 100644
--- a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden
+++ b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden
@@ -211,7 +211,7 @@
       env,
       jni_zero::JavaParamRef<jobject>(env, items));
   auto _ret = JNI_SampleForTests_ListTest2(env, items_converted);
-  jobject converted_ret = jni_zero::ToJniList(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniList(env, _ret).Release();
   return converted_ret;
 }
 
@@ -228,7 +228,7 @@
       env,
       jni_zero::JavaParamRef<jobject>(env, arg0));
   auto _ret = JNI_SampleForTests_MapTest2(env, arg0_converted);
-  jobject converted_ret = jni_zero::ToJniType(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniType(env, _ret).Release();
   return converted_ret;
 }
 
@@ -310,7 +310,7 @@
       l_converted,
       f_converted,
       d_converted);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret).Release();
   return converted_ret;
 }
 
@@ -326,6 +326,17 @@
 }
 
 // Forward declaration. To be implemented by the including .cc file.
+static MyEnum JNI_SampleForTests_ReturnFromEnum(JNIEnv* env);
+
+JNI_ZERO_BOUNDARY_EXPORT jint Java_this_is_a_package_prefix_org_jni_1zero_GEN_1JNI_this_1is_1a_1package_1prefix_1org_1jni_11zero_1SampleForTests_1returnFromEnum(
+    JNIEnv* env,
+    jclass jcaller) {
+  auto _ret = JNI_SampleForTests_ReturnFromEnum(env);
+  auto converted_ret = jni_zero::internal::PrimitiveConvert<MyEnum, jint>::ToJniType(env, _ret);
+  return static_cast<jint>(converted_ret);
+}
+
+// Forward declaration. To be implemented by the including .cc file.
 static void JNI_SampleForTests_SetNonPODDatatype(
     JNIEnv* env,
     const jni_zero::JavaParamRef<jobject>& obj,
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-placeholder.srcjar.golden b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-placeholder.srcjar.golden
index 709c1bbc..6e045ab 100644
--- a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-placeholder.srcjar.golden
+++ b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-placeholder.srcjar.golden
@@ -33,6 +33,7 @@
     public double methodOtherP0(long nativePtr, org.jni_zero.SampleForTests caller);
     public boolean[] primitiveArrays(byte[] b, char[] c, short[] s, int[] i, long[] l, float[] f, double[] d);
     public String returnAString(long nativeCPPClass, org.jni_zero.SampleForTests caller);
+    public int returnFromEnum();
     public void setNonPODDatatype(org.jni_zero.SampleForTests obj, android.graphics.Rect rect);
   }
 }
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-Placeholder-GEN_JNI.java.golden b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-Placeholder-GEN_JNI.java.golden
index aad48c72..124c3cd 100644
--- a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-Placeholder-GEN_JNI.java.golden
+++ b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-Placeholder-GEN_JNI.java.golden
@@ -27,5 +27,6 @@
   public static native double this_is_a_package_prefix_org_jni_1zero_SampleForTests_methodOtherP0(long nativePtr, Object caller);
   public static native Object this_is_a_package_prefix_org_jni_1zero_SampleForTests_primitiveArrays(Object b, Object c, Object s, Object i, Object l, Object f, Object d);
   public static native Object this_is_a_package_prefix_org_jni_1zero_SampleForTests_returnAString(long nativeCPPClass, Object caller);
+  public static native int this_is_a_package_prefix_org_jni_1zero_SampleForTests_returnFromEnum();
   public static native void this_is_a_package_prefix_org_jni_1zero_SampleForTests_setNonPODDatatype(Object obj, Object rect);
 }
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTestsJni.java.golden b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTestsJni.java.golden
index 69330e3..9e1418b 100644
--- a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTestsJni.java.golden
+++ b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTestsJni.java.golden
@@ -181,6 +181,11 @@
   }
 
   @Override
+  public int returnFromEnum() {
+    return (int) GEN_JNI.this_is_a_package_prefix_org_jni_1zero_SampleForTests_returnFromEnum();
+  }
+
+  @Override
   public void setNonPODDatatype(SampleForTests obj, Rect rect) {
     assert obj != null : "Parameter \"obj\" was null. Add @Nullable to it?";
     assert rect != null : "Parameter \"rect\" was null. Add @Nullable to it?";
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden
index 55f8927..c9ab5ab 100644
--- a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden
+++ b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden
@@ -211,7 +211,7 @@
       env,
       jni_zero::JavaParamRef<jobject>(env, items));
   auto _ret = JNI_SampleForTests_ListTest2(env, items_converted);
-  jobject converted_ret = jni_zero::ToJniList(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniList(env, _ret).Release();
   return converted_ret;
 }
 
@@ -228,7 +228,7 @@
       env,
       jni_zero::JavaParamRef<jobject>(env, arg0));
   auto _ret = JNI_SampleForTests_MapTest2(env, arg0_converted);
-  jobject converted_ret = jni_zero::ToJniType(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniType(env, _ret).Release();
   return converted_ret;
 }
 
@@ -310,7 +310,7 @@
       l_converted,
       f_converted,
       d_converted);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret).Release();
   return converted_ret;
 }
 
@@ -326,6 +326,17 @@
 }
 
 // Forward declaration. To be implemented by the including .cc file.
+static MyEnum JNI_SampleForTests_ReturnFromEnum(JNIEnv* env);
+
+JNI_ZERO_BOUNDARY_EXPORT jint Java_this_is_a_package_prefix_org_jni_1zero_GEN_1JNI_this_1is_1a_1package_1prefix_1org_1jni_11zero_1SampleForTests_1returnFromEnum(
+    JNIEnv* env,
+    jclass jcaller) {
+  auto _ret = JNI_SampleForTests_ReturnFromEnum(env);
+  auto converted_ret = jni_zero::internal::PrimitiveConvert<MyEnum, jint>::ToJniType(env, _ret);
+  return static_cast<jint>(converted_ret);
+}
+
+// Forward declaration. To be implemented by the including .cc file.
 static void JNI_SampleForTests_SetNonPODDatatype(
     JNIEnv* env,
     const jni_zero::JavaParamRef<jobject>& obj,
diff --git a/third_party/jni_zero/test/golden/testPerFileNatives-SampleForAnnotationProcessor_jni.h.golden b/third_party/jni_zero/test/golden/testPerFileNatives-SampleForAnnotationProcessor_jni.h.golden
index 86ce506..dd3fb52 100644
--- a/third_party/jni_zero/test/golden/testPerFileNatives-SampleForAnnotationProcessor_jni.h.golden
+++ b/third_party/jni_zero/test/golden/testPerFileNatives-SampleForAnnotationProcessor_jni.h.golden
@@ -90,7 +90,7 @@
     jclass jcaller,
     jobject __arrayClazz) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedAppObjects(env);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret, static_cast<jclass>(__arrayClazz)).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret, static_cast<jclass>(__arrayClazz)).Release();
   return converted_ret;
 }
 
@@ -101,7 +101,7 @@
     JNIEnv* env,
     jclass jcaller) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedInts(env);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret).Release();
   return converted_ret;
 }
 
@@ -112,7 +112,7 @@
     JNIEnv* env,
     jclass jcaller) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedString(env);
-  jobject converted_ret = jni_zero::ToJniType(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniType(env, _ret).Release();
   return converted_ret;
 }
 
@@ -124,7 +124,7 @@
     JNIEnv* env,
     jclass jcaller) {
   auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedStrings(env);
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret, jni_zero::g_string_class).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret, jni_zero::g_string_class).Release();
   return converted_ret;
 }
 
@@ -323,7 +323,7 @@
       jni_zero::JavaParamRef<jfloatArray>(env, static_cast<jfloatArray>(floats)),
       zbool,
       jni_zero::JavaParamRef<jbooleanArray>(env, static_cast<jbooleanArray>(bools)));
-  jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
+  auto converted_ret = jni_zero::ToJniArray(env, _ret).Release();
   return converted_ret;
 }
 
diff --git a/third_party/jni_zero/test/java/src/org/jni_zero/SampleForTests.java b/third_party/jni_zero/test/java/src/org/jni_zero/SampleForTests.java
index 11468e1..7f641e0 100644
--- a/third_party/jni_zero/test/java/src/org/jni_zero/SampleForTests.java
+++ b/third_party/jni_zero/test/java/src/org/jni_zero/SampleForTests.java
@@ -376,6 +376,9 @@
                 @JniType("std::vector<float>") float[] f,
                 @JniType("std::vector<double>") double[] d);
 
+        @JniType("MyEnum")
+        int returnFromEnum();
+
         // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from
         // the annotation rather than parameter name, which can thus be chosen freely.
         @NativeClassQualifiedName("CPPClass::InnerClass")
diff --git a/third_party/jni_zero/test/sample_for_tests.cc b/third_party/jni_zero/test/sample_for_tests.cc
index 3641a23..5868b44e 100644
--- a/third_party/jni_zero/test/sample_for_tests.cc
+++ b/third_party/jni_zero/test/sample_for_tests.cc
@@ -166,6 +166,10 @@
   return Java_SampleForTests_primitiveArrays(env, b, c, s, i, l, f, d);
 }
 
+static MyEnum JNI_SampleForTests_ReturnFromEnum(JNIEnv* env) {
+  return MyEnum::kFirstOption;
+}
+
 }  // namespace jni_zero::tests
 
 // Proxy natives.
diff --git a/third_party/libxml/README.chromium b/third_party/libxml/README.chromium
index 92f91c1..cf382a8 100644
--- a/third_party/libxml/README.chromium
+++ b/third_party/libxml/README.chromium
@@ -20,6 +20,7 @@
   aren't implemented or don't work on several platforms.
 - counted_by.patch: Work around __counted_by__ supported in a cronet toolchain
   with a pre-release clang.
+- xml-attr-extra.patch: add an `extra` member to struct _xmlAttr.
 - Add helper classes in the chromium/ subdirectory.
 - Delete various unused files, see chromium/roll.py
 - Disable various unused libxml features:
diff --git a/third_party/libxml/chromium/xml-attr-extra.patch b/third_party/libxml/chromium/xml-attr-extra.patch
new file mode 100644
index 0000000..b81c432
--- /dev/null
+++ b/third_party/libxml/chromium/xml-attr-extra.patch
@@ -0,0 +1,20 @@
+diff --git a/third_party/libxml/src/include/libxml/tree.h b/third_party/libxml/src/include/libxml/tree.h
+index e5a8fb709471f..7819d5819b427 100644
+--- a/third_party/libxml/src/include/libxml/tree.h
++++ b/third_party/libxml/src/include/libxml/tree.h
+@@ -454,6 +454,7 @@ struct _xmlAttr {
+     xmlAttributeType atype;     /* the attribute type if validating */
+     void            *psvi;	/* for type/PSVI information */
+     struct _xmlID   *id;        /* the ID struct */
++    unsigned int     extra;     /* extra data for XPath/XSLT */
+ };
+ 
+ /**
+@@ -592,6 +593,7 @@ struct _xmlDoc {
+ 				   document */
+     int             properties;	/* set of xmlDocProperties for this document
+ 				   set at the end of parsing */
++    unsigned int    extra;      /* extra data for XPath/XSLT */
+ };
+ 
+ 
diff --git a/third_party/libxml/src/include/libxml/tree.h b/third_party/libxml/src/include/libxml/tree.h
index e5a8fb7..7819d58 100644
--- a/third_party/libxml/src/include/libxml/tree.h
+++ b/third_party/libxml/src/include/libxml/tree.h
@@ -454,6 +454,7 @@
     xmlAttributeType atype;     /* the attribute type if validating */
     void            *psvi;	/* for type/PSVI information */
     struct _xmlID   *id;        /* the ID struct */
+    unsigned int     extra;     /* extra data for XPath/XSLT */
 };
 
 /**
@@ -592,6 +593,7 @@
 				   document */
     int             properties;	/* set of xmlDocProperties for this document
 				   set at the end of parsing */
+    unsigned int    extra;      /* extra data for XPath/XSLT */
 };
 
 
diff --git a/third_party/pdfium b/third_party/pdfium
index 1eb36c3..e265bde6 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit 1eb36c32e79a499ab0612b6be6006c563037bb3d
+Subproject commit e265bde6fee233a96f87ca46464dd662531e0f90
diff --git a/third_party/perfetto b/third_party/perfetto
index fc9aac5..f4cde1b 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit fc9aac573945f2da6d05bf1904d500e6d5cdf18d
+Subproject commit f4cde1b052fd591a5c50fe11dbcda61c51c4cccf
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn
index 2185b71..3e77121 100644
--- a/third_party/protobuf/BUILD.gn
+++ b/third_party/protobuf/BUILD.gn
@@ -7,9 +7,6 @@
 import("proto_sources.gni")
 if (enable_js_protobuf) {
   import("//third_party/closure_compiler/compile_js.gni")
-  import("//ui/webui/resources/tools/bundle_js.gni")
-  import("//ui/webui/resources/tools/generate_grd.gni")
-  import("//ui/webui/resources/tools/minify_js.gni")
 }
 
 config("protobuf_config") {
@@ -422,34 +419,4 @@
       "//third_party/protobuf-javascript/src/message.js",
     ]
   }
-
-  bundle_js("bufbuild_bundle") {
-    visibility = [ ":bufbuild_min_js" ]
-    host = "_ignored_"
-    input = rebase_path(
-            "//third_party/node/node_modules/@bufbuild/protobuf/dist/esm",
-            root_build_dir)
-    js_module_in_files = [ "wire/index.js" ]
-    out_folder = "$target_gen_dir/bufbuild/bundled"
-  }
-
-  minify_js("bufbuild_min_js") {
-    visibility = [ ":bufbuild_grdp" ]
-    deps = [ ":bufbuild_bundle" ]
-    in_folder = "$target_gen_dir/bufbuild/bundled"
-    in_files = [ "wire/index.rollup.js" ]
-    out_folder = "$target_gen_dir/bufbuild/minified"
-  }
-
-  generate_grd("bufbuild_grdp") {
-    deps = [ ":bufbuild_min_js" ]
-    grd_prefix = "bufbuild"
-    out_grd = "$root_gen_dir/bufbuild.grdp"
-    input_files = [ "wire/index.rollup.js" ]
-
-    input_files_base_dir =
-        rebase_path("$target_gen_dir/bufbuild/minified", root_build_dir)
-    resource_path_rewrites =
-        [ "wire/index.rollup.js|@bufbuild/protobuf/wire/index.js" ]
-  }
 }
diff --git a/third_party/protobuf/DIR_METADATA b/third_party/protobuf/DIR_METADATA
index 744e51f..208cc2f 100644
--- a/third_party/protobuf/DIR_METADATA
+++ b/third_party/protobuf/DIR_METADATA
@@ -1,6 +1,13 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 monorail: {
-  component: "Internals>Core"
+  component: "Chromium>ThirdParty>Protobuf"
 }
 buganizer_public: {
-  component_id: 1456128
+  component_id: 1793013
 }
diff --git a/third_party/rust/adler2/OWNERS b/third_party/rust/adler2/OWNERS
new file mode 100644
index 0000000..07bd9a4
--- /dev/null
+++ b/third_party/rust/adler2/OWNERS
@@ -0,0 +1,2 @@
+# This crate has been brought in as a dependency of the `png` crate.
+file://third_party/rust/png/OWNERS
diff --git a/third_party/rust/android_system_properties/v0_1/BUILD.gn b/third_party/rust/android_system_properties/v0_1/BUILD.gn
index d12ee4e..3e0f80b 100644
--- a/third_party/rust/android_system_properties/v0_1/BUILD.gn
+++ b/third_party/rust/android_system_properties/v0_1/BUILD.gn
@@ -29,7 +29,10 @@
   executable_configs += [ "//build/config/compiler:no_chromium_code" ]
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [ "//third_party/rust/libc/v0_2:lib" ]
+  deps = []
+  if (is_android) {
+    deps += [ "//third_party/rust/libc/v0_2:lib" ]
+  }
   rustflags = [
     "--cap-lints=allow",  # Suppress all warnings in crates.io crates
   ]
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock
index 99a1e68..4f60c5f 100644
--- a/third_party/rust/chromium_crates_io/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -103,7 +103,6 @@
  "cxxbridge-cmd",
  "fend-core",
  "font-types",
- "group",
  "hex",
  "icu_capi",
  "icu_casemap",
@@ -121,7 +120,6 @@
  "prost",
  "qr_code",
  "quote",
- "rand_core",
  "read-fonts",
  "rustc-demangle-capi",
  "serde_json_lenient",
@@ -304,15 +302,6 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "ff"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rand_core",
- "subtle",
-]
-
-[[package]]
 name = "fixed_decimal"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -345,16 +334,6 @@
 ]
 
 [[package]]
-name = "group"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "ff",
- "rand_core",
- "subtle",
-]
-
-[[package]]
 name = "hashbrown"
 version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1035,11 +1014,6 @@
 ]
 
 [[package]]
-name = "rand_core"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
 name = "read-fonts"
 version = "0.27.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/third_party/rust/chromium_crates_io/Cargo.toml b/third_party/rust/chromium_crates_io/Cargo.toml
index 4ae9b5e..25d6c49e 100644
--- a/third_party/rust/chromium_crates_io/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/Cargo.toml
@@ -42,13 +42,6 @@
 version = "1.4.2"
 features = ["nightly"]  # For optimized aarch64 implementation.
 
-# Include temporarily here as a direct dependency during the import process
-# for authenticated-pseudonyms.
-# TODO(crbug.com/404604413): Stop exposing this here when it becomes a
-# transitive dependency.
-[dependencies.group]
-version = "0.13"
-
 [dependencies.icu_capi]
 version = "2.0.0-beta2"
 default-features = false
@@ -87,14 +80,6 @@
 # when debug asserts are off, which is when DCHECK_IS_ON() is false.
 features = [ "std", "release_max_level_info" ]
 
-# Temporarily inform our cargo tooling that we need a new version of rand_core. Remove
-# default features to align with authenticated-pseudonyms use case (crbug.com/404604413)
-# TODO(crbug.com/404598090) Remove this when all upstreams have updated, and rand_core
-# moves to be a transitive dependency only.
-[dependencies.rand_core]
-version = "0.9.0"
-default-features = false
-
 # Temporarily inform our cargo tooling that we care about
 # the new version of serde_json_lenient. We are in the midst
 # of CLs that move from the older to the newer.
diff --git a/third_party/rust/chromium_crates_io/patches/ff/0001-update-rand-core.patch b/third_party/rust/chromium_crates_io/patches/ff/0001-update-rand-core.patch
deleted file mode 100644
index 0a6c74d..0000000
--- a/third_party/rust/chromium_crates_io/patches/ff/0001-update-rand-core.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From a27c9d3621facb03a450422910fe2d5835d7d0d6 Mon Sep 17 00:00:00 2001
-From: Theodore Olsauskas-Warren <sauski@google.com>
-Date: Tue, 1 Apr 2025 08:39:49 -0700
-Subject: [PATCH] patched
-
-TODO(crbug.com/408276016): Upstream this version bump into the ff
-repository.
-
----
- .../rust/chromium_crates_io/vendor/ff-0.13.1/Cargo.toml       | 4 ++--
- .../chromium_crates_io/vendor/ff-0.13.1/rust-toolchain.toml   | 2 +-
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/Cargo.toml
-index 3b025f826d27d..9853b82cbb651 100644
---- a/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/Cargo.toml
-+++ b/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/Cargo.toml
-@@ -11,7 +11,7 @@
- 
- [package]
- edition = "2021"
--rust-version = "1.56"
-+rust-version = "1.63"
- name = "ff"
- version = "0.13.1"
- authors = ["Sean Bowe <ewillbefull@gmail.com>", "Jack Grigg <thestr4d@gmail.com>"]
-@@ -44,7 +44,7 @@ version = "0.13.1"
- optional = true
- 
- [dependencies.rand_core]
--version = "0.6"
-+version = "0.9"
- default-features = false
- 
- [dependencies.subtle]
-diff --git a/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/rust-toolchain.toml b/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/rust-toolchain.toml
-index de43b23004fa5..3eebdfe1d3e95 100644
---- a/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/rust-toolchain.toml
-+++ b/third_party/rust/chromium_crates_io/vendor/ff-0.13.1/rust-toolchain.toml
-@@ -1,3 +1,3 @@
- [toolchain]
--channel = "1.56.0"
-+channel = "1.63.0"
- components = [ "clippy", "rustfmt" ]
--- 
-2.49.0.472.ge94155a9ec-goog
-
diff --git a/third_party/rust/chromium_crates_io/patches/group/0001-update-rand-core.patch b/third_party/rust/chromium_crates_io/patches/group/0001-update-rand-core.patch
deleted file mode 100644
index e21bb79..0000000
--- a/third_party/rust/chromium_crates_io/patches/group/0001-update-rand-core.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 651b16e6b0ab5812450b60f953616ed82cc4187b Mon Sep 17 00:00:00 2001
-From: Theodore Olsauskas-Warren <sauski@google.com>
-Date: Fri, 4 Apr 2025 08:09:47 -0700
-Subject: [PATCH] update-rand-core
-
-TODO(crbug.com/408276016): Upstream this version bump into the group
-repository.
-
----
- .../rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml       | 2 +-
- .../rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain   | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml
-index 059f0f76146a3..270336ad54355 100644
---- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml
-+++ b/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml
-@@ -35,7 +35,7 @@ optional = true
- default-features = false
- 
- [dependencies.rand_core]
--version = "0.6"
-+version = "0.9"
- default-features = false
- 
- [dependencies.rand_xorshift]
-diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain b/third_party/rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain
-index 3ebf789f5a8df..af92bdd9f58d1 100644
---- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain
-+++ b/third_party/rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain
-@@ -1 +1 @@
--1.56.0
-+1.63.0
--- 
-2.49.0.504.g3bcea36a83-goog
-
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 dd24060..bb40e66 100644
--- a/third_party/rust/chromium_crates_io/supply-chain/config.toml
+++ b/third_party/rust/chromium_crates_io/supply-chain/config.toml
@@ -143,9 +143,6 @@
 [policy."fend-core:1.5.6"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."ff:0.13.1"]
-criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
-
 [policy."fixed_decimal:0.7.0"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
@@ -158,9 +155,6 @@
 [policy."font-types:0.8.4"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."group:0.13.0"]
-criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
-
 [policy."hashbrown:0.15.2"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
@@ -353,9 +347,6 @@
 [policy."quote:1.0.40"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."rand_core:0.9.3"]
-criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
-
 [policy."read-fonts:0.27.5"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.cargo-checksum.json
deleted file mode 100644
index 697c9ce..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.cargo-checksum.json
+++ /dev/null
@@ -1 +0,0 @@
-{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.cargo_vcs_info.json
deleted file mode 100644
index 195b404..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.cargo_vcs_info.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "git": {
-    "sha1": "851b0f61bbcf9a5b61027307144d8bd1f9b756ba"
-  }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.github/workflows/ci.yml b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.github/workflows/ci.yml
deleted file mode 100644
index be7b028e..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.github/workflows/ci.yml
+++ /dev/null
@@ -1,104 +0,0 @@
-name: CI checks
-
-on:
-  pull_request:
-  push:
-    branches: main
-
-jobs:
-  test-msrv:
-    name: Test MSRV on ${{ matrix.os }}
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os: [ubuntu-latest, windows-latest, macOS-latest]
-    steps:
-      - uses: actions/checkout@v4
-      - name: Run tests
-        run: cargo test --verbose --all-features
-      - name: Run tests (without bitvec)
-        run: cargo test --verbose --no-default-features --features derive
-      - name: Verify working directory is clean
-        run: git diff --exit-code
-
-  test-latest:
-    name: Test latest on ${{ matrix.os }}
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os: [ubuntu-latest, windows-latest, macOS-latest]
-    steps:
-      - uses: actions/checkout@v4
-      - uses: dtolnay/rust-toolchain@stable
-        id: toolchain
-      - run: rustup override set ${{steps.toolchain.outputs.name}}
-      - name: Remove lockfile to build with latest dependencies
-        run: rm Cargo.lock
-      - name: Run tests
-        run: cargo test --verbose --all-features
-      - name: Run tests (without bitvec)
-        run: cargo test --verbose --no-default-features --features derive
-      - name: Verify working directory is clean (excluding lockfile)
-        run: git diff --exit-code ':!Cargo.lock'
-
-  build-nodefault:
-    name: Build target ${{ matrix.target }}
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        target:
-          - wasm32-wasi
-          - thumbv6m-none-eabi
-          - thumbv7em-none-eabihf
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          path: crate_root
-      # We use a synthetic crate to ensure no dev-dependencies are enabled, which can
-      # be incompatible with some of these targets.
-      - name: Create synthetic crate for testing
-        run: cargo init --edition 2021 --lib ci-build
-      - name: Copy Rust version into synthetic crate
-        run: cp crate_root/rust-toolchain.toml ci-build/
-      - name: Copy patch directives into synthetic crate
-        run: |
-          echo "[patch.crates-io]" >> ./ci-build/Cargo.toml
-          cat ./crate_root/Cargo.toml | sed "0,/.\+\(patch.crates.\+\)/d" >> ./ci-build/Cargo.toml
-      - name: Add no_std pragma to lib.rs
-        run: |
-          echo "#![no_std]" > ./ci-build/src/lib.rs
-      - name: Add ff as a dependency of the synthetic crate
-        working-directory: ./ci-build
-        # run: cargo add --no-default-features --path ../crate_root
-        run: sed -i 's;\[dependencies\];\[dependencies\]\nff = { path = "../crate_root", default-features = false };g' ./Cargo.toml
-      - name: Add target
-        working-directory: ./ci-build
-        run: rustup target add ${{ matrix.target }}
-      - name: Build for target
-        working-directory: ./ci-build
-        run: cargo build --verbose --target ${{ matrix.target }}
-      - name: Enable the bits feature of ff
-        working-directory: ./ci-build
-        # run: cargo add --no-default-features --features bits --path ../crate_root
-        run: sed -i 's;ff = { path = "../crate_root", default-features = false };ff = { path = "../crate_root", default-features = false, features = ["bits"] };g' ./Cargo.toml
-      - name: Build for target with the bits feature
-        working-directory: ./ci-build
-        run: cargo build --verbose --target ${{ matrix.target }}
-
-  doc-links:
-    name: Intra-doc links
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v4
-      - run: cargo fetch
-      # Requires #![deny(rustdoc::broken_intra_doc_links)] in crates.
-      - run: sudo apt-get -y install libfontconfig1-dev
-      - name: Check intra-doc links
-        run: cargo doc --all-features --document-private-items
-
-  fmt:
-    name: Rustfmt
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v4
-      - run: cargo fmt -- --check
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.gitignore b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.gitignore
deleted file mode 100644
index 324c57f7..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-target/
-**/*.rs.bk
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/CHANGELOG.md
deleted file mode 100644
index 955e6a83..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/CHANGELOG.md
+++ /dev/null
@@ -1,152 +0,0 @@
-# Changelog
-All notable changes to this library will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this library adheres to Rust's notion of
-[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [Unreleased]
-
-## [0.13.1] - 2025-03-09
-### Changed
-- `ff_derive` now works with all odd primes, not just primes that are either
-  `3 (mod 4)` or `1 (mod 16)`.
-
-### Fixed
-- A type inference problem when `ff_derive` and `hybrid-array` are in the same
-  dependency tree has been fixed.
-
-## [0.13.0] - 2022-12-06
-### Added
-- `ff::Field::{ZERO, ONE}`
-- `ff::Field::pow`
-- `ff::Field::{sqrt_ratio, sqrt_alt}`
-- `core::iter::{Sum, Product}` bounds on `ff::Field`
-- `ff::PrimeField::from_u128`
-- `ff::PrimeField::{MODULUS, TWO_INV}`
-- Constants related to multiplicative generators:
-  - `ff::PrimeField::MULTIPLICATIVE_GENERATOR`
-  - `ff::PrimeField::{ROOT_OF_UNITY, ROOT_OF_UNITY_INV}`
-  - `ff::PrimeField::DELTA`
-- `ff::WithSmallOrderMulGroup`
-- `ff::FromUniformBytes`
-- `ff::helpers`:
-  - `sqrt_tonelli_shanks`
-  - `sqrt_ratio_generic`
-
-### Changed
-- `ff::Field::sqrt` is now a provided method that uses the `Field::sqrt_ratio`
-  method. Implementors of the `Field` trait can choose to implement
-  `Field::sqrt_ratio` and use the provided `ff::Field::sqrt` method, especially
-  if it is more efficient in practice, or they can keep their own implementation
-  of `Field::sqrt` and implement `Field::sqrt_ratio` in terms of that
-  implementation using the `ff::helpers::sqrt_ratio_generic` helper function.
-- `ff::PrimeField` is now documented as representing a non-binary field (i.e.
-  its prime is not 2). This was always the intention, but is now a concrete
-  requirement in order for `PrimeField::TWO_INV` to exist.
-
-### Removed
-- `ff::Field::{zero, one}` (use `ff::Field::{ZERO, ONE}` instead).
-- `ff::PrimeField::{multiplicative_generator, root_of_unity}` (use
-  `ff::PrimeField::{MULTIPLICATIVE_GENERATOR, ROOT_OF_UNITY}` instead).
-
-## [0.12.1] - 2022-10-28
-### Fixed
-- `ff_derive` previously generated a `Field::random` implementation that would
-  overflow for fields that needed a full 64-bit spare limb.
-
-## [0.12.0] - 2022-05-04
-### Changed
-
-- MSRV is now 1.56.0.
-- Bumped `bitvec` to 1.0.
-
-## [0.11.1] - 2022-05-04
-### Fixed
-- `ff_derive` procedural macro can now be invoked within regular macros.
-- Previously, `ff_derive`'s procedural macro would generate implementations of
-  `PrimeFieldBits` even when the `bits` crate feature was disabled. `ff_derive`
-  can now be used without a dependency on `bitvec` by disabling feature
-  features. The new crate feature `derive_bits` can be used to force the
-  generation of `PrimeFieldBits` implementations. This new crate feature will be
-  removed once our MSRV is at least 1.60 and we have access to [weak dependency
-  features](https://blog.rust-lang.org/2022/04/07/Rust-1.60.0.html#new-syntax-for-cargo-features).
-
-## [0.11.0] - 2021-09-02
-### Added
-- `subtle::ConstantTimeEq` bound on `ff::Field`
-- `Copy + Send + Sync + 'static` bounds on `ff::PrimeField::Repr`
-- `ff::derive` module behind the `derive` feature flag, containing dependencies for the
-  `PrimeField` derive macro:
-  - Re-exports of required crates.
-  - `adc, mac, sbb` constant-time const helper functions.
-- `ff::Field::is_zero_vartime`
-- `ff::PrimeField::from_repr_vartime`
-
-### Changed
-- `ff::Field::is_zero` now returns `subtle::Choice`.
-- `ff::PrimeField::{is_odd, is_even}` now return `subtle::Choice`.
-- `ff::PrimeField::from_repr` now return `subtle::CtOption<Self>`.
-- `ff::PrimeField::from_str` has been renamed to `PrimeField::from_str_vartime`.
-
-### Removed
-- `ff::{adc, mac_with_carry, sbb}` (replaced by `ff::derive::{adc, mac, sbb}`).
-
-## [0.10.1] - 2021-08-11
-### Added
-- `ff::BatchInvert` extension trait, implemented for iterators over mutable field elements
-  which allows those field elements to be inverted in a batch. This trait is behind the
-  new `alloc` feature flag.
-- `ff::BatchInverter` struct, which provides methods for non-allocating batch inversion of
-  field elements contained within slices.
-
-## [0.10.0] - 2021-06-01
-### Added
-- `ff::PrimeFieldBits: PrimeField` trait, behind a `bits` feature flag.
-
-### Changed
-- MSRV is now 1.51.0.
-- Bumped `bitvec` to 0.22 to enable fixing a performance regression in `ff 0.9`.
-  The `bitvec::view::BitView` re-export has been replaced by
-  `bitvec::view::BitViewSized`.
-- The `bitvec` dependency and its re-exports have been gated behind the `bits`
-  feature flag.
-
-### Removed
-- `ff::PrimeField::{ReprBits, char_le_bits, to_le_bits}` (replaced by
-  `ff::PrimeFieldBits` trait).
-
-### Fixed
-- `#[derive(PrimeField)]` now works on small moduli (that fit in a single `u64`
-  limb).
-
-## [0.9.0] - 2021-01-05
-### Added
-- Re-export of `bitvec::view::BitView`.
-- `ff::FieldBits<V>` type alias for the return type of
-  `ff::PrimeField::{char_le_bits, to_le_bits}`.
-
-### Changed
-- Bumped `bitvec` to 0.20, `rand_core` to 0.6.
-
-### Removed
-- `From<Self>` and `From<&Self>` bounds on `ff::PrimeField::Repr`.
-
-## [0.8.0] - 2020-09-08
-### Added
-- `ff::PrimeField::{ReprBits, char_le_bits, to_le_bits}`, and a public
-  dependency on `bitvec 0.18`.
-- `ff::Field::cube` method with provided implementation.
-- `Send + Sync` bounds on `ff::PrimeField::ReprBits`
-
-### Changed
-- MSRV is now 1.44.0.
-- `ff::Field::random<R: RngCore + ?Sized>(rng: &mut R) -> Self` has been changed
-  to `Field::random(rng: impl RngCore) -> Self`, to align with
-  `group::Group::random`.
-
-### Removed
-- `fmt::Display` bound on `ff::Field`.
-- `ff::PrimeField::char` (replaced by `ff::PrimeField::char_le_bits`).
-- `ff::{BitIterator, Endianness, PrimeField::ReprEndianness` (replaced by
-  `ff::PrimeField::to_le_bits`).
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/Cargo.toml
deleted file mode 100644
index 9853b82..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/Cargo.toml
+++ /dev/null
@@ -1,68 +0,0 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies.
-#
-# If you are reading this file be aware that the original Cargo.toml
-# will likely look very different (and much more reasonable).
-# See Cargo.toml.orig for the original contents.
-
-[package]
-edition = "2021"
-rust-version = "1.63"
-name = "ff"
-version = "0.13.1"
-authors = ["Sean Bowe <ewillbefull@gmail.com>", "Jack Grigg <thestr4d@gmail.com>"]
-description = "Library for building and interfacing with finite fields"
-homepage = "https://github.com/zkcrypto/ff"
-documentation = "https://docs.rs/ff/"
-readme = "README.md"
-license = "MIT/Apache-2.0"
-repository = "https://github.com/zkcrypto/ff"
-resolver = "2"
-[package.metadata.docs.rs]
-all-features = true
-rustdoc-args = ["--cfg", "docsrs"]
-
-[[test]]
-name = "derive"
-required-features = ["derive"]
-[dependencies.bitvec]
-version = "1"
-optional = true
-default-features = false
-
-[dependencies.byteorder]
-version = "1"
-optional = true
-default-features = false
-
-[dependencies.ff_derive]
-version = "0.13.1"
-optional = true
-
-[dependencies.rand_core]
-version = "0.9"
-default-features = false
-
-[dependencies.subtle]
-version = "2.2.1"
-features = ["i128"]
-default-features = false
-[dev-dependencies.blake2b_simd]
-version = "1"
-
-[dev-dependencies.rand]
-version = "0.8"
-
-[features]
-alloc = []
-bits = ["bitvec"]
-default = ["bits", "std"]
-derive = ["byteorder", "ff_derive"]
-derive_bits = ["bits", "ff_derive/bits"]
-std = ["alloc"]
-[badges.maintenance]
-status = "actively-developed"
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/Cargo.toml.orig
deleted file mode 100644
index a6af21f4..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/Cargo.toml.orig
+++ /dev/null
@@ -1,47 +0,0 @@
-[package]
-name = "ff"
-version = "0.13.1"
-authors = [
-    "Sean Bowe <ewillbefull@gmail.com>",
-    "Jack Grigg <thestr4d@gmail.com>",
-]
-edition = "2021"
-rust-version = "1.56"
-description = "Library for building and interfacing with finite fields"
-readme = "README.md"
-documentation = "https://docs.rs/ff/"
-homepage = "https://github.com/zkcrypto/ff"
-license = "MIT/Apache-2.0"
-repository = "https://github.com/zkcrypto/ff"
-
-[dependencies]
-bitvec = { version = "1", default-features = false, optional = true }
-byteorder = { version = "1", default-features = false, optional = true }
-ff_derive = { version = "0.13.1", path = "ff_derive", optional = true }
-rand_core = { version = "0.6", default-features = false }
-subtle = { version = "2.2.1", default-features = false, features = ["i128"] }
-
-[dev-dependencies]
-blake2b_simd = "1"
-rand = "0.8"
-
-[features]
-default = ["bits", "std"]
-alloc = []
-bits = ["bitvec"]
-derive = ["byteorder", "ff_derive"]
-std = ["alloc"]
-# with MSRV 1.60 this could be merged into bits with ff_derive?/bits
-# see PR#72 for more information.
-derive_bits = ["bits", "ff_derive/bits"]
-
-[[test]]
-name = "derive"
-required-features = ["derive"]
-
-[badges]
-maintenance = { status = "actively-developed" }
-
-[package.metadata.docs.rs]
-all-features = true
-rustdoc-args = ["--cfg", "docsrs"]
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/LICENSE-APACHE
deleted file mode 100644
index 1e5006dc..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/LICENSE-APACHE
+++ /dev/null
@@ -1,202 +0,0 @@
-                              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/ff-v0_13/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/LICENSE-MIT
deleted file mode 100644
index ed3a13fd..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/LICENSE-MIT
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2017 Sean Bowe
-
-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 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/ff-v0_13/README.md b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/README.md
deleted file mode 100644
index caff4493..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/README.md
+++ /dev/null
@@ -1,82 +0,0 @@
-# ff
-
-`ff` is a finite field library written in pure Rust, with no `unsafe{}` code.
-
-## RFC process
-
-This crate follows the [zkcrypto RFC process](https://zkcrypto.github.io/rfcs/).
-If you want to propose "substantial" changes to this crate (in particular to the
-`ff` traits), please [create an RFC](https://github.com/zkcrypto/rfcs) for wider
-discussion.
-
-## Disclaimers
-
-* This library does not provide constant-time guarantees. The traits enable downstream
-  users to expose constant-time logic, but `#[derive(PrimeField)]` in particular does not
-  generate constant-time code (even for trait methods that return constant-time-compatible
-  values).
-
-## Usage
-
-Add the `ff` crate to your `Cargo.toml`:
-
-```toml
-[dependencies]
-ff = "0.13"
-```
-
-The `ff` crate contains the `Field` and `PrimeField` traits.
-See the **[documentation](https://docs.rs/ff/)** for more.
-
-### `#![derive(PrimeField)]`
-
-If you need an implementation of a prime field, this library also provides a procedural
-macro that will expand into an efficient implementation of a prime field when supplied
-with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is
-also quadratic nonresidue.
-
-First, enable the `derive` crate feature:
-
-```toml
-[dependencies]
-ff = { version = "0.13", features = ["derive"] }
-```
-
-And then use the macro like so:
-
-```rust
-#[macro_use]
-extern crate ff;
-
-#[derive(PrimeField)]
-#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
-#[PrimeFieldGenerator = "7"]
-#[PrimeFieldReprEndianness = "little"]
-struct Fp([u64; 4]);
-```
-
-And that's it! `Fp` now implements `Field` and `PrimeField`.
-
-## Minimum Supported Rust Version
-
-Requires Rust **1.56** or higher.
-
-Minimum supported Rust version can be changed in the future, but it will be done with a
-minor version bump.
-
-## License
-
-Licensed under either of
-
- * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
-   http://www.apache.org/licenses/LICENSE-2.0)
- * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
-
-at your option.
-
-### Contribution
-
-Unless you explicitly state otherwise, any contribution intentionally
-submitted for inclusion in the work by you, as defined in the Apache-2.0
-license, shall be dual licensed as above, without any additional terms or
-conditions.
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/rust-toolchain.toml b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/rust-toolchain.toml
deleted file mode 100644
index 3eebdfe..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/rust-toolchain.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-[toolchain]
-channel = "1.63.0"
-components = [ "clippy", "rustfmt" ]
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/batch.rs b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/batch.rs
deleted file mode 100644
index 96ddc5a9..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/batch.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-//! Batched field inversion APIs, using [Montgomery's trick].
-//!
-//! [Montgomery's trick]: https://zcash.github.io/halo2/background/fields.html#montgomerys-trick
-
-use subtle::ConstantTimeEq;
-
-use crate::Field;
-
-/// Extension trait for iterators over mutable field elements which allows those field
-/// elements to be inverted in a batch.
-///
-/// `I: IntoIterator<Item = &'a mut F: Field + ConstantTimeEq>` implements this trait when
-/// the `alloc` feature flag is enabled.
-///
-/// For non-allocating contexts, see the [`BatchInverter`] struct.
-#[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
-pub trait BatchInvert<F: Field> {
-    /// Consumes this iterator and inverts each field element (when nonzero). Zero-valued
-    /// elements are left as zero.
-    ///
-    /// Returns the inverse of the product of all nonzero field elements.
-    fn batch_invert(self) -> F;
-}
-
-#[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
-impl<'a, F, I> BatchInvert<F> for I
-where
-    F: Field + ConstantTimeEq,
-    I: IntoIterator<Item = &'a mut F>,
-{
-    fn batch_invert(self) -> F {
-        let mut acc = F::ONE;
-        let iter = self.into_iter();
-        let mut tmp = alloc::vec::Vec::with_capacity(iter.size_hint().0);
-        for p in iter {
-            let q = *p;
-            tmp.push((acc, p));
-            acc = F::conditional_select(&(acc * q), &acc, q.is_zero());
-        }
-        acc = acc.invert().unwrap();
-        let allinv = acc;
-
-        for (tmp, p) in tmp.into_iter().rev() {
-            let skip = p.is_zero();
-
-            let tmp = tmp * acc;
-            acc = F::conditional_select(&(acc * *p), &acc, skip);
-            *p = F::conditional_select(&tmp, p, skip);
-        }
-
-        allinv
-    }
-}
-
-/// A non-allocating batch inverter.
-pub struct BatchInverter {}
-
-impl BatchInverter {
-    /// Inverts each field element in `elements` (when nonzero). Zero-valued elements are
-    /// left as zero.
-    ///
-    /// - `scratch_space` is a slice of field elements that can be freely overwritten.
-    ///
-    /// Returns the inverse of the product of all nonzero field elements.
-    ///
-    /// # Panics
-    ///
-    /// This function will panic if `elements.len() != scratch_space.len()`.
-    pub fn invert_with_external_scratch<F>(elements: &mut [F], scratch_space: &mut [F]) -> F
-    where
-        F: Field + ConstantTimeEq,
-    {
-        assert_eq!(elements.len(), scratch_space.len());
-
-        let mut acc = F::ONE;
-        for (p, scratch) in elements.iter().zip(scratch_space.iter_mut()) {
-            *scratch = acc;
-            acc = F::conditional_select(&(acc * *p), &acc, p.is_zero());
-        }
-        acc = acc.invert().unwrap();
-        let allinv = acc;
-
-        for (p, scratch) in elements.iter_mut().zip(scratch_space.iter()).rev() {
-            let tmp = *scratch * acc;
-            let skip = p.is_zero();
-            acc = F::conditional_select(&(acc * *p), &acc, skip);
-            *p = F::conditional_select(&tmp, &p, skip);
-        }
-
-        allinv
-    }
-
-    /// Inverts each field element in `items` (when nonzero). Zero-valued elements are
-    /// left as zero.
-    ///
-    /// - `element` is a function that extracts the element to be inverted from `items`.
-    /// - `scratch_space` is a function that extracts the scratch space from `items`.
-    ///
-    /// Returns the inverse of the product of all nonzero field elements.
-    pub fn invert_with_internal_scratch<F, T, TE, TS>(
-        items: &mut [T],
-        element: TE,
-        scratch_space: TS,
-    ) -> F
-    where
-        F: Field + ConstantTimeEq,
-        TE: Fn(&mut T) -> &mut F,
-        TS: Fn(&mut T) -> &mut F,
-    {
-        let mut acc = F::ONE;
-        for item in items.iter_mut() {
-            *(scratch_space)(item) = acc;
-            let p = (element)(item);
-            acc = F::conditional_select(&(acc * *p), &acc, p.is_zero());
-        }
-        acc = acc.invert().unwrap();
-        let allinv = acc;
-
-        for item in items.iter_mut().rev() {
-            let tmp = *(scratch_space)(item) * acc;
-            let p = (element)(item);
-            let skip = p.is_zero();
-            acc = F::conditional_select(&(acc * *p), &acc, skip);
-            *p = F::conditional_select(&tmp, &p, skip);
-        }
-
-        allinv
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/helpers.rs b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/helpers.rs
deleted file mode 100644
index d1d6371..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/helpers.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-//! Helper methods for implementing the `ff` traits.
-
-use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
-
-use crate::PrimeField;
-
-/// Constant-time implementation of Tonelli–Shanks' square-root algorithm for
-/// `p mod 16 = 1`.
-///
-/// `tm1d2` should be set to `(t - 1) // 2`, where `t = (modulus - 1) >> F::S`.
-///
-/// ## Implementing [`Field::sqrt`]
-///
-/// This function can be used to implement [`Field::sqrt`] for fields that both implement
-/// [`PrimeField`] and satisfy `p mod 16 = 1`.
-///
-/// [`Field::sqrt`]: crate::Field::sqrt
-pub fn sqrt_tonelli_shanks<F: PrimeField, S: AsRef<[u64]>>(f: &F, tm1d2: S) -> CtOption<F> {
-    // This is a constant-time version of https://eprint.iacr.org/2012/685.pdf (page 12,
-    // algorithm 5). Steps 2-5 of the algorithm are omitted because they are only needed
-    // to detect non-square input; it is more efficient to do that by checking at the end
-    // whether the square of the result is the input.
-
-    // w = self^((t - 1) // 2)
-    let w = f.pow_vartime(tm1d2);
-
-    let mut v = F::S;
-    let mut x = w * f;
-    let mut b = x * w;
-
-    // Initialize z as the 2^S root of unity.
-    let mut z = F::ROOT_OF_UNITY;
-
-    for max_v in (1..=F::S).rev() {
-        let mut k = 1;
-        let mut b2k = b.square();
-        let mut j_less_than_v: Choice = 1.into();
-
-        // This loop has three phases based on the value of k for algorithm 5:
-        // - for j <= k, we square b2k in order to calculate b^{2^k}.
-        // - for k < j <= v, we square z in order to calculate ω.
-        // - for j > v, we do nothing.
-        for j in 2..max_v {
-            let b2k_is_one = b2k.ct_eq(&F::ONE);
-            let squared = F::conditional_select(&b2k, &z, b2k_is_one).square();
-            b2k = F::conditional_select(&squared, &b2k, b2k_is_one);
-            let new_z = F::conditional_select(&z, &squared, b2k_is_one);
-            j_less_than_v &= !j.ct_eq(&v);
-            k = u32::conditional_select(&j, &k, b2k_is_one);
-            z = F::conditional_select(&z, &new_z, j_less_than_v);
-        }
-
-        let result = x * z;
-        x = F::conditional_select(&result, &x, b.ct_eq(&F::ONE));
-        z = z.square();
-        b *= z;
-        v = k;
-    }
-
-    CtOption::new(
-        x,
-        (x * x).ct_eq(f), // Only return Some if it's the square root.
-    )
-}
-
-/// Computes:
-///
-/// - $(\textsf{true}, \sqrt{\textsf{num}/\textsf{div}})$, if $\textsf{num}$ and
-///   $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is a square in the
-///   field;
-/// - $(\textsf{true}, 0)$, if $\textsf{num}$ is zero;
-/// - $(\textsf{false}, 0)$, if $\textsf{num}$ is nonzero and $\textsf{div}$ is zero;
-/// - $(\textsf{false}, \sqrt{G_S \cdot \textsf{num}/\textsf{div}})$, if
-///   $\textsf{num}$ and $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is
-///   a nonsquare in the field;
-///
-/// where $G_S$ is a non-square.
-///
-/// For this method, $G_S$ is currently [`PrimeField::ROOT_OF_UNITY`], a generator of the
-/// order $2^S$ subgroup. Users of this crate should not rely on this generator being
-/// fixed; it may be changed in future crate versions to simplify the implementation of
-/// the SSWU hash-to-curve algorithm.
-///
-/// The choice of root from sqrt is unspecified.
-///
-/// ## Implementing [`Field::sqrt_ratio`]
-///
-/// This function can be used to implement [`Field::sqrt_ratio`] for fields that also
-/// implement [`PrimeField`]. If doing so, the default implementation of [`Field::sqrt`]
-/// *MUST* be overridden, or else both functions will recurse in a cycle until a stack
-/// overflow occurs.
-///
-/// [`Field::sqrt_ratio`]: crate::Field::sqrt_ratio
-/// [`Field::sqrt`]: crate::Field::sqrt
-pub fn sqrt_ratio_generic<F: PrimeField>(num: &F, div: &F) -> (Choice, F) {
-    // General implementation:
-    //
-    // a = num * inv0(div)
-    //   = {    0    if div is zero
-    //     { num/div otherwise
-    //
-    // b = G_S * a
-    //   = {      0      if div is zero
-    //     { G_S*num/div otherwise
-    //
-    // Since G_S is non-square, a and b are either both zero (and both square), or
-    // only one of them is square. We can therefore choose the square root to return
-    // based on whether a is square, but for the boolean output we need to handle the
-    // num != 0 && div == 0 case specifically.
-
-    let a = div.invert().unwrap_or(F::ZERO) * num;
-    let b = a * F::ROOT_OF_UNITY;
-    let sqrt_a = a.sqrt();
-    let sqrt_b = b.sqrt();
-
-    let num_is_zero = num.is_zero();
-    let div_is_zero = div.is_zero();
-    let is_square = sqrt_a.is_some();
-    let is_nonsquare = sqrt_b.is_some();
-    assert!(bool::from(
-        num_is_zero | div_is_zero | (is_square ^ is_nonsquare)
-    ));
-
-    (
-        is_square & (num_is_zero | !div_is_zero),
-        CtOption::conditional_select(&sqrt_b, &sqrt_a, is_square).unwrap(),
-    )
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/lib.rs
deleted file mode 100644
index f9eee3c..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/lib.rs
+++ /dev/null
@@ -1,498 +0,0 @@
-//! This crate provides traits for working with finite fields.
-
-#![no_std]
-#![cfg_attr(docsrs, feature(doc_cfg))]
-// Catch documentation errors caused by code changes.
-#![deny(rustdoc::broken_intra_doc_links)]
-#![forbid(unsafe_code)]
-
-#[cfg(feature = "alloc")]
-extern crate alloc;
-
-mod batch;
-pub use batch::*;
-
-pub mod helpers;
-
-#[cfg(feature = "derive")]
-#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
-pub use ff_derive::PrimeField;
-
-#[cfg(feature = "bits")]
-#[cfg_attr(docsrs, doc(cfg(feature = "bits")))]
-pub use bitvec::view::BitViewSized;
-
-#[cfg(feature = "bits")]
-use bitvec::{array::BitArray, order::Lsb0};
-
-use core::fmt;
-use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
-
-use rand_core::RngCore;
-use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
-
-/// Bit representation of a field element.
-#[cfg(feature = "bits")]
-#[cfg_attr(docsrs, doc(cfg(feature = "bits")))]
-pub type FieldBits<V> = BitArray<V, Lsb0>;
-
-/// This trait represents an element of a field.
-pub trait Field:
-    Sized
-    + Eq
-    + Copy
-    + Clone
-    + Default
-    + Send
-    + Sync
-    + fmt::Debug
-    + 'static
-    + ConditionallySelectable
-    + ConstantTimeEq
-    + Neg<Output = Self>
-    + Add<Output = Self>
-    + Sub<Output = Self>
-    + Mul<Output = Self>
-    + Sum
-    + Product
-    + for<'a> Add<&'a Self, Output = Self>
-    + for<'a> Sub<&'a Self, Output = Self>
-    + for<'a> Mul<&'a Self, Output = Self>
-    + for<'a> Sum<&'a Self>
-    + for<'a> Product<&'a Self>
-    + AddAssign
-    + SubAssign
-    + MulAssign
-    + for<'a> AddAssign<&'a Self>
-    + for<'a> SubAssign<&'a Self>
-    + for<'a> MulAssign<&'a Self>
-{
-    /// The zero element of the field, the additive identity.
-    const ZERO: Self;
-
-    /// The one element of the field, the multiplicative identity.
-    const ONE: Self;
-
-    /// Returns an element chosen uniformly at random using a user-provided RNG.
-    fn random(rng: impl RngCore) -> Self;
-
-    /// Returns true iff this element is zero.
-    fn is_zero(&self) -> Choice {
-        self.ct_eq(&Self::ZERO)
-    }
-
-    /// Returns true iff this element is zero.
-    ///
-    /// # Security
-    ///
-    /// This method provides **no** constant-time guarantees. Implementors of the
-    /// `Field` trait **may** optimise this method using non-constant-time logic.
-    fn is_zero_vartime(&self) -> bool {
-        self.is_zero().into()
-    }
-
-    /// Squares this element.
-    #[must_use]
-    fn square(&self) -> Self;
-
-    /// Cubes this element.
-    #[must_use]
-    fn cube(&self) -> Self {
-        self.square() * self
-    }
-
-    /// Doubles this element.
-    #[must_use]
-    fn double(&self) -> Self;
-
-    /// Computes the multiplicative inverse of this element,
-    /// failing if the element is zero.
-    fn invert(&self) -> CtOption<Self>;
-
-    /// Computes:
-    ///
-    /// - $(\textsf{true}, \sqrt{\textsf{num}/\textsf{div}})$, if $\textsf{num}$ and
-    ///   $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is a square in the
-    ///   field;
-    /// - $(\textsf{true}, 0)$, if $\textsf{num}$ is zero;
-    /// - $(\textsf{false}, 0)$, if $\textsf{num}$ is nonzero and $\textsf{div}$ is zero;
-    /// - $(\textsf{false}, \sqrt{G_S \cdot \textsf{num}/\textsf{div}})$, if
-    ///   $\textsf{num}$ and $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is
-    ///   a nonsquare in the field;
-    ///
-    /// where $G_S$ is a non-square.
-    ///
-    /// # Warnings
-    ///
-    /// - The choice of root from `sqrt` is unspecified.
-    /// - The value of $G_S$ is unspecified, and cannot be assumed to have any specific
-    ///   value in a generic context.
-    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self);
-
-    /// Equivalent to `Self::sqrt_ratio(self, one())`.
-    ///
-    /// The provided method is implemented in terms of [`Self::sqrt_ratio`].
-    fn sqrt_alt(&self) -> (Choice, Self) {
-        Self::sqrt_ratio(self, &Self::ONE)
-    }
-
-    /// Returns the square root of the field element, if it is
-    /// quadratic residue.
-    ///
-    /// The provided method is implemented in terms of [`Self::sqrt_ratio`].
-    fn sqrt(&self) -> CtOption<Self> {
-        let (is_square, res) = Self::sqrt_ratio(self, &Self::ONE);
-        CtOption::new(res, is_square)
-    }
-
-    /// Exponentiates `self` by `exp`, where `exp` is a little-endian order integer
-    /// exponent.
-    ///
-    /// # Guarantees
-    ///
-    /// This operation is constant time with respect to `self`, for all exponents with the
-    /// same number of digits (`exp.as_ref().len()`). It is variable time with respect to
-    /// the number of digits in the exponent.
-    fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
-        let mut res = Self::ONE;
-        for e in exp.as_ref().iter().rev() {
-            for i in (0..64).rev() {
-                res = res.square();
-                let mut tmp = res;
-                tmp *= self;
-                res.conditional_assign(&tmp, (((*e >> i) & 1) as u8).into());
-            }
-        }
-        res
-    }
-
-    /// Exponentiates `self` by `exp`, where `exp` is a little-endian order integer
-    /// exponent.
-    ///
-    /// # Guarantees
-    ///
-    /// **This operation is variable time with respect to `self`, for all exponent.** If
-    /// the exponent is fixed, this operation is effectively constant time. However, for
-    /// stronger constant-time guarantees, [`Field::pow`] should be used.
-    fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
-        let mut res = Self::ONE;
-        for e in exp.as_ref().iter().rev() {
-            for i in (0..64).rev() {
-                res = res.square();
-
-                if ((*e >> i) & 1) == 1 {
-                    res.mul_assign(self);
-                }
-            }
-        }
-
-        res
-    }
-}
-
-/// This represents an element of a non-binary prime field.
-pub trait PrimeField: Field + From<u64> {
-    /// The prime field can be converted back and forth into this binary
-    /// representation.
-    type Repr: Copy + Default + Send + Sync + 'static + AsRef<[u8]> + AsMut<[u8]>;
-
-    /// Interpret a string of numbers as a (congruent) prime field element.
-    /// Does not accept unnecessary leading zeroes or a blank string.
-    ///
-    /// # Security
-    ///
-    /// This method provides **no** constant-time guarantees.
-    fn from_str_vartime(s: &str) -> Option<Self> {
-        if s.is_empty() {
-            return None;
-        }
-
-        if s == "0" {
-            return Some(Self::ZERO);
-        }
-
-        let mut res = Self::ZERO;
-
-        let ten = Self::from(10);
-
-        let mut first_digit = true;
-
-        for c in s.chars() {
-            match c.to_digit(10) {
-                Some(c) => {
-                    if first_digit {
-                        if c == 0 {
-                            return None;
-                        }
-
-                        first_digit = false;
-                    }
-
-                    res.mul_assign(&ten);
-                    res.add_assign(&Self::from(u64::from(c)));
-                }
-                None => {
-                    return None;
-                }
-            }
-        }
-
-        Some(res)
-    }
-
-    /// Obtains a field element congruent to the integer `v`.
-    ///
-    /// For fields where `Self::CAPACITY >= 128`, this is injective and will produce a
-    /// unique field element.
-    ///
-    /// For fields where `Self::CAPACITY < 128`, this is surjective; some field elements
-    /// will be produced by multiple values of `v`.
-    ///
-    /// If you want to deterministically sample a field element representing a value, use
-    /// [`FromUniformBytes`] instead.
-    fn from_u128(v: u128) -> Self {
-        let lower = v as u64;
-        let upper = (v >> 64) as u64;
-        let mut tmp = Self::from(upper);
-        for _ in 0..64 {
-            tmp = tmp.double();
-        }
-        tmp + Self::from(lower)
-    }
-
-    /// Attempts to convert a byte representation of a field element into an element of
-    /// this prime field, failing if the input is not canonical (is not smaller than the
-    /// field's modulus).
-    ///
-    /// The byte representation is interpreted with the same endianness as elements
-    /// returned by [`PrimeField::to_repr`].
-    fn from_repr(repr: Self::Repr) -> CtOption<Self>;
-
-    /// Attempts to convert a byte representation of a field element into an element of
-    /// this prime field, failing if the input is not canonical (is not smaller than the
-    /// field's modulus).
-    ///
-    /// The byte representation is interpreted with the same endianness as elements
-    /// returned by [`PrimeField::to_repr`].
-    ///
-    /// # Security
-    ///
-    /// This method provides **no** constant-time guarantees. Implementors of the
-    /// `PrimeField` trait **may** optimise this method using non-constant-time logic.
-    fn from_repr_vartime(repr: Self::Repr) -> Option<Self> {
-        Self::from_repr(repr).into()
-    }
-
-    /// Converts an element of the prime field into the standard byte representation for
-    /// this field.
-    ///
-    /// The endianness of the byte representation is implementation-specific. Generic
-    /// encodings of field elements should be treated as opaque.
-    fn to_repr(&self) -> Self::Repr;
-
-    /// Returns true iff this element is odd.
-    fn is_odd(&self) -> Choice;
-
-    /// Returns true iff this element is even.
-    #[inline(always)]
-    fn is_even(&self) -> Choice {
-        !self.is_odd()
-    }
-
-    /// Modulus of the field written as a string for debugging purposes.
-    ///
-    /// The encoding of the modulus is implementation-specific. Generic users of the
-    /// `PrimeField` trait should treat this string as opaque.
-    const MODULUS: &'static str;
-
-    /// How many bits are needed to represent an element of this field.
-    const NUM_BITS: u32;
-
-    /// How many bits of information can be reliably stored in the field element.
-    ///
-    /// This is usually `Self::NUM_BITS - 1`.
-    const CAPACITY: u32;
-
-    /// Inverse of $2$ in the field.
-    const TWO_INV: Self;
-
-    /// A fixed multiplicative generator of `modulus - 1` order. This element must also be
-    /// a quadratic nonresidue.
-    ///
-    /// It can be calculated using [SageMath] as `GF(modulus).primitive_element()`.
-    ///
-    /// Implementations of this trait MUST ensure that this is the generator used to
-    /// derive `Self::ROOT_OF_UNITY`.
-    ///
-    /// [SageMath]: https://www.sagemath.org/
-    const MULTIPLICATIVE_GENERATOR: Self;
-
-    /// An integer `s` satisfying the equation `2^s * t = modulus - 1` with `t` odd.
-    ///
-    /// This is the number of leading zero bits in the little-endian bit representation of
-    /// `modulus - 1`.
-    const S: u32;
-
-    /// The `2^s` root of unity.
-    ///
-    /// It can be calculated by exponentiating `Self::MULTIPLICATIVE_GENERATOR` by `t`,
-    /// where `t = (modulus - 1) >> Self::S`.
-    const ROOT_OF_UNITY: Self;
-
-    /// Inverse of [`Self::ROOT_OF_UNITY`].
-    const ROOT_OF_UNITY_INV: Self;
-
-    /// Generator of the `t-order` multiplicative subgroup.
-    ///
-    /// It can be calculated by exponentiating [`Self::MULTIPLICATIVE_GENERATOR`] by `2^s`,
-    /// where `s` is [`Self::S`].
-    const DELTA: Self;
-}
-
-/// The subset of prime-order fields such that `(modulus - 1)` is divisible by `N`.
-///
-/// If `N` is prime, there will be `N - 1` valid choices of [`Self::ZETA`]. Similarly to
-/// [`PrimeField::MULTIPLICATIVE_GENERATOR`], the specific choice does not matter, as long
-/// as the choice is consistent across all uses of the field.
-pub trait WithSmallOrderMulGroup<const N: u8>: PrimeField {
-    /// A field element of small multiplicative order $N$.
-    ///
-    /// The presence of this element allows you to perform (certain types of)
-    /// endomorphisms on some elliptic curves.
-    ///
-    /// It can be calculated using [SageMath] as
-    /// `GF(modulus).primitive_element() ^ ((modulus - 1) // N)`.
-    /// Choosing the element of order $N$ that is smallest, when considered
-    /// as an integer, may help to ensure consistency.
-    ///
-    /// [SageMath]: https://www.sagemath.org/
-    const ZETA: Self;
-}
-
-/// Trait for constructing a [`PrimeField`] element from a fixed-length uniform byte
-/// array.
-///
-/// "Uniform" means that the byte array's contents must be indistinguishable from the
-/// [discrete uniform distribution]. Suitable byte arrays can be obtained:
-/// - from a cryptographically-secure randomness source (which makes this constructor
-///   equivalent to [`Field::random`]).
-/// - from a cryptographic hash function output, which enables a "random" field element to
-///   be selected deterministically. This is the primary use case for `FromUniformBytes`.
-///
-/// The length `N` of the byte array is chosen by the trait implementer such that the loss
-/// of uniformity in the mapping from byte arrays to field elements is cryptographically
-/// negligible.
-///
-/// [discrete uniform distribution]: https://en.wikipedia.org/wiki/Discrete_uniform_distribution
-///
-/// # Examples
-///
-/// ```
-/// # #[cfg(feature = "derive")] {
-/// # // Fake this so we don't actually need a dev-dependency on bls12_381.
-/// # mod bls12_381 {
-/// #     use ff::{Field, PrimeField};
-/// #
-/// #     #[derive(PrimeField)]
-/// #     #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
-/// #     #[PrimeFieldGenerator = "7"]
-/// #     #[PrimeFieldReprEndianness = "little"]
-/// #     pub struct Scalar([u64; 4]);
-/// #
-/// #     impl ff::FromUniformBytes<64> for Scalar {
-/// #         fn from_uniform_bytes(_bytes: &[u8; 64]) -> Self {
-/// #             // Fake impl for doctest
-/// #             Scalar::ONE
-/// #         }
-/// #     }
-/// # }
-/// #
-/// use blake2b_simd::blake2b;
-/// use bls12_381::Scalar;
-/// use ff::FromUniformBytes;
-///
-/// // `bls12_381::Scalar` implements `FromUniformBytes<64>`, and BLAKE2b (by default)
-/// // produces a 64-byte hash.
-/// let hash = blake2b(b"Some message");
-/// let val = Scalar::from_uniform_bytes(hash.as_array());
-/// # }
-/// ```
-///
-/// # Implementing `FromUniformBytes`
-///
-/// [`Self::from_uniform_bytes`] should always be implemented by interpreting the provided
-/// byte array as the little endian unsigned encoding of an integer, and then reducing that
-/// integer modulo the field modulus.
-///
-/// For security, `N` must be chosen so that `N * 8 >= Self::NUM_BITS + 128`. A larger
-/// value of `N` may be chosen for convenience; for example, for a field with a 255-bit
-/// modulus, `N = 64` is convenient as it matches the output length of several common
-/// cryptographic hash functions (such as SHA-512 and BLAKE2b).
-///
-/// ## Trait design
-///
-/// This trait exists because `PrimeField::from_uniform_bytes([u8; N])` cannot currently
-/// exist (trait methods cannot use associated constants in the const positions of their
-/// type signature, and we do not want `PrimeField` to require a generic const parameter).
-/// However, this has the side-effect that `FromUniformBytes` can be implemented multiple
-/// times for different values of `N`. Most implementations of [`PrimeField`] should only
-/// need to implement `FromUniformBytes` trait for one value of `N` (chosen following the
-/// above considerations); if you find yourself needing to implement it multiple times,
-/// please [let us know about your use case](https://github.com/zkcrypto/ff/issues/new) so
-/// we can take it into consideration for future evolutions of the `ff` traits.
-pub trait FromUniformBytes<const N: usize>: PrimeField {
-    /// Returns a field element that is congruent to the provided little endian unsigned
-    /// byte representation of an integer.
-    fn from_uniform_bytes(bytes: &[u8; N]) -> Self;
-}
-
-/// This represents the bits of an element of a prime field.
-#[cfg(feature = "bits")]
-#[cfg_attr(docsrs, doc(cfg(feature = "bits")))]
-pub trait PrimeFieldBits: PrimeField {
-    /// The backing store for a bit representation of a prime field element.
-    type ReprBits: BitViewSized + Send + Sync;
-
-    /// Converts an element of the prime field into a little-endian sequence of bits.
-    fn to_le_bits(&self) -> FieldBits<Self::ReprBits>;
-
-    /// Returns the bits of the field characteristic (the modulus) in little-endian order.
-    fn char_le_bits() -> FieldBits<Self::ReprBits>;
-}
-
-/// Functions and re-exported crates used by the [`PrimeField`] derive macro.
-#[cfg(feature = "derive")]
-#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
-pub mod derive {
-    pub use crate::arith_impl::*;
-
-    pub use {byteorder, rand_core, subtle};
-
-    #[cfg(feature = "bits")]
-    pub use bitvec;
-}
-
-#[cfg(feature = "derive")]
-mod arith_impl {
-    /// Computes `a - (b + borrow)`, returning the result and the new borrow.
-    #[inline(always)]
-    pub const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
-        let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128));
-        (ret as u64, (ret >> 64) as u64)
-    }
-
-    /// Computes `a + b + carry`, returning the result and the new carry over.
-    #[inline(always)]
-    pub const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) {
-        let ret = (a as u128) + (b as u128) + (carry as u128);
-        (ret as u64, (ret >> 64) as u64)
-    }
-
-    /// Computes `a + (b * c) + carry`, returning the result and the new carry over.
-    #[inline(always)]
-    pub const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) {
-        let ret = (a as u128) + ((b as u128) * (c as u128)) + (carry as u128);
-        (ret as u64, (ret >> 64) as u64)
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/tests/derive.rs b/third_party/rust/chromium_crates_io/vendor/ff-v0_13/tests/derive.rs
deleted file mode 100644
index 5baf435..0000000
--- a/third_party/rust/chromium_crates_io/vendor/ff-v0_13/tests/derive.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! This module exercises the `ff_derive` procedural macros, to ensure that changes to the
-//! `ff` crate are reflected in `ff_derive`. It also uses the resulting field to test some
-//! of the APIs provided by `ff`, such as batch inversion.
-
-#[macro_use]
-extern crate ff;
-
-/// The BLS12-381 scalar field.
-#[derive(PrimeField)]
-#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
-#[PrimeFieldGenerator = "7"]
-#[PrimeFieldReprEndianness = "little"]
-struct Bls381K12Scalar([u64; 4]);
-
-mod fermat {
-    /// The largest known Fermat prime, used to test the case `t = 1`.
-    #[derive(PrimeField)]
-    #[PrimeFieldModulus = "65537"]
-    #[PrimeFieldGenerator = "3"]
-    #[PrimeFieldReprEndianness = "little"]
-    struct Fermat65537Field([u64; 1]);
-}
-
-mod full_limbs {
-    #[derive(PrimeField)]
-    #[PrimeFieldModulus = "39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319"]
-    #[PrimeFieldGenerator = "19"]
-    #[PrimeFieldReprEndianness = "little"]
-    struct F384p([u64; 7]);
-
-    #[test]
-    fn random_masking_does_not_overflow() {
-        use ff::Field;
-        use rand::rngs::OsRng;
-
-        let _ = F384p::random(OsRng);
-    }
-}
-
-#[test]
-fn constants() {
-    use ff::{Field, PrimeField};
-
-    assert_eq!(
-        Bls381K12Scalar::MODULUS,
-        "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001",
-    );
-
-    assert_eq!(
-        Bls381K12Scalar::from(2) * Bls381K12Scalar::TWO_INV,
-        Bls381K12Scalar::ONE,
-    );
-
-    assert_eq!(
-        Bls381K12Scalar::ROOT_OF_UNITY * Bls381K12Scalar::ROOT_OF_UNITY_INV,
-        Bls381K12Scalar::ONE,
-    );
-
-    // ROOT_OF_UNITY^{2^s} mod m == 1
-    assert_eq!(
-        Bls381K12Scalar::ROOT_OF_UNITY.pow(&[1u64 << Bls381K12Scalar::S, 0, 0, 0]),
-        Bls381K12Scalar::ONE,
-    );
-
-    // DELTA^{t} mod m == 1
-    assert_eq!(
-        Bls381K12Scalar::DELTA.pow(&[
-            0xfffe5bfeffffffff,
-            0x09a1d80553bda402,
-            0x299d7d483339d808,
-            0x73eda753,
-        ]),
-        Bls381K12Scalar::ONE,
-    );
-}
-
-#[test]
-fn from_u128() {
-    use ff::{Field, PrimeField};
-
-    assert_eq!(Bls381K12Scalar::from_u128(1), Bls381K12Scalar::ONE);
-    assert_eq!(Bls381K12Scalar::from_u128(2), Bls381K12Scalar::from(2));
-    assert_eq!(
-        Bls381K12Scalar::from_u128(u128::MAX),
-        Bls381K12Scalar::from_str_vartime("340282366920938463463374607431768211455").unwrap(),
-    );
-}
-
-#[test]
-fn batch_inversion() {
-    use ff::{BatchInverter, Field};
-
-    let one = Bls381K12Scalar::ONE;
-
-    // [1, 2, 3, 4]
-    let values: Vec<_> = (0..4)
-        .scan(one, |acc, _| {
-            let ret = *acc;
-            *acc += &one;
-            Some(ret)
-        })
-        .collect();
-
-    // Test BatchInverter::invert_with_external_scratch
-    {
-        let mut elements = values.clone();
-        let mut scratch_space = vec![Bls381K12Scalar::ZERO; elements.len()];
-        BatchInverter::invert_with_external_scratch(&mut elements, &mut scratch_space);
-        for (a, a_inv) in values.iter().zip(elements.into_iter()) {
-            assert_eq!(*a * a_inv, one);
-        }
-    }
-
-    // Test BatchInverter::invert_with_internal_scratch
-    {
-        let mut items: Vec<_> = values.iter().cloned().map(|p| (p, one)).collect();
-        BatchInverter::invert_with_internal_scratch(
-            &mut items,
-            |item| &mut item.0,
-            |item| &mut item.1,
-        );
-        for (a, (a_inv, _)) in values.iter().zip(items.into_iter()) {
-            assert_eq!(*a * a_inv, one);
-        }
-    }
-
-    // Test BatchInvert trait
-    #[cfg(feature = "alloc")]
-    {
-        use ff::BatchInvert;
-        let mut elements = values.clone();
-        elements.iter_mut().batch_invert();
-        for (a, a_inv) in values.iter().zip(elements.into_iter()) {
-            assert_eq!(*a * a_inv, one);
-        }
-    }
-}
-
-#[test]
-fn sqrt() {
-    use ff::{Field, PrimeField};
-    // A field modulo a prime such that p = 1 mod 4 and p != 1 mod 16
-    #[derive(PrimeField)]
-    #[PrimeFieldModulus = "357686312646216567629137"]
-    #[PrimeFieldGenerator = "5"]
-    #[PrimeFieldReprEndianness = "little"]
-    struct Fp([u64; 2]);
-    fn test(square_root: Fp) {
-        let square = square_root.square();
-        let square_root = square.sqrt().unwrap();
-        assert_eq!(square_root.square(), square);
-    }
-
-    test(Fp::ZERO);
-    test(Fp::ONE);
-    use rand::rngs::OsRng;
-    test(Fp::random(OsRng));
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/group-v0_13/.cargo-checksum.json
deleted file mode 100644
index 697c9ce..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.cargo-checksum.json
+++ /dev/null
@@ -1 +0,0 @@
-{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/group-v0_13/.cargo_vcs_info.json
deleted file mode 100644
index dbff4830..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.cargo_vcs_info.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "git": {
-    "sha1": "090a7ec2f2fca9b4ddec05e39123e57dc0d73a2f"
-  }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.github/workflows/ci.yml b/third_party/rust/chromium_crates_io/vendor/group-v0_13/.github/workflows/ci.yml
deleted file mode 100644
index c0ffd6d..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.github/workflows/ci.yml
+++ /dev/null
@@ -1,100 +0,0 @@
-name: CI checks
-
-on: [push, pull_request]
-
-jobs:
-  lint:
-    name: Lint
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v1
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: 1.56.0
-          override: true
-
-      # Ensure all code has been formatted with rustfmt
-      - run: rustup component add rustfmt
-      - name: Check formatting
-        uses: actions-rs/cargo@v1
-        with:
-          command: fmt
-          args: -- --check --color always
-
-  test:
-    name: Test on ${{ matrix.os }}
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os: [ubuntu-latest, windows-latest, macOS-latest]
-
-    steps:
-      - uses: actions/checkout@v1
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: 1.56.0
-          override: true
-      - name: cargo fetch
-        uses: actions-rs/cargo@v1
-        with:
-          command: fetch
-      - name: Build tests
-        uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --verbose --release --tests
-      - name: Run tests
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --verbose --release
-      - name: Run --all-features tests
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --all-features --verbose --release
-
-  no-std:
-    name: Check no-std compatibility
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v1
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: 1.56.0
-          override: true
-      - run: rustup target add thumbv6m-none-eabi
-      - name: cargo fetch
-        uses: actions-rs/cargo@v1
-        with:
-          command: fetch
-      - name: Build
-        uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --verbose --target thumbv6m-none-eabi --no-default-features
-
-  doc-links:
-    name: Nightly lint
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v1
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: nightly
-          override: true
-      - name: cargo fetch
-        uses: actions-rs/cargo@v1
-        with:
-          command: fetch
-
-      # Ensure intra-documentation links all resolve correctly
-      # Requires #![deny(intra_doc_link_resolution_failure)] in crate.
-      - name: Check intra-doc links
-        uses: actions-rs/cargo@v1
-        with:
-          command: doc
-          args: --document-private-items
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.gitignore b/third_party/rust/chromium_crates_io/vendor/group-v0_13/.gitignore
deleted file mode 100644
index 6936990..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/target
-**/*.rs.bk
-Cargo.lock
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/group-v0_13/CHANGELOG.md
deleted file mode 100644
index aec3f6d..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/CHANGELOG.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# Changelog
-All notable changes to this library will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this library adheres to Rust's notion of
-[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [Unreleased]
-
-## [0.13.0] - 2022-12-06
-### Changed
-- Bumped `ff` to `0.13`
-
-## [0.12.1] - 2022-10-13
-### Added
-- `group::{WnafBase, WnafScalar}` structs for caching precomputations of both
-  bases and scalars, for improved many-base many-scalar multiplication
-  performance.
-- `impl memuse::DynamicUsage for group::{Wnaf WnafBase, WnafScalar}`, behind the
-  new `wnaf-memuse` feature flag, to enable the heap usage of these types to be
-  measured at runtime.
-
-### Changed
-- Removed temporary allocations from `Wnaf` internals for improved performance.
-
-## [0.12.0] - 2022-05-04
-### Changed
-- MSRV is now 1.56.0.
-- Bumped `ff` to `0.12`
-
-## [0.11.0] - 2021-09-02
-### Fixed
-- The affine scalar multiplication bounds on the following traits had typos that
-  prevented multiplying by `&Self::Scalar`, which has now been fixed:
-  - `group::cofactor::{CofactorCurve::Affine, CofactorCurveAffine}`
-  - `group::prime::{PrimeCurve::Affine, PrimeCurveAffine}`
-
-### Added
-- `Copy + Send + Sync + 'static` bounds on `group::GroupEncoding::Repr`.
-
-### Changed
-- Bumped `ff` to 0.11.
-
-## [0.10.0] - 2021-06-01
-### Added
-- `group::ff`, which re-exports the `ff` crate to make version-matching easier.
-
-### Changed
-- MSRV is now 1.51.0.
-- Bumped `ff` to 0.10.
-
-### Removed
-- `group::cofactor::CofactorGroup::is_torsion_free` provided implementation
-  (trait implementors must now implement this method themselves). This avoids
-  a hard dependency on the `ff/bits` feature flag.
-
-## [0.9.0] - 2021-01-06
-### Changed
-- Bumped dependencies to `ff 0.9`, `rand_core 0.6`, `rand 0.8`.
-
-## [0.8.0] - 2020-09-08
-### Added
-- `no_std` support.
-
-### Changed
-- MSRV is now 1.44.0.
-- Bumped `ff` to 0.8.
-- `group::{wnaf, Wnaf, WnafGroup}` are now gated behind the (default-enabled)
-  `alloc` feature flag. The `byteorder` dependency is now optional.
-- `group::tests` is now gated behind the `tests` feature flag. The `rand` and
-  `rand_xorshift` dependencies are now optional.
-
-### Removed
-- `fmt::Display` bound from the following traits:
-  - `group::Group`
-  - `group::cofactor::CofactorCurveAffine`
-  - `group::prime::PrimeCurveAffine`
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/COPYRIGHT b/third_party/rust/chromium_crates_io/vendor/group-v0_13/COPYRIGHT
deleted file mode 100644
index 849e327..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/COPYRIGHT
+++ /dev/null
@@ -1,14 +0,0 @@
-Copyrights in the "group" library are retained by their contributors. No
-copyright assignment is required to contribute to the "group" library.
-
-The "group" library is licensed under either of
-
- * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT)
-
-at your option.
-
-Unless you explicitly state otherwise, any contribution intentionally
-submitted for inclusion in the work by you, as defined in the Apache-2.0
-license, shall be dual licensed as above, without any additional terms or
-conditions.
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml
deleted file mode 100644
index 270336ad..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml
+++ /dev/null
@@ -1,55 +0,0 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies.
-#
-# If you are reading this file be aware that the original Cargo.toml
-# will likely look very different (and much more reasonable).
-# See Cargo.toml.orig for the original contents.
-
-[package]
-edition = "2021"
-name = "group"
-version = "0.13.0"
-authors = ["Sean Bowe <ewillbefull@gmail.com>", "Jack Grigg <jack@z.cash>"]
-description = "Elliptic curve group traits and utilities"
-homepage = "https://github.com/zkcrypto/group"
-documentation = "https://docs.rs/group/"
-readme = "README.md"
-license = "MIT/Apache-2.0"
-repository = "https://github.com/zkcrypto/group"
-resolver = "2"
-[dependencies.ff]
-version = "0.13"
-default-features = false
-
-[dependencies.memuse]
-version = "0.2"
-optional = true
-
-[dependencies.rand]
-version = "0.8"
-optional = true
-default-features = false
-
-[dependencies.rand_core]
-version = "0.9"
-default-features = false
-
-[dependencies.rand_xorshift]
-version = "0.3"
-optional = true
-
-[dependencies.subtle]
-version = "2.2.1"
-default-features = false
-
-[features]
-alloc = []
-default = ["alloc"]
-tests = ["alloc", "rand", "rand_xorshift"]
-wnaf-memuse = ["alloc", "memuse"]
-[badges.maintenance]
-status = "actively-developed"
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml.orig
deleted file mode 100644
index 60c0854a..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/Cargo.toml.orig
+++ /dev/null
@@ -1,34 +0,0 @@
-[package]
-name = "group"
-version = "0.13.0"
-authors = [
-    "Sean Bowe <ewillbefull@gmail.com>",
-    "Jack Grigg <jack@z.cash>",
-]
-readme = "README.md"
-license = "MIT/Apache-2.0"
-
-description = "Elliptic curve group traits and utilities"
-documentation = "https://docs.rs/group/"
-homepage = "https://github.com/zkcrypto/group"
-repository = "https://github.com/zkcrypto/group"
-edition = "2021"
-
-[dependencies]
-ff = { version = "0.13", default-features = false }
-rand = { version = "0.8", optional = true, default-features = false }
-rand_core = { version = "0.6", default-features = false }
-rand_xorshift = { version = "0.3", optional = true }
-subtle = { version = "2.2.1", default-features = false }
-
-# Crate for exposing the dynamic memory usage of the w-NAF structs.
-memuse = { version = "0.2", optional = true }
-
-[features]
-default = ["alloc"]
-alloc = []
-tests = ["alloc", "rand", "rand_xorshift"]
-wnaf-memuse = ["alloc", "memuse"]
-
-[badges]
-maintenance = { status = "actively-developed" }
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/group-v0_13/LICENSE-APACHE
deleted file mode 100644
index 16fe87b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/LICENSE-APACHE
+++ /dev/null
@@ -1,201 +0,0 @@
-                              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/group-v0_13/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/group-v0_13/LICENSE-MIT
deleted file mode 100644
index 31aa7938..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/LICENSE-MIT
+++ /dev/null
@@ -1,23 +0,0 @@
-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
-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/group-v0_13/README.md b/third_party/rust/chromium_crates_io/vendor/group-v0_13/README.md
deleted file mode 100644
index 5c2398b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# group [![Crates.io](https://img.shields.io/crates/v/group.svg)](https://crates.io/crates/group) #
-
-`group` is a crate for working with groups over elliptic curves.
-
-## License
-
-Licensed under either of
-
- * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
-   http://www.apache.org/licenses/LICENSE-2.0)
- * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
-
-at your option.
-
-### Contribution
-
-Unless you explicitly state otherwise, any contribution intentionally
-submitted for inclusion in the work by you, as defined in the Apache-2.0
-license, shall be dual licensed as above, without any additional terms or
-conditions.
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain b/third_party/rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain
deleted file mode 100644
index af92bdd9..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/rust-toolchain
+++ /dev/null
@@ -1 +0,0 @@
-1.63.0
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/cofactor.rs b/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/cofactor.rs
deleted file mode 100644
index 84bfe0a..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/cofactor.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-use core::fmt;
-use core::ops::{Mul, Neg};
-use ff::PrimeField;
-use subtle::{Choice, CtOption};
-
-use crate::{prime::PrimeGroup, Curve, Group, GroupEncoding, GroupOps, GroupOpsOwned};
-
-/// This trait represents an element of a cryptographic group with a large prime-order
-/// subgroup and a comparatively-small cofactor.
-pub trait CofactorGroup:
-    Group
-    + GroupEncoding
-    + GroupOps<<Self as CofactorGroup>::Subgroup>
-    + GroupOpsOwned<<Self as CofactorGroup>::Subgroup>
-{
-    /// The large prime-order subgroup in which cryptographic operations are performed.
-    /// If `Self` implements `PrimeGroup`, then `Self::Subgroup` may be `Self`.
-    type Subgroup: PrimeGroup<Scalar = Self::Scalar> + Into<Self>;
-
-    /// Maps `self` to the prime-order subgroup by multiplying this element by some
-    /// `k`-multiple of the cofactor.
-    ///
-    /// The value `k` does not vary between inputs for a given implementation, but may
-    /// vary between different implementations of `CofactorGroup` because some groups have
-    /// more efficient methods of clearing the cofactor when `k` is allowed to be
-    /// different than `1`.
-    ///
-    /// If `Self` implements [`PrimeGroup`], this returns `self`.
-    fn clear_cofactor(&self) -> Self::Subgroup;
-
-    /// Returns `self` if it is contained in the prime-order subgroup.
-    ///
-    /// If `Self` implements [`PrimeGroup`], this returns `Some(self)`.
-    fn into_subgroup(self) -> CtOption<Self::Subgroup>;
-
-    /// Determines if this element is of small order.
-    ///
-    /// Returns:
-    /// - `true` if `self` is in the torsion subgroup.
-    /// - `false` if `self` is not in the torsion subgroup.
-    fn is_small_order(&self) -> Choice {
-        self.clear_cofactor().is_identity()
-    }
-
-    /// Determines if this element is "torsion free", i.e., is contained in the
-    /// prime-order subgroup.
-    ///
-    /// Returns:
-    /// - `true` if `self` has trivial torsion and is in the prime-order subgroup.
-    /// - `false` if `self` has non-zero torsion component and is not in the prime-order
-    ///   subgroup.
-    fn is_torsion_free(&self) -> Choice;
-}
-
-/// Efficient representation of an elliptic curve point guaranteed to be
-/// in the correct prime order subgroup.
-pub trait CofactorCurve:
-    Curve<AffineRepr = <Self as CofactorCurve>::Affine> + CofactorGroup
-{
-    type Affine: CofactorCurveAffine<Curve = Self, Scalar = Self::Scalar>
-        + Mul<Self::Scalar, Output = Self>
-        + for<'r> Mul<&'r Self::Scalar, Output = Self>;
-}
-
-/// Affine representation of an elliptic curve point guaranteed to be
-/// in the correct prime order subgroup.
-pub trait CofactorCurveAffine:
-    GroupEncoding
-    + Copy
-    + Clone
-    + Sized
-    + Send
-    + Sync
-    + fmt::Debug
-    + PartialEq
-    + Eq
-    + 'static
-    + Neg<Output = Self>
-    + Mul<<Self as CofactorCurveAffine>::Scalar, Output = <Self as CofactorCurveAffine>::Curve>
-    + for<'r> Mul<
-        &'r <Self as CofactorCurveAffine>::Scalar,
-        Output = <Self as CofactorCurveAffine>::Curve,
-    >
-{
-    type Scalar: PrimeField;
-    type Curve: CofactorCurve<Affine = Self, Scalar = Self::Scalar>;
-
-    /// Returns the additive identity.
-    fn identity() -> Self;
-
-    /// Returns a fixed generator of unknown exponent.
-    fn generator() -> Self;
-
-    /// Determines if this point represents the point at infinity; the
-    /// additive identity.
-    fn is_identity(&self) -> Choice;
-
-    /// Converts this element to its curve representation.
-    fn to_curve(&self) -> Self::Curve;
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/lib.rs
deleted file mode 100644
index 27ed5c9b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/lib.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-#![no_std]
-// Catch documentation errors caused by code changes.
-#![deny(rustdoc::broken_intra_doc_links)]
-
-#[cfg(feature = "alloc")]
-#[macro_use]
-extern crate alloc;
-
-// Re-export ff to make version-matching easier.
-pub use ff;
-
-use core::fmt;
-use core::iter::Sum;
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
-use ff::PrimeField;
-use rand_core::RngCore;
-use subtle::{Choice, CtOption};
-
-pub mod cofactor;
-pub mod prime;
-#[cfg(feature = "tests")]
-pub mod tests;
-
-#[cfg(feature = "alloc")]
-mod wnaf;
-#[cfg(feature = "alloc")]
-pub use self::wnaf::{Wnaf, WnafBase, WnafGroup, WnafScalar};
-
-/// A helper trait for types with a group operation.
-pub trait GroupOps<Rhs = Self, Output = Self>:
-    Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + AddAssign<Rhs> + SubAssign<Rhs>
-{
-}
-
-impl<T, Rhs, Output> GroupOps<Rhs, Output> for T where
-    T: Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + AddAssign<Rhs> + SubAssign<Rhs>
-{
-}
-
-/// A helper trait for references with a group operation.
-pub trait GroupOpsOwned<Rhs = Self, Output = Self>: for<'r> GroupOps<&'r Rhs, Output> {}
-impl<T, Rhs, Output> GroupOpsOwned<Rhs, Output> for T where T: for<'r> GroupOps<&'r Rhs, Output> {}
-
-/// A helper trait for types implementing group scalar multiplication.
-pub trait ScalarMul<Rhs, Output = Self>: Mul<Rhs, Output = Output> + MulAssign<Rhs> {}
-
-impl<T, Rhs, Output> ScalarMul<Rhs, Output> for T where T: Mul<Rhs, Output = Output> + MulAssign<Rhs>
-{}
-
-/// A helper trait for references implementing group scalar multiplication.
-pub trait ScalarMulOwned<Rhs, Output = Self>: for<'r> ScalarMul<&'r Rhs, Output> {}
-impl<T, Rhs, Output> ScalarMulOwned<Rhs, Output> for T where T: for<'r> ScalarMul<&'r Rhs, Output> {}
-
-/// This trait represents an element of a cryptographic group.
-pub trait Group:
-    Clone
-    + Copy
-    + fmt::Debug
-    + Eq
-    + Sized
-    + Send
-    + Sync
-    + 'static
-    + Sum
-    + for<'a> Sum<&'a Self>
-    + Neg<Output = Self>
-    + GroupOps
-    + GroupOpsOwned
-    + ScalarMul<<Self as Group>::Scalar>
-    + ScalarMulOwned<<Self as Group>::Scalar>
-{
-    /// Scalars modulo the order of this group's scalar field.
-    type Scalar: PrimeField;
-
-    /// Returns an element chosen uniformly at random from the non-identity elements of
-    /// this group.
-    ///
-    /// This function is non-deterministic, and samples from the user-provided RNG.
-    fn random(rng: impl RngCore) -> Self;
-
-    /// Returns the additive identity, also known as the "neutral element".
-    fn identity() -> Self;
-
-    /// Returns a fixed generator of the prime-order subgroup.
-    fn generator() -> Self;
-
-    /// Determines if this point is the identity.
-    fn is_identity(&self) -> Choice;
-
-    /// Doubles this element.
-    #[must_use]
-    fn double(&self) -> Self;
-}
-
-/// Efficient representation of an elliptic curve point guaranteed.
-pub trait Curve:
-    Group + GroupOps<<Self as Curve>::AffineRepr> + GroupOpsOwned<<Self as Curve>::AffineRepr>
-{
-    /// The affine representation for this elliptic curve.
-    type AffineRepr;
-
-    /// Converts a batch of projective elements into affine elements. This function will
-    /// panic if `p.len() != q.len()`.
-    fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
-        assert_eq!(p.len(), q.len());
-
-        for (p, q) in p.iter().zip(q.iter_mut()) {
-            *q = p.to_affine();
-        }
-    }
-
-    /// Converts this element into its affine representation.
-    fn to_affine(&self) -> Self::AffineRepr;
-}
-
-pub trait GroupEncoding: Sized {
-    /// The encoding of group elements.
-    ///
-    /// The `Default` implementation is not required to return a valid point encoding. The
-    /// bound is present to enable encodings to be constructed generically:
-    /// ```
-    /// # use group::GroupEncoding;
-    /// # use subtle::CtOption;
-    /// # struct G;
-    /// # impl GroupEncoding for G {
-    /// #     type Repr = [u8; 0];
-    /// #     fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { unimplemented!() }
-    /// #     fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { unimplemented!() }
-    /// #     fn to_bytes(&self) -> Self::Repr { unimplemented!() }
-    /// # }
-    /// # let buf = &[0u8; 0][..];
-    /// let mut encoding = <G as GroupEncoding>::Repr::default();
-    /// encoding.as_mut().copy_from_slice(buf);
-    /// ```
-    ///
-    /// It is recommended that the default should be the all-zeroes encoding.
-    type Repr: Copy + Default + Send + Sync + 'static + AsRef<[u8]> + AsMut<[u8]>;
-
-    /// Attempts to deserialize a group element from its encoding.
-    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self>;
-
-    /// Attempts to deserialize a group element, not checking if the element is valid.
-    ///
-    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
-    /// API invariants may be broken.** Please consider using
-    /// [`GroupEncoding::from_bytes`] instead.
-    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self>;
-
-    /// Converts this element into its byte encoding. This may or may not support
-    /// encoding the identity.
-    // TODO: Figure out how to handle identity encoding generically.
-    fn to_bytes(&self) -> Self::Repr;
-}
-
-/// Affine representation of a point on an elliptic curve that has a defined uncompressed
-/// encoding.
-pub trait UncompressedEncoding: Sized {
-    type Uncompressed: Default + AsRef<[u8]> + AsMut<[u8]>;
-
-    /// Attempts to deserialize an element from its uncompressed encoding.
-    fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self>;
-
-    /// Attempts to deserialize an uncompressed element, not checking if the element is in
-    /// the correct subgroup.
-    ///
-    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
-    /// API invariants may be broken.** Please consider using
-    /// [`UncompressedEncoding::from_uncompressed`] instead.
-    fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self>;
-
-    /// Converts this element into its uncompressed encoding, so long as it's not
-    /// the point at infinity.
-    fn to_uncompressed(&self) -> Self::Uncompressed;
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/prime.rs b/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/prime.rs
deleted file mode 100644
index 174888e..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/prime.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use core::fmt;
-use core::ops::{Mul, Neg};
-use ff::PrimeField;
-use subtle::Choice;
-
-use crate::{Curve, Group, GroupEncoding};
-
-/// This trait represents an element of a prime-order cryptographic group.
-pub trait PrimeGroup: Group + GroupEncoding {}
-
-/// Efficient representation of an elliptic curve point guaranteed to be
-/// in the correct prime order subgroup.
-pub trait PrimeCurve: Curve<AffineRepr = <Self as PrimeCurve>::Affine> + PrimeGroup {
-    type Affine: PrimeCurveAffine<Curve = Self, Scalar = Self::Scalar>
-        + Mul<Self::Scalar, Output = Self>
-        + for<'r> Mul<&'r Self::Scalar, Output = Self>;
-}
-
-/// Affine representation of an elliptic curve point guaranteed to be
-/// in the correct prime order subgroup.
-pub trait PrimeCurveAffine: GroupEncoding
-    + Copy
-    + Clone
-    + Sized
-    + Send
-    + Sync
-    + fmt::Debug
-    + PartialEq
-    + Eq
-    + 'static
-    + Neg<Output = Self>
-    + Mul<<Self as PrimeCurveAffine>::Scalar, Output = <Self as PrimeCurveAffine>::Curve>
-    + for<'r> Mul<&'r <Self as PrimeCurveAffine>::Scalar, Output = <Self as PrimeCurveAffine>::Curve>
-{
-    type Scalar: PrimeField;
-    type Curve: PrimeCurve<Affine = Self, Scalar = Self::Scalar>;
-
-    /// Returns the additive identity.
-    fn identity() -> Self;
-
-    /// Returns a fixed generator of unknown exponent.
-    fn generator() -> Self;
-
-    /// Determines if this point represents the point at infinity; the
-    /// additive identity.
-    fn is_identity(&self) -> Choice;
-
-    /// Converts this element to its curve representation.
-    fn to_curve(&self) -> Self::Curve;
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/tests/mod.rs b/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/tests/mod.rs
deleted file mode 100644
index ff79a9b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/tests/mod.rs
+++ /dev/null
@@ -1,448 +0,0 @@
-use alloc::vec::Vec;
-use core::ops::{Mul, Neg};
-use ff::{Field, PrimeField};
-use rand::SeedableRng;
-use rand_xorshift::XorShiftRng;
-
-use crate::{
-    prime::{PrimeCurve, PrimeCurveAffine},
-    wnaf::WnafGroup,
-    GroupEncoding, UncompressedEncoding,
-};
-
-pub fn curve_tests<G: PrimeCurve>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    // Negation edge case with identity.
-    {
-        let z = G::identity().neg();
-        assert!(bool::from(z.is_identity()));
-    }
-
-    // Doubling edge case with identity.
-    {
-        let z = G::identity().double();
-        assert!(bool::from(z.is_identity()));
-    }
-
-    // Addition edge cases with identity
-    {
-        let mut r = G::random(&mut rng);
-        let rcopy = r;
-        r.add_assign(&G::identity());
-        assert_eq!(r, rcopy);
-        r.add_assign(&G::Affine::identity());
-        assert_eq!(r, rcopy);
-
-        let mut z = G::identity();
-        z.add_assign(&G::identity());
-        assert!(bool::from(z.is_identity()));
-        z.add_assign(&G::Affine::identity());
-        assert!(bool::from(z.is_identity()));
-
-        let mut z2 = z;
-        z2.add_assign(&r);
-
-        z.add_assign(&r.to_affine());
-
-        assert_eq!(z, z2);
-        assert_eq!(z, r);
-    }
-
-    // Transformations
-    {
-        let a = G::random(&mut rng);
-        let b = a.to_affine().to_curve();
-        let c = a.to_affine().to_curve().to_affine().to_curve();
-        assert_eq!(a, b);
-        assert_eq!(b, c);
-    }
-
-    random_addition_tests::<G>();
-    random_multiplication_tests::<G>();
-    random_doubling_tests::<G>();
-    random_negation_tests::<G>();
-    random_transformation_tests::<G>();
-    random_compressed_encoding_tests::<G>();
-}
-
-pub fn random_wnaf_tests<G: WnafGroup>() {
-    use crate::wnaf::*;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    {
-        let mut table = vec![];
-        let mut wnaf = vec![];
-
-        for w in 2..14 {
-            for _ in 0..100 {
-                let g = G::random(&mut rng);
-                let s = G::Scalar::random(&mut rng);
-                let mut g1 = g;
-                g1.mul_assign(s);
-
-                wnaf_table(&mut table, g, w);
-                wnaf_form(&mut wnaf, s.to_repr(), w);
-                let g2 = wnaf_exp(&table, &wnaf);
-
-                assert_eq!(g1, g2);
-            }
-        }
-    }
-
-    {
-        fn only_compiles_if_send<S: Send>(_: &S) {}
-
-        for _ in 0..100 {
-            let g = G::random(&mut rng);
-            let s = G::Scalar::random(&mut rng);
-            let mut g1 = g;
-            g1.mul_assign(s);
-
-            let g2 = {
-                let mut wnaf = Wnaf::new();
-                wnaf.base(g, 1).scalar(&s)
-            };
-            let g3 = {
-                let mut wnaf = Wnaf::new();
-                wnaf.scalar(&s).base(g)
-            };
-            let g4 = {
-                let mut wnaf = Wnaf::new();
-                let mut shared = wnaf.base(g, 1).shared();
-
-                only_compiles_if_send(&shared);
-
-                shared.scalar(&s)
-            };
-            let g5 = {
-                let mut wnaf = Wnaf::new();
-                let mut shared = wnaf.scalar(&s).shared();
-
-                only_compiles_if_send(&shared);
-
-                shared.base(g)
-            };
-
-            let g6 = {
-                let mut wnaf = Wnaf::new();
-                {
-                    // Populate the vectors.
-                    wnaf.base(G::random(&mut rng), 1)
-                        .scalar(&G::Scalar::random(&mut rng));
-                }
-                wnaf.base(g, 1).scalar(&s)
-            };
-            let g7 = {
-                let mut wnaf = Wnaf::new();
-                {
-                    // Populate the vectors.
-                    wnaf.base(G::random(&mut rng), 1)
-                        .scalar(&G::Scalar::random(&mut rng));
-                }
-                wnaf.scalar(&s).base(g)
-            };
-            let g8 = {
-                let mut wnaf = Wnaf::new();
-                {
-                    // Populate the vectors.
-                    wnaf.base(G::random(&mut rng), 1)
-                        .scalar(&G::Scalar::random(&mut rng));
-                }
-                let mut shared = wnaf.base(g, 1).shared();
-
-                only_compiles_if_send(&shared);
-
-                shared.scalar(&s)
-            };
-            let g9 = {
-                let mut wnaf = Wnaf::new();
-                {
-                    // Populate the vectors.
-                    wnaf.base(G::random(&mut rng), 1)
-                        .scalar(&G::Scalar::random(&mut rng));
-                }
-                let mut shared = wnaf.scalar(&s).shared();
-
-                only_compiles_if_send(&shared);
-
-                shared.base(g)
-            };
-
-            assert_eq!(g1, g2);
-            assert_eq!(g1, g3);
-            assert_eq!(g1, g4);
-            assert_eq!(g1, g5);
-            assert_eq!(g1, g6);
-            assert_eq!(g1, g7);
-            assert_eq!(g1, g8);
-            assert_eq!(g1, g9);
-        }
-    }
-}
-
-fn random_negation_tests<G: PrimeCurve>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    for _ in 0..1000 {
-        let r = G::random(&mut rng);
-
-        let s = G::Scalar::random(&mut rng);
-        let sneg = s.neg();
-
-        let mut t1 = r;
-        t1.mul_assign(s);
-
-        let mut t2 = r;
-        t2.mul_assign(sneg);
-
-        let mut t3 = t1;
-        t3.add_assign(&t2);
-        assert!(bool::from(t3.is_identity()));
-
-        let mut t4 = t1;
-        t4.add_assign(&t2.to_affine());
-        assert!(bool::from(t4.is_identity()));
-
-        assert_eq!(t1.neg(), t2);
-    }
-}
-
-fn random_doubling_tests<G: PrimeCurve>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    for _ in 0..1000 {
-        let mut a = G::random(&mut rng);
-        let mut b = G::random(&mut rng);
-
-        // 2(a + b)
-        let tmp1 = (a + b).double();
-
-        // 2a + 2b
-        a = a.double();
-        b = b.double();
-
-        let mut tmp2 = a;
-        tmp2.add_assign(&b);
-
-        let mut tmp3 = a;
-        tmp3.add_assign(&b.to_affine());
-
-        assert_eq!(tmp1, tmp2);
-        assert_eq!(tmp1, tmp3);
-    }
-}
-
-fn random_multiplication_tests<G: PrimeCurve>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    for _ in 0..1000 {
-        let mut a = G::random(&mut rng);
-        let mut b = G::random(&mut rng);
-        let a_affine = a.to_affine();
-        let b_affine = b.to_affine();
-
-        let s = G::Scalar::random(&mut rng);
-
-        // s ( a + b )
-        let mut tmp1 = a;
-        tmp1.add_assign(&b);
-        tmp1.mul_assign(s);
-
-        // sa + sb
-        a.mul_assign(s);
-        b.mul_assign(s);
-
-        let mut tmp2 = a;
-        tmp2.add_assign(&b);
-
-        // Affine multiplication
-        let mut tmp3 = Mul::<G::Scalar>::mul(a_affine, s);
-        tmp3.add_assign(Mul::<G::Scalar>::mul(b_affine, s));
-
-        assert_eq!(tmp1, tmp2);
-        assert_eq!(tmp1, tmp3);
-    }
-}
-
-fn random_addition_tests<G: PrimeCurve>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    for _ in 0..1000 {
-        let a = G::random(&mut rng);
-        let b = G::random(&mut rng);
-        let c = G::random(&mut rng);
-        let a_affine = a.to_affine();
-        let b_affine = b.to_affine();
-        let c_affine = c.to_affine();
-
-        // a + a should equal the doubling
-        {
-            let mut aplusa = a;
-            aplusa.add_assign(&a);
-
-            let mut aplusamixed = a;
-            aplusamixed.add_assign(&a.to_affine());
-
-            let adouble = a.double();
-
-            assert_eq!(aplusa, adouble);
-            assert_eq!(aplusa, aplusamixed);
-        }
-
-        let mut tmp = vec![G::identity(); 6];
-
-        // (a + b) + c
-        tmp[0] = a;
-        tmp[0].add_assign(&b);
-        tmp[0].add_assign(&c);
-
-        // a + (b + c)
-        tmp[1] = b;
-        tmp[1].add_assign(&c);
-        tmp[1].add_assign(&a);
-
-        // (a + c) + b
-        tmp[2] = a;
-        tmp[2].add_assign(&c);
-        tmp[2].add_assign(&b);
-
-        // Mixed addition
-
-        // (a + b) + c
-        tmp[3] = a_affine.to_curve();
-        tmp[3].add_assign(&b_affine);
-        tmp[3].add_assign(&c_affine);
-
-        // a + (b + c)
-        tmp[4] = b_affine.to_curve();
-        tmp[4].add_assign(&c_affine);
-        tmp[4].add_assign(&a_affine);
-
-        // (a + c) + b
-        tmp[5] = a_affine.to_curve();
-        tmp[5].add_assign(&c_affine);
-        tmp[5].add_assign(&b_affine);
-
-        // Comparisons
-        for i in 0..6 {
-            for j in 0..6 {
-                assert_eq!(tmp[i], tmp[j]);
-                assert_eq!(tmp[i].to_affine(), tmp[j].to_affine());
-            }
-
-            assert!(tmp[i] != a);
-            assert!(tmp[i] != b);
-            assert!(tmp[i] != c);
-
-            assert!(a != tmp[i]);
-            assert!(b != tmp[i]);
-            assert!(c != tmp[i]);
-        }
-    }
-}
-
-fn random_transformation_tests<G: PrimeCurve>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    for _ in 0..1000 {
-        let g = G::random(&mut rng);
-        let g_affine = g.to_affine();
-        let g_projective = g_affine.to_curve();
-        assert_eq!(g, g_projective);
-    }
-
-    // Batch normalization
-    for _ in 0..10 {
-        let mut v = (0..1000).map(|_| G::random(&mut rng)).collect::<Vec<_>>();
-
-        use rand::distributions::{Distribution, Uniform};
-        let between = Uniform::new(0, 1000);
-        // Sprinkle in some normalized points
-        for _ in 0..5 {
-            v[between.sample(&mut rng)] = G::identity();
-        }
-        for _ in 0..5 {
-            let s = between.sample(&mut rng);
-            v[s] = v[s].to_affine().to_curve();
-        }
-
-        let expected_v = v.iter().map(|v| v.to_affine()).collect::<Vec<_>>();
-
-        let mut normalized = vec![G::Affine::identity(); v.len()];
-        G::batch_normalize(&v, &mut normalized);
-
-        assert_eq!(normalized, expected_v);
-    }
-}
-
-fn random_compressed_encoding_tests<G: PrimeCurve>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    assert_eq!(
-        G::Affine::from_bytes(&G::Affine::identity().to_bytes()).unwrap(),
-        G::Affine::identity()
-    );
-
-    for _ in 0..1000 {
-        let mut r = G::random(&mut rng).to_affine();
-
-        let compressed = r.to_bytes();
-        let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
-        assert_eq!(de_compressed, r);
-
-        r = r.neg();
-
-        let compressed = r.to_bytes();
-        let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
-        assert_eq!(de_compressed, r);
-    }
-}
-
-pub fn random_uncompressed_encoding_tests<G: PrimeCurve>()
-where
-    <G as PrimeCurve>::Affine: UncompressedEncoding,
-{
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    assert_eq!(
-        G::Affine::from_uncompressed(&G::Affine::identity().to_uncompressed()).unwrap(),
-        G::Affine::identity()
-    );
-
-    for _ in 0..1000 {
-        let r = G::random(&mut rng).to_affine();
-
-        let uncompressed = r.to_uncompressed();
-        let de_uncompressed = G::Affine::from_uncompressed(&uncompressed).unwrap();
-        assert_eq!(de_uncompressed, r);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/wnaf.rs b/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/wnaf.rs
deleted file mode 100644
index 175d6766..0000000
--- a/third_party/rust/chromium_crates_io/vendor/group-v0_13/src/wnaf.rs
+++ /dev/null
@@ -1,506 +0,0 @@
-use alloc::vec::Vec;
-use core::iter;
-use core::marker::PhantomData;
-use core::ops::Mul;
-
-use ff::PrimeField;
-
-use super::Group;
-
-/// Extension trait on a [`Group`] that provides helpers used by [`Wnaf`].
-pub trait WnafGroup: Group {
-    /// Recommends a wNAF window size given the number of scalars you intend to multiply
-    /// a base by. Always returns a number between 2 and 22, inclusive.
-    fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
-}
-
-/// Replaces the contents of `table` with a w-NAF window table for the given window size.
-pub(crate) fn wnaf_table<G: Group>(table: &mut Vec<G>, mut base: G, window: usize) {
-    table.truncate(0);
-    table.reserve(1 << (window - 1));
-
-    let dbl = base.double();
-
-    for _ in 0..(1 << (window - 1)) {
-        table.push(base);
-        base.add_assign(&dbl);
-    }
-}
-
-/// This struct represents a view of a sequence of bytes as a sequence of
-/// `u64` limbs in little-endian byte order. It maintains a current index, and
-/// allows access to the limb at that index and the one following it. Bytes
-/// beyond the end of the original buffer are treated as zero.
-struct LimbBuffer<'a> {
-    buf: &'a [u8],
-    cur_idx: usize,
-    cur_limb: u64,
-    next_limb: u64,
-}
-
-impl<'a> LimbBuffer<'a> {
-    fn new(buf: &'a [u8]) -> Self {
-        let mut ret = Self {
-            buf,
-            cur_idx: 0,
-            cur_limb: 0,
-            next_limb: 0,
-        };
-
-        // Initialise the limb buffers.
-        ret.increment_limb();
-        ret.increment_limb();
-        ret.cur_idx = 0usize;
-
-        ret
-    }
-
-    fn increment_limb(&mut self) {
-        self.cur_idx += 1;
-        self.cur_limb = self.next_limb;
-        match self.buf.len() {
-            // There are no more bytes in the buffer; zero-extend.
-            0 => self.next_limb = 0,
-
-            // There are fewer bytes in the buffer than a u64 limb; zero-extend.
-            x @ 1..=7 => {
-                let mut next_limb = [0; 8];
-                next_limb[..x].copy_from_slice(self.buf);
-                self.next_limb = u64::from_le_bytes(next_limb);
-                self.buf = &[];
-            }
-
-            // There are at least eight bytes in the buffer; read the next u64 limb.
-            _ => {
-                let (next_limb, rest) = self.buf.split_at(8);
-                self.next_limb = u64::from_le_bytes(next_limb.try_into().unwrap());
-                self.buf = rest;
-            }
-        }
-    }
-
-    fn get(&mut self, idx: usize) -> (u64, u64) {
-        assert!([self.cur_idx, self.cur_idx + 1].contains(&idx));
-        if idx > self.cur_idx {
-            self.increment_limb();
-        }
-        (self.cur_limb, self.next_limb)
-    }
-}
-
-/// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian
-/// scalar.
-pub(crate) fn wnaf_form<S: AsRef<[u8]>>(wnaf: &mut Vec<i64>, c: S, window: usize) {
-    // Required by the NAF definition
-    debug_assert!(window >= 2);
-    // Required so that the NAF digits fit in i64
-    debug_assert!(window <= 64);
-
-    let bit_len = c.as_ref().len() * 8;
-
-    wnaf.truncate(0);
-    wnaf.reserve(bit_len);
-
-    // Initialise the current and next limb buffers.
-    let mut limbs = LimbBuffer::new(c.as_ref());
-
-    let width = 1u64 << window;
-    let window_mask = width - 1;
-
-    let mut pos = 0;
-    let mut carry = 0;
-    while pos < bit_len {
-        // Construct a buffer of bits of the scalar, starting at bit `pos`
-        let u64_idx = pos / 64;
-        let bit_idx = pos % 64;
-        let (cur_u64, next_u64) = limbs.get(u64_idx);
-        let bit_buf = if bit_idx + window < 64 {
-            // This window's bits are contained in a single u64
-            cur_u64 >> bit_idx
-        } else {
-            // Combine the current u64's bits with the bits from the next u64
-            (cur_u64 >> bit_idx) | (next_u64 << (64 - bit_idx))
-        };
-
-        // Add the carry into the current window
-        let window_val = carry + (bit_buf & window_mask);
-
-        if window_val & 1 == 0 {
-            // If the window value is even, preserve the carry and emit 0.
-            // Why is the carry preserved?
-            // If carry == 0 and window_val & 1 == 0, then the next carry should be 0
-            // If carry == 1 and window_val & 1 == 0, then bit_buf & 1 == 1 so the next carry should be 1
-            wnaf.push(0);
-            pos += 1;
-        } else {
-            wnaf.push(if window_val < width / 2 {
-                carry = 0;
-                window_val as i64
-            } else {
-                carry = 1;
-                (window_val as i64).wrapping_sub(width as i64)
-            });
-            wnaf.extend(iter::repeat(0).take(window - 1));
-            pos += window;
-        }
-    }
-}
-
-/// Performs w-NAF exponentiation with the provided window table and w-NAF form scalar.
-///
-/// This function must be provided a `table` and `wnaf` that were constructed with
-/// the same window size; otherwise, it may panic or produce invalid results.
-pub(crate) fn wnaf_exp<G: Group>(table: &[G], wnaf: &[i64]) -> G {
-    let mut result = G::identity();
-
-    let mut found_one = false;
-
-    for n in wnaf.iter().rev() {
-        if found_one {
-            result = result.double();
-        }
-
-        if *n != 0 {
-            found_one = true;
-
-            if *n > 0 {
-                result += &table[(n / 2) as usize];
-            } else {
-                result -= &table[((-n) / 2) as usize];
-            }
-        }
-    }
-
-    result
-}
-
-/// A "w-ary non-adjacent form" scalar multiplication (also known as exponentiation)
-/// context.
-///
-/// # Examples
-///
-/// This struct can be used to implement several patterns:
-///
-/// ## One base, one scalar
-///
-/// For this pattern, you can use a transient `Wnaf` context:
-///
-/// ```ignore
-/// use group::Wnaf;
-///
-/// let result = Wnaf::new().scalar(&scalar).base(base);
-/// ```
-///
-/// ## Many bases, one scalar
-///
-/// For this pattern, you create a `Wnaf` context, load the scalar into it, and then
-/// process each base in turn:
-///
-/// ```ignore
-/// use group::Wnaf;
-///
-/// let mut wnaf = Wnaf::new();
-/// let mut wnaf_scalar = wnaf.scalar(&scalar);
-/// let results: Vec<_> = bases
-///     .into_iter()
-///     .map(|base| wnaf_scalar.base(base))
-///     .collect();
-/// ```
-///
-/// ## One base, many scalars
-///
-/// For this pattern, you create a `Wnaf` context, load the base into it, and then process
-/// each scalar in turn:
-///
-/// ```ignore
-/// use group::Wnaf;
-///
-/// let mut wnaf = Wnaf::new();
-/// let mut wnaf_base = wnaf.base(base, scalars.len());
-/// let results: Vec<_> = scalars
-///     .iter()
-///     .map(|scalar| wnaf_base.scalar(scalar))
-///     .collect();
-/// ```
-///
-/// ## Many bases, many scalars
-///
-/// Say you have `n` bases and `m` scalars, and want to produce `n * m` results. For this
-/// pattern, you need to cache the w-NAF tables for the bases and then compute the w-NAF
-/// form of the scalars on the fly for every base, or vice versa:
-///
-/// ```ignore
-/// use group::Wnaf;
-///
-/// let mut wnaf_contexts: Vec<_> = (0..bases.len()).map(|_| Wnaf::new()).collect();
-/// let mut wnaf_bases: Vec<_> = wnaf_contexts
-///     .iter_mut()
-///     .zip(bases)
-///     .map(|(wnaf, base)| wnaf.base(base, scalars.len()))
-///     .collect();
-/// let results: Vec<_> = wnaf_bases
-///     .iter()
-///     .flat_map(|wnaf_base| scalars.iter().map(|scalar| wnaf_base.scalar(scalar)))
-///     .collect();
-/// ```
-///
-/// Alternatively, use the [`WnafBase`] and [`WnafScalar`] types, which enable the various
-/// tables and w-NAF forms to be cached individually per base and scalar. These types can
-/// then be directly multiplied without any additional runtime work, at the cost of fixing
-/// a specific window size (rather than choosing the window size dynamically).
-#[derive(Debug)]
-pub struct Wnaf<W, B, S> {
-    base: B,
-    scalar: S,
-    window_size: W,
-}
-
-impl<G: Group> Wnaf<(), Vec<G>, Vec<i64>> {
-    /// Construct a new wNAF context without allocating.
-    pub fn new() -> Self {
-        Wnaf {
-            base: vec![],
-            scalar: vec![],
-            window_size: (),
-        }
-    }
-}
-
-#[cfg(feature = "wnaf-memuse")]
-impl<G: Group + memuse::DynamicUsage> memuse::DynamicUsage for Wnaf<(), Vec<G>, Vec<i64>> {
-    fn dynamic_usage(&self) -> usize {
-        self.base.dynamic_usage() + self.scalar.dynamic_usage()
-    }
-
-    fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
-        let (base_lower, base_upper) = self.base.dynamic_usage_bounds();
-        let (scalar_lower, scalar_upper) = self.scalar.dynamic_usage_bounds();
-
-        (
-            base_lower + scalar_lower,
-            base_upper.zip(scalar_upper).map(|(a, b)| a + b),
-        )
-    }
-}
-
-impl<G: WnafGroup> Wnaf<(), Vec<G>, Vec<i64>> {
-    /// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that
-    /// can perform exponentiations with `.scalar(..)`.
-    pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf<usize, &[G], &mut Vec<i64>> {
-        // Compute the appropriate window size based on the number of scalars.
-        let window_size = G::recommended_wnaf_for_num_scalars(num_scalars);
-
-        // Compute a wNAF table for the provided base and window size.
-        wnaf_table(&mut self.base, base, window_size);
-
-        // Return a Wnaf object that immutably borrows the computed base storage location,
-        // but mutably borrows the scalar storage location.
-        Wnaf {
-            base: &self.base[..],
-            scalar: &mut self.scalar,
-            window_size,
-        }
-    }
-
-    /// Given a scalar, compute its wNAF representation and return a `Wnaf` object that can perform
-    /// exponentiations with `.base(..)`.
-    pub fn scalar(&mut self, scalar: &<G as Group>::Scalar) -> Wnaf<usize, &mut Vec<G>, &[i64]> {
-        // We hard-code a window size of 4.
-        let window_size = 4;
-
-        // Compute the wNAF form of the scalar.
-        wnaf_form(&mut self.scalar, scalar.to_repr(), window_size);
-
-        // Return a Wnaf object that mutably borrows the base storage location, but
-        // immutably borrows the computed wNAF form scalar location.
-        Wnaf {
-            base: &mut self.base,
-            scalar: &self.scalar[..],
-            window_size,
-        }
-    }
-}
-
-impl<'a, G: Group> Wnaf<usize, &'a [G], &'a mut Vec<i64>> {
-    /// Constructs new space for the scalar representation while borrowing
-    /// the computed window table, for sending the window table across threads.
-    pub fn shared(&self) -> Wnaf<usize, &'a [G], Vec<i64>> {
-        Wnaf {
-            base: self.base,
-            scalar: vec![],
-            window_size: self.window_size,
-        }
-    }
-}
-
-#[cfg(feature = "wnaf-memuse")]
-impl<'a, G: Group> memuse::DynamicUsage for Wnaf<usize, &'a [G], Vec<i64>> {
-    fn dynamic_usage(&self) -> usize {
-        // The heap memory for the window table is counted in the parent `Wnaf`.
-        self.scalar.dynamic_usage()
-    }
-
-    fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
-        self.scalar.dynamic_usage_bounds()
-    }
-}
-
-impl<'a, G: Group> Wnaf<usize, &'a mut Vec<G>, &'a [i64]> {
-    /// Constructs new space for the window table while borrowing
-    /// the computed scalar representation, for sending the scalar representation
-    /// across threads.
-    pub fn shared(&self) -> Wnaf<usize, Vec<G>, &'a [i64]> {
-        Wnaf {
-            base: vec![],
-            scalar: self.scalar,
-            window_size: self.window_size,
-        }
-    }
-}
-
-#[cfg(feature = "wnaf-memuse")]
-impl<'a, G: Group + memuse::DynamicUsage> memuse::DynamicUsage for Wnaf<usize, Vec<G>, &'a [i64]> {
-    fn dynamic_usage(&self) -> usize {
-        // The heap memory for the scalar representation is counted in the parent `Wnaf`.
-        self.base.dynamic_usage()
-    }
-
-    fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
-        self.base.dynamic_usage_bounds()
-    }
-}
-
-impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
-    /// Performs exponentiation given a base.
-    pub fn base<G: Group>(&mut self, base: G) -> G
-    where
-        B: AsMut<Vec<G>>,
-    {
-        wnaf_table(self.base.as_mut(), base, self.window_size);
-        wnaf_exp(self.base.as_mut(), self.scalar.as_ref())
-    }
-}
-
-impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
-    /// Performs exponentiation given a scalar.
-    pub fn scalar<G: Group>(&mut self, scalar: &<G as Group>::Scalar) -> G
-    where
-        B: AsRef<[G]>,
-    {
-        wnaf_form(self.scalar.as_mut(), scalar.to_repr(), self.window_size);
-        wnaf_exp(self.base.as_ref(), self.scalar.as_mut())
-    }
-}
-
-/// A "w-ary non-adjacent form" scalar, that uses precomputation to improve the speed of
-/// scalar multiplication.
-///
-/// # Examples
-///
-/// See [`WnafBase`] for usage examples.
-#[derive(Clone, Debug)]
-pub struct WnafScalar<F: PrimeField, const WINDOW_SIZE: usize> {
-    wnaf: Vec<i64>,
-    field: PhantomData<F>,
-}
-
-#[cfg(feature = "wnaf-memuse")]
-impl<F: PrimeField, const WINDOW_SIZE: usize> memuse::DynamicUsage for WnafScalar<F, WINDOW_SIZE> {
-    fn dynamic_usage(&self) -> usize {
-        self.wnaf.dynamic_usage()
-    }
-
-    fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
-        self.wnaf.dynamic_usage_bounds()
-    }
-}
-
-impl<F: PrimeField, const WINDOW_SIZE: usize> WnafScalar<F, WINDOW_SIZE> {
-    /// Computes the w-NAF representation of the given scalar with the specified
-    /// `WINDOW_SIZE`.
-    pub fn new(scalar: &F) -> Self {
-        let mut wnaf = vec![];
-
-        // Compute the w-NAF form of the scalar.
-        wnaf_form(&mut wnaf, scalar.to_repr(), WINDOW_SIZE);
-
-        WnafScalar {
-            wnaf,
-            field: PhantomData::default(),
-        }
-    }
-}
-
-/// A fixed window table for a group element, precomputed to improve the speed of scalar
-/// multiplication.
-///
-/// This struct is designed for usage patterns that have long-term cached bases and/or
-/// scalars, or [Cartesian products] of bases and scalars. The [`Wnaf`] API enables one or
-/// the other to be cached, but requires either the base window tables or the scalar w-NAF
-/// forms to be computed repeatedly on the fly, which can become a significant performance
-/// issue for some use cases.
-///
-/// `WnafBase` and [`WnafScalar`] enable an alternative trade-off: by fixing the window
-/// size at compile time, the precomputations are guaranteed to only occur once per base
-/// and once per scalar. Users should select their window size based on how long the bases
-/// are expected to live; a larger window size will consume more memory and take longer to
-/// precompute, but result in faster scalar multiplications.
-///
-/// [Cartesian products]: https://en.wikipedia.org/wiki/Cartesian_product
-///
-/// # Examples
-///
-/// ```ignore
-/// use group::{WnafBase, WnafScalar};
-///
-/// let wnaf_bases: Vec<_> = bases.into_iter().map(WnafBase::<_, 4>::new).collect();
-/// let wnaf_scalars: Vec<_> = scalars.iter().map(WnafScalar::new).collect();
-/// let results: Vec<_> = wnaf_bases
-///     .iter()
-///     .flat_map(|base| wnaf_scalars.iter().map(|scalar| base * scalar))
-///     .collect();
-/// ```
-///
-/// Note that this pattern requires specifying a fixed window size (unlike previous
-/// patterns that picked a suitable window size internally). This is necessary to ensure
-/// in the type system that the base and scalar `Wnaf`s were computed with the same window
-/// size, allowing the result to be computed infallibly.
-#[derive(Clone, Debug)]
-pub struct WnafBase<G: Group, const WINDOW_SIZE: usize> {
-    table: Vec<G>,
-}
-
-#[cfg(feature = "wnaf-memuse")]
-impl<G: Group + memuse::DynamicUsage, const WINDOW_SIZE: usize> memuse::DynamicUsage
-    for WnafBase<G, WINDOW_SIZE>
-{
-    fn dynamic_usage(&self) -> usize {
-        self.table.dynamic_usage()
-    }
-
-    fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
-        self.table.dynamic_usage_bounds()
-    }
-}
-
-impl<G: Group, const WINDOW_SIZE: usize> WnafBase<G, WINDOW_SIZE> {
-    /// Computes a window table for the given base with the specified `WINDOW_SIZE`.
-    pub fn new(base: G) -> Self {
-        let mut table = vec![];
-
-        // Compute a window table for the provided base and window size.
-        wnaf_table(&mut table, base, WINDOW_SIZE);
-
-        WnafBase { table }
-    }
-}
-
-impl<G: Group, const WINDOW_SIZE: usize> Mul<&WnafScalar<G::Scalar, WINDOW_SIZE>>
-    for &WnafBase<G, WINDOW_SIZE>
-{
-    type Output = G;
-
-    fn mul(self, rhs: &WnafScalar<G::Scalar, WINDOW_SIZE>) -> Self::Output {
-        wnaf_exp(&self.table, &rhs.wnaf)
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/.cargo-checksum.json
deleted file mode 100644
index 697c9ce..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/.cargo-checksum.json
+++ /dev/null
@@ -1 +0,0 @@
-{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/.cargo_vcs_info.json
deleted file mode 100644
index 4787b563..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "git": {
-    "sha1": "89a1336b934c68ddce548127c6f8afd910b35a18"
-  },
-  "path_in_vcs": "rand_core"
-}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/CHANGELOG.md
deleted file mode 100644
index 75fcbc6..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/CHANGELOG.md
+++ /dev/null
@@ -1,94 +0,0 @@
-# Changelog
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [0.6.4] - 2022-09-15
-- Fix unsoundness in `<BlockRng64 as RngCore>::next_u32` (#1160)
-- Reduce use of `unsafe` and improve gen_bytes performance (#1180)
-- Add `CryptoRngCore` trait (#1187, #1230)
-
-## [0.6.3] - 2021-06-15
-### Changed
-- Improved bound for `serde` impls on `BlockRng` (#1130)
-- Minor doc additions (#1118)
-
-## [0.6.2] - 2021-02-12
-### Fixed
-- Fixed assertions in `le::read_u32_into` and `le::read_u64_into` which could
-  have allowed buffers not to be fully populated (#1096)
-
-## [0.6.1] - 2021-01-03
-### Fixed
-- Avoid panic when using `RngCore::seed_from_u64` with a seed which is not a
-  multiple of four (#1082)
-### Other
-- Enable all stable features in the playground (#1081)
-
-## [0.6.0] - 2020-12-08
-### Breaking changes
-- Bump MSRV to 1.36, various code improvements (#1011)
-- Update to getrandom v0.2 (#1041)
-- Fix: `next_u32_via_fill` and `next_u64_via_fill` now use LE as documented (#1061)
-
-### Other
-- Reduce usage of `unsafe` (#962, #963, #1011)
-- Annotate feature-gates in documentation (#1019)
-- Document available error codes (#1061)
-- Various documentation tweaks
-- Fix some clippy warnings (#1036)
-- Apply rustfmt (#926)
-
-## [0.5.1] - 2019-08-28
-- `OsRng` added to `rand_core` (#863)
-- `Error::INTERNAL_START` and `Error::CUSTOM_START` constants (#864)
-- `Error::raw_os_error` method (#864)
-- `Debug` and `Display` formatting for `getrandom` error codes without `std` (#864)
-### Changed
-- `alloc` feature in `no_std` is available since Rust 1.36 (#856)
-- Added `#[inline]` to `Error` conversion methods (#864)
-
-## [0.5.0] - 2019-06-06
-### Changed
-- Enable testing with Miri and fix incorrect pointer usages (#779, #780, #781, #783, #784)
-- Rewrite `Error` type and adjust API (#800)
-- Adjust usage of `#[inline]` for `BlockRng` and `BlockRng64`
-
-## [0.4.0] - 2019-01-24
-### Changed
-- Disable the `std` feature by default (#702)
-
-## [0.3.0] - 2018-09-24
-### Added
-- Add `SeedableRng::seed_from_u64` for convenient seeding. (#537)
-
-## [0.2.1] - 2018-06-08
-### Added
-- References to a `CryptoRng` now also implement `CryptoRng`. (#470)
-
-## [0.2.0] - 2018-05-21
-### Changed
-- Enable the `std` feature by default. (#409)
-- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public
-- Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419)
-### Added
-- Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419)
-- Implement `std::io::Read` for RngCore. (#434)
-
-## [0.1.0] - 2018-04-17
-(Split out of the Rand crate, changes here are relative to rand 0.4.2.)
-### Added
-- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288)
-- Add modules to help implementing RNGs `impl` and `le`. (#209, #228)
-- Add `Error` and `ErrorKind`. (#225)
-- Add `CryptoRng` marker trait. (#273)
-- Add `BlockRngCore` trait. (#281)
-- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
-- Add `RngCore::try_fill_bytes`. (#225)
-### Changed
-- Revise the `SeedableRng` trait. (#233)
-- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
-
-## [0.0.1] - 2017-09-14 (yanked)
-Experimental version as part of the rand crate refactor.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/COPYRIGHT b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/COPYRIGHT
deleted file mode 100644
index 468d907..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/COPYRIGHT
+++ /dev/null
@@ -1,12 +0,0 @@
-Copyrights in the Rand project are retained by their contributors. No
-copyright assignment is required to contribute to the Rand project.
-
-For full authorship information, see the version control history.
-
-Except as otherwise noted (below and/or in individual files), Rand is
-licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
-<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
-
-The Rand project includes code from the Rust project
-published under these same licenses.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/Cargo.toml
deleted file mode 100644
index fd8c96d9b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/Cargo.toml
+++ /dev/null
@@ -1,63 +0,0 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies.
-#
-# If you are reading this file be aware that the original Cargo.toml
-# will likely look very different (and much more reasonable).
-# See Cargo.toml.orig for the original contents.
-
-[package]
-edition = "2018"
-name = "rand_core"
-version = "0.6.4"
-authors = [
-    "The Rand Project Developers",
-    "The Rust Project Developers",
-]
-description = """
-Core random number generator traits and tools for implementation.
-"""
-homepage = "https://rust-random.github.io/book"
-documentation = "https://docs.rs/rand_core"
-readme = "README.md"
-keywords = [
-    "random",
-    "rng",
-]
-categories = [
-    "algorithms",
-    "no-std",
-]
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/rust-random/rand"
-
-[package.metadata.docs.rs]
-all-features = true
-rustdoc-args = [
-    "--cfg",
-    "doc_cfg",
-]
-
-[package.metadata.playground]
-all-features = true
-
-[dependencies.getrandom]
-version = "0.2"
-optional = true
-
-[dependencies.serde]
-version = "1"
-features = ["derive"]
-optional = true
-
-[features]
-alloc = []
-serde1 = ["serde"]
-std = [
-    "alloc",
-    "getrandom",
-    "getrandom/std",
-]
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/Cargo.toml.orig
deleted file mode 100644
index bfaa029..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/Cargo.toml.orig
+++ /dev/null
@@ -1,33 +0,0 @@
-[package]
-name = "rand_core"
-version = "0.6.4"
-authors = ["The Rand Project Developers", "The Rust Project Developers"]
-license = "MIT OR Apache-2.0"
-readme = "README.md"
-repository = "https://github.com/rust-random/rand"
-documentation = "https://docs.rs/rand_core"
-homepage = "https://rust-random.github.io/book"
-description = """
-Core random number generator traits and tools for implementation.
-"""
-keywords = ["random", "rng"]
-categories = ["algorithms", "no-std"]
-edition = "2018"
-
-[package.metadata.docs.rs]
-# To build locally:
-# RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --no-deps --open
-all-features = true
-rustdoc-args = ["--cfg", "doc_cfg"]
-
-[package.metadata.playground]
-all-features = true
-
-[features]
-std = ["alloc", "getrandom", "getrandom/std"]    # use std library; should be default but for above bug
-alloc = []  # enables Vec and Box support without std
-serde1 = ["serde"] # enables serde for BlockRng wrapper
-
-[dependencies]
-serde = { version = "1", features = ["derive"], optional = true }
-getrandom = { version = "0.2", optional = true }
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/LICENSE-APACHE
deleted file mode 100644
index 455787c2..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/LICENSE-APACHE
+++ /dev/null
@@ -1,187 +0,0 @@
-                              Apache License
-                        Version 2.0, January 2004
-                     https://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.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/LICENSE-MIT
deleted file mode 100644
index d93b5ba..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/LICENSE-MIT
+++ /dev/null
@@ -1,26 +0,0 @@
-Copyright 2018 Developers of the Rand project
-Copyright (c) 2014 The Rust Project Developers
-
-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
-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/rand_core-v0_6/README.md b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/README.md
deleted file mode 100644
index d32dd6853..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/README.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# rand_core
-
-[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions)
-[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core)
-[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
-[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core)
-[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core)
-[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
-
-Core traits and error types of the [rand] library, plus tools for implementing
-RNGs.
-
-This crate is intended for use when implementing the core trait, `RngCore`; it
-defines the core traits to be implemented as well as several small functions to
-aid in their implementation and types required for error handling.
-
-The main [rand] crate re-exports most items defined in this crate, along with
-tools to convert the integer samples generated by `RngCore` to many different
-applications (including sampling from restricted ranges, conversion to floating
-point, list permutations and secure initialisation of RNGs). Most users should
-prefer to use the main [rand] crate.
-
-Links:
-
--   [API documentation (master)](https://rust-random.github.io/rand/rand_core)
--   [API documentation (docs.rs)](https://docs.rs/rand_core)
--   [Changelog](https://github.com/rust-random/rand/blob/master/rand_core/CHANGELOG.md)
-
-[rand]: https://crates.io/crates/rand
-
-
-## Functionality
-
-The `rand_core` crate provides:
-
--   base random number generator traits
--   error-reporting types
--   functionality to aid implementation of RNGs
-
-The traits and error types are also available via `rand`.
-
-## Versions
-
-The current version is:
-```
-rand_core = "0.6.0"
-```
-
-Rand libs have inter-dependencies and make use of the
-[semver trick](https://github.com/dtolnay/semver-trick/) in order to make traits
-compatible across crate versions. (This is especially important for `RngCore`
-and `SeedableRng`.) A few crate releases are thus compatibility shims,
-depending on the *next* lib version (e.g. `rand_core` versions `0.2.2` and
-`0.3.1`). This means, for example, that `rand_core_0_4_0::SeedableRng` and
-`rand_core_0_3_0::SeedableRng` are distinct, incompatible traits, which can
-cause build errors. Usually, running `cargo update` is enough to fix any issues.
-
-## Crate Features
-
-`rand_core` supports `no_std` and `alloc`-only configurations, as well as full
-`std` functionality. The differences between `no_std` and full `std` are small,
-comprising `RngCore` support for `Box<R>` types where `R: RngCore`,
-`std::io::Read` support for types supporting `RngCore`, and
-extensions to the `Error` type's functionality.
-
-The `std` feature is *not enabled by default*. This is primarily to avoid build
-problems where one crate implicitly requires `rand_core` with `std` support and
-another crate requires `rand` *without* `std` support. However, the `rand` crate
-continues to enable `std` support by default, both for itself and `rand_core`.
-
-The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG
-implementations that use the `BlockRng` or `BlockRng64` wrappers.
-
-
-# License
-
-`rand_core` is distributed under the terms of both the MIT license and the
-Apache License (Version 2.0).
-
-See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
-[COPYRIGHT](COPYRIGHT) for details.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/block.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/block.rs
deleted file mode 100644
index d311b68..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/block.rs
+++ /dev/null
@@ -1,539 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The `BlockRngCore` trait and implementation helpers
-//!
-//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs
-//! which generate a block of data in a cache instead of returning generated
-//! values directly.
-//!
-//! Usage of this trait is optional, but provides two advantages:
-//! implementations only need to concern themselves with generation of the
-//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where
-//! the optimal implementations are not trivial), and this allows
-//! `ReseedingRng` (see [`rand`](https://docs.rs/rand) crate) perform periodic
-//! reseeding with very low overhead.
-//!
-//! # Example
-//!
-//! ```no_run
-//! use rand_core::{RngCore, SeedableRng};
-//! use rand_core::block::{BlockRngCore, BlockRng};
-//!
-//! struct MyRngCore;
-//!
-//! impl BlockRngCore for MyRngCore {
-//!     type Item = u32;
-//!     type Results = [u32; 16];
-//!
-//!     fn generate(&mut self, results: &mut Self::Results) {
-//!         unimplemented!()
-//!     }
-//! }
-//!
-//! impl SeedableRng for MyRngCore {
-//!     type Seed = [u8; 32];
-//!     fn from_seed(seed: Self::Seed) -> Self {
-//!         unimplemented!()
-//!     }
-//! }
-//!
-//! // optionally, also implement CryptoRng for MyRngCore
-//!
-//! // Final RNG.
-//! let mut rng = BlockRng::<MyRngCore>::seed_from_u64(0);
-//! println!("First value: {}", rng.next_u32());
-//! ```
-//!
-//! [`BlockRngCore`]: crate::block::BlockRngCore
-//! [`fill_bytes`]: RngCore::fill_bytes
-
-use crate::impls::{fill_via_u32_chunks, fill_via_u64_chunks};
-use crate::{CryptoRng, Error, RngCore, SeedableRng};
-use core::convert::AsRef;
-use core::fmt;
-#[cfg(feature = "serde1")]
-use serde::{Deserialize, Serialize};
-
-/// A trait for RNGs which do not generate random numbers individually, but in
-/// blocks (typically `[u32; N]`). This technique is commonly used by
-/// cryptographic RNGs to improve performance.
-///
-/// See the [module][crate::block] documentation for details.
-pub trait BlockRngCore {
-    /// Results element type, e.g. `u32`.
-    type Item;
-
-    /// Results type. This is the 'block' an RNG implementing `BlockRngCore`
-    /// generates, which will usually be an array like `[u32; 16]`.
-    type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default;
-
-    /// Generate a new block of results.
-    fn generate(&mut self, results: &mut Self::Results);
-}
-
-/// A wrapper type implementing [`RngCore`] for some type implementing
-/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement
-/// a full RNG from just a `generate` function.
-///
-/// The `core` field may be accessed directly but the results buffer may not.
-/// PRNG implementations can simply use a type alias
-/// (`pub type MyRng = BlockRng<MyRngCore>;`) but might prefer to use a
-/// wrapper type (`pub struct MyRng(BlockRng<MyRngCore>);`); the latter must
-/// re-implement `RngCore` but hides the implementation details and allows
-/// extra functionality to be defined on the RNG
-/// (e.g. `impl MyRng { fn set_stream(...){...} }`).
-///
-/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods
-/// reading values from the results buffer, as well as
-/// calling [`BlockRngCore::generate`] directly on the output array when
-/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods
-/// also handle the bookkeeping of when to generate a new batch of values.
-///
-/// No whole generated `u32` values are thrown away and all values are consumed
-/// in-order. [`next_u32`] simply takes the next available `u32` value.
-/// [`next_u64`] is implemented by combining two `u32` values, least
-/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole
-/// number of `u32` values, converting each `u32` to a byte slice in
-/// little-endian order. If the requested byte length is not a multiple of 4,
-/// some bytes will be discarded.
-///
-/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is
-/// no direct support for other buffer types.
-///
-/// For easy initialization `BlockRng` also implements [`SeedableRng`].
-///
-/// [`next_u32`]: RngCore::next_u32
-/// [`next_u64`]: RngCore::next_u64
-/// [`fill_bytes`]: RngCore::fill_bytes
-/// [`try_fill_bytes`]: RngCore::try_fill_bytes
-#[derive(Clone)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-#[cfg_attr(
-    feature = "serde1",
-    serde(
-        bound = "for<'x> R: Serialize + Deserialize<'x> + Sized, for<'x> R::Results: Serialize + Deserialize<'x>"
-    )
-)]
-pub struct BlockRng<R: BlockRngCore + ?Sized> {
-    results: R::Results,
-    index: usize,
-    /// The *core* part of the RNG, implementing the `generate` function.
-    pub core: R,
-}
-
-// Custom Debug implementation that does not expose the contents of `results`.
-impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng<R> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        fmt.debug_struct("BlockRng")
-            .field("core", &self.core)
-            .field("result_len", &self.results.as_ref().len())
-            .field("index", &self.index)
-            .finish()
-    }
-}
-
-impl<R: BlockRngCore> BlockRng<R> {
-    /// Create a new `BlockRng` from an existing RNG implementing
-    /// `BlockRngCore`. Results will be generated on first use.
-    #[inline]
-    pub fn new(core: R) -> BlockRng<R> {
-        let results_empty = R::Results::default();
-        BlockRng {
-            core,
-            index: results_empty.as_ref().len(),
-            results: results_empty,
-        }
-    }
-
-    /// Get the index into the result buffer.
-    ///
-    /// If this is equal to or larger than the size of the result buffer then
-    /// the buffer is "empty" and `generate()` must be called to produce new
-    /// results.
-    #[inline(always)]
-    pub fn index(&self) -> usize {
-        self.index
-    }
-
-    /// Reset the number of available results.
-    /// This will force a new set of results to be generated on next use.
-    #[inline]
-    pub fn reset(&mut self) {
-        self.index = self.results.as_ref().len();
-    }
-
-    /// Generate a new set of results immediately, setting the index to the
-    /// given value.
-    #[inline]
-    pub fn generate_and_set(&mut self, index: usize) {
-        assert!(index < self.results.as_ref().len());
-        self.core.generate(&mut self.results);
-        self.index = index;
-    }
-}
-
-impl<R: BlockRngCore<Item = u32>> RngCore for BlockRng<R>
-where
-    <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>,
-{
-    #[inline]
-    fn next_u32(&mut self) -> u32 {
-        if self.index >= self.results.as_ref().len() {
-            self.generate_and_set(0);
-        }
-
-        let value = self.results.as_ref()[self.index];
-        self.index += 1;
-        value
-    }
-
-    #[inline]
-    fn next_u64(&mut self) -> u64 {
-        let read_u64 = |results: &[u32], index| {
-            let data = &results[index..=index + 1];
-            u64::from(data[1]) << 32 | u64::from(data[0])
-        };
-
-        let len = self.results.as_ref().len();
-
-        let index = self.index;
-        if index < len - 1 {
-            self.index += 2;
-            // Read an u64 from the current index
-            read_u64(self.results.as_ref(), index)
-        } else if index >= len {
-            self.generate_and_set(2);
-            read_u64(self.results.as_ref(), 0)
-        } else {
-            let x = u64::from(self.results.as_ref()[len - 1]);
-            self.generate_and_set(1);
-            let y = u64::from(self.results.as_ref()[0]);
-            (y << 32) | x
-        }
-    }
-
-    #[inline]
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        let mut read_len = 0;
-        while read_len < dest.len() {
-            if self.index >= self.results.as_ref().len() {
-                self.generate_and_set(0);
-            }
-            let (consumed_u32, filled_u8) =
-                fill_via_u32_chunks(&self.results.as_ref()[self.index..], &mut dest[read_len..]);
-
-            self.index += consumed_u32;
-            read_len += filled_u8;
-        }
-    }
-
-    #[inline(always)]
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-        self.fill_bytes(dest);
-        Ok(())
-    }
-}
-
-impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
-    type Seed = R::Seed;
-
-    #[inline(always)]
-    fn from_seed(seed: Self::Seed) -> Self {
-        Self::new(R::from_seed(seed))
-    }
-
-    #[inline(always)]
-    fn seed_from_u64(seed: u64) -> Self {
-        Self::new(R::seed_from_u64(seed))
-    }
-
-    #[inline(always)]
-    fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
-        Ok(Self::new(R::from_rng(rng)?))
-    }
-}
-
-/// A wrapper type implementing [`RngCore`] for some type implementing
-/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement
-/// a full RNG from just a `generate` function.
-///
-/// This is similar to [`BlockRng`], but specialized for algorithms that operate
-/// on `u64` values.
-///
-/// No whole generated `u64` values are thrown away and all values are consumed
-/// in-order. [`next_u64`] simply takes the next available `u64` value.
-/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving
-/// the other half in the buffer. If the next function called is [`next_u32`]
-/// then the other half is then consumed, however both [`next_u64`] and
-/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called.
-///
-/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64`
-/// values. If the requested length is not a multiple of 8, some bytes will be
-/// discarded.
-///
-/// [`next_u32`]: RngCore::next_u32
-/// [`next_u64`]: RngCore::next_u64
-/// [`fill_bytes`]: RngCore::fill_bytes
-/// [`try_fill_bytes`]: RngCore::try_fill_bytes
-#[derive(Clone)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct BlockRng64<R: BlockRngCore + ?Sized> {
-    results: R::Results,
-    index: usize,
-    half_used: bool, // true if only half of the previous result is used
-    /// The *core* part of the RNG, implementing the `generate` function.
-    pub core: R,
-}
-
-// Custom Debug implementation that does not expose the contents of `results`.
-impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng64<R> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        fmt.debug_struct("BlockRng64")
-            .field("core", &self.core)
-            .field("result_len", &self.results.as_ref().len())
-            .field("index", &self.index)
-            .field("half_used", &self.half_used)
-            .finish()
-    }
-}
-
-impl<R: BlockRngCore> BlockRng64<R> {
-    /// Create a new `BlockRng` from an existing RNG implementing
-    /// `BlockRngCore`. Results will be generated on first use.
-    #[inline]
-    pub fn new(core: R) -> BlockRng64<R> {
-        let results_empty = R::Results::default();
-        BlockRng64 {
-            core,
-            index: results_empty.as_ref().len(),
-            half_used: false,
-            results: results_empty,
-        }
-    }
-
-    /// Get the index into the result buffer.
-    ///
-    /// If this is equal to or larger than the size of the result buffer then
-    /// the buffer is "empty" and `generate()` must be called to produce new
-    /// results.
-    #[inline(always)]
-    pub fn index(&self) -> usize {
-        self.index
-    }
-
-    /// Reset the number of available results.
-    /// This will force a new set of results to be generated on next use.
-    #[inline]
-    pub fn reset(&mut self) {
-        self.index = self.results.as_ref().len();
-        self.half_used = false;
-    }
-
-    /// Generate a new set of results immediately, setting the index to the
-    /// given value.
-    #[inline]
-    pub fn generate_and_set(&mut self, index: usize) {
-        assert!(index < self.results.as_ref().len());
-        self.core.generate(&mut self.results);
-        self.index = index;
-        self.half_used = false;
-    }
-}
-
-impl<R: BlockRngCore<Item = u64>> RngCore for BlockRng64<R>
-where
-    <R as BlockRngCore>::Results: AsRef<[u64]> + AsMut<[u64]>,
-{
-    #[inline]
-    fn next_u32(&mut self) -> u32 {
-        let mut index = self.index - self.half_used as usize;
-        if index >= self.results.as_ref().len() {
-            self.core.generate(&mut self.results);
-            self.index = 0;
-            index = 0;
-            // `self.half_used` is by definition `false`
-            self.half_used = false;
-        }
-
-        let shift = 32 * (self.half_used as usize);
-
-        self.half_used = !self.half_used;
-        self.index += self.half_used as usize;
-
-        (self.results.as_ref()[index] >> shift) as u32
-    }
-
-    #[inline]
-    fn next_u64(&mut self) -> u64 {
-        if self.index >= self.results.as_ref().len() {
-            self.core.generate(&mut self.results);
-            self.index = 0;
-        }
-
-        let value = self.results.as_ref()[self.index];
-        self.index += 1;
-        self.half_used = false;
-        value
-    }
-
-    #[inline]
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        let mut read_len = 0;
-        self.half_used = false;
-        while read_len < dest.len() {
-            if self.index as usize >= self.results.as_ref().len() {
-                self.core.generate(&mut self.results);
-                self.index = 0;
-            }
-
-            let (consumed_u64, filled_u8) = fill_via_u64_chunks(
-                &self.results.as_ref()[self.index as usize..],
-                &mut dest[read_len..],
-            );
-
-            self.index += consumed_u64;
-            read_len += filled_u8;
-        }
-    }
-
-    #[inline(always)]
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-        self.fill_bytes(dest);
-        Ok(())
-    }
-}
-
-impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
-    type Seed = R::Seed;
-
-    #[inline(always)]
-    fn from_seed(seed: Self::Seed) -> Self {
-        Self::new(R::from_seed(seed))
-    }
-
-    #[inline(always)]
-    fn seed_from_u64(seed: u64) -> Self {
-        Self::new(R::seed_from_u64(seed))
-    }
-
-    #[inline(always)]
-    fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
-        Ok(Self::new(R::from_rng(rng)?))
-    }
-}
-
-impl<R: BlockRngCore + CryptoRng> CryptoRng for BlockRng<R> {}
-
-#[cfg(test)]
-mod test {
-    use crate::{SeedableRng, RngCore};
-    use crate::block::{BlockRng, BlockRng64, BlockRngCore};
-
-    #[derive(Debug, Clone)]
-    struct DummyRng {
-        counter: u32,
-    }
-
-    impl BlockRngCore for DummyRng {
-        type Item = u32;
-
-        type Results = [u32; 16];
-
-        fn generate(&mut self, results: &mut Self::Results) {
-            for r in results {
-                *r = self.counter;
-                self.counter = self.counter.wrapping_add(3511615421);
-            }
-        }
-    }
-
-    impl SeedableRng for DummyRng {
-        type Seed = [u8; 4];
-
-        fn from_seed(seed: Self::Seed) -> Self {
-            DummyRng { counter: u32::from_le_bytes(seed) }
-        }
-    }
-
-    #[test]
-    fn blockrng_next_u32_vs_next_u64() {
-        let mut rng1 = BlockRng::<DummyRng>::from_seed([1, 2, 3, 4]);
-        let mut rng2 = rng1.clone();
-        let mut rng3 = rng1.clone();
-
-        let mut a = [0; 16];
-        (&mut a[..4]).copy_from_slice(&rng1.next_u32().to_le_bytes());
-        (&mut a[4..12]).copy_from_slice(&rng1.next_u64().to_le_bytes());
-        (&mut a[12..]).copy_from_slice(&rng1.next_u32().to_le_bytes());
-
-        let mut b = [0; 16];
-        (&mut b[..4]).copy_from_slice(&rng2.next_u32().to_le_bytes());
-        (&mut b[4..8]).copy_from_slice(&rng2.next_u32().to_le_bytes());
-        (&mut b[8..]).copy_from_slice(&rng2.next_u64().to_le_bytes());
-        assert_eq!(a, b);
-
-        let mut c = [0; 16];
-        (&mut c[..8]).copy_from_slice(&rng3.next_u64().to_le_bytes());
-        (&mut c[8..12]).copy_from_slice(&rng3.next_u32().to_le_bytes());
-        (&mut c[12..]).copy_from_slice(&rng3.next_u32().to_le_bytes());
-        assert_eq!(a, c);
-    }
-
-    #[derive(Debug, Clone)]
-    struct DummyRng64 {
-        counter: u64,
-    }
-
-    impl BlockRngCore for DummyRng64 {
-        type Item = u64;
-
-        type Results = [u64; 8];
-
-        fn generate(&mut self, results: &mut Self::Results) {
-            for r in results {
-                *r = self.counter;
-                self.counter = self.counter.wrapping_add(2781463553396133981);
-            }
-        }
-    }
-
-    impl SeedableRng for DummyRng64 {
-        type Seed = [u8; 8];
-
-        fn from_seed(seed: Self::Seed) -> Self {
-            DummyRng64 { counter: u64::from_le_bytes(seed) }
-        }
-    }
-
-    #[test]
-    fn blockrng64_next_u32_vs_next_u64() {
-        let mut rng1 = BlockRng64::<DummyRng64>::from_seed([1, 2, 3, 4, 5, 6, 7, 8]);
-        let mut rng2 = rng1.clone();
-        let mut rng3 = rng1.clone();
-
-        let mut a = [0; 16];
-        (&mut a[..4]).copy_from_slice(&rng1.next_u32().to_le_bytes());
-        (&mut a[4..12]).copy_from_slice(&rng1.next_u64().to_le_bytes());
-        (&mut a[12..]).copy_from_slice(&rng1.next_u32().to_le_bytes());
-
-        let mut b = [0; 16];
-        (&mut b[..4]).copy_from_slice(&rng2.next_u32().to_le_bytes());
-        (&mut b[4..8]).copy_from_slice(&rng2.next_u32().to_le_bytes());
-        (&mut b[8..]).copy_from_slice(&rng2.next_u64().to_le_bytes());
-        assert_ne!(a, b);
-        assert_eq!(&a[..4], &b[..4]);
-        assert_eq!(&a[4..12], &b[8..]);
-
-        let mut c = [0; 16];
-        (&mut c[..8]).copy_from_slice(&rng3.next_u64().to_le_bytes());
-        (&mut c[8..12]).copy_from_slice(&rng3.next_u32().to_le_bytes());
-        (&mut c[12..]).copy_from_slice(&rng3.next_u32().to_le_bytes());
-        assert_eq!(b, c);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/error.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/error.rs
deleted file mode 100644
index 411896f..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/error.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Error types
-
-use core::fmt;
-use core::num::NonZeroU32;
-
-#[cfg(feature = "std")] use std::boxed::Box;
-
-/// Error type of random number generators
-///
-/// In order to be compatible with `std` and `no_std`, this type has two
-/// possible implementations: with `std` a boxed `Error` trait object is stored,
-/// while with `no_std` we merely store an error code.
-pub struct Error {
-    #[cfg(feature = "std")]
-    inner: Box<dyn std::error::Error + Send + Sync + 'static>,
-    #[cfg(not(feature = "std"))]
-    code: NonZeroU32,
-}
-
-impl Error {
-    /// Codes at or above this point can be used by users to define their own
-    /// custom errors.
-    ///
-    /// This has a fixed value of `(1 << 31) + (1 << 30) = 0xC000_0000`,
-    /// therefore the number of values available for custom codes is `1 << 30`.
-    ///
-    /// This is identical to [`getrandom::Error::CUSTOM_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.CUSTOM_START).
-    pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);
-    /// Codes below this point represent OS Errors (i.e. positive i32 values).
-    /// Codes at or above this point, but below [`Error::CUSTOM_START`] are
-    /// reserved for use by the `rand` and `getrandom` crates.
-    ///
-    /// This is identical to [`getrandom::Error::INTERNAL_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.INTERNAL_START).
-    pub const INTERNAL_START: u32 = 1 << 31;
-
-    /// Construct from any type supporting `std::error::Error`
-    ///
-    /// Available only when configured with `std`.
-    ///
-    /// See also `From<NonZeroU32>`, which is available with and without `std`.
-    #[cfg(feature = "std")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
-    #[inline]
-    pub fn new<E>(err: E) -> Self
-    where
-        E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
-    {
-        Error { inner: err.into() }
-    }
-
-    /// Reference the inner error (`std` only)
-    ///
-    /// When configured with `std`, this is a trivial operation and never
-    /// panics. Without `std`, this method is simply unavailable.
-    #[cfg(feature = "std")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
-    #[inline]
-    pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
-        &*self.inner
-    }
-
-    /// Unwrap the inner error (`std` only)
-    ///
-    /// When configured with `std`, this is a trivial operation and never
-    /// panics. Without `std`, this method is simply unavailable.
-    #[cfg(feature = "std")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
-    #[inline]
-    pub fn take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static> {
-        self.inner
-    }
-
-    /// Extract the raw OS error code (if this error came from the OS)
-    ///
-    /// This method is identical to `std::io::Error::raw_os_error()`, except
-    /// that it works in `no_std` contexts. If this method returns `None`, the
-    /// error value can still be formatted via the `Display` implementation.
-    #[inline]
-    pub fn raw_os_error(&self) -> Option<i32> {
-        #[cfg(feature = "std")]
-        {
-            if let Some(e) = self.inner.downcast_ref::<std::io::Error>() {
-                return e.raw_os_error();
-            }
-        }
-        match self.code() {
-            Some(code) if u32::from(code) < Self::INTERNAL_START => Some(u32::from(code) as i32),
-            _ => None,
-        }
-    }
-
-    /// Retrieve the error code, if any.
-    ///
-    /// If this `Error` was constructed via `From<NonZeroU32>`, then this method
-    /// will return this `NonZeroU32` code (for `no_std` this is always the
-    /// case). Otherwise, this method will return `None`.
-    #[inline]
-    pub fn code(&self) -> Option<NonZeroU32> {
-        #[cfg(feature = "std")]
-        {
-            self.inner.downcast_ref::<ErrorCode>().map(|c| c.0)
-        }
-        #[cfg(not(feature = "std"))]
-        {
-            Some(self.code)
-        }
-    }
-}
-
-impl fmt::Debug for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        #[cfg(feature = "std")]
-        {
-            write!(f, "Error {{ inner: {:?} }}", self.inner)
-        }
-        #[cfg(all(feature = "getrandom", not(feature = "std")))]
-        {
-            getrandom::Error::from(self.code).fmt(f)
-        }
-        #[cfg(not(feature = "getrandom"))]
-        {
-            write!(f, "Error {{ code: {} }}", self.code)
-        }
-    }
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        #[cfg(feature = "std")]
-        {
-            write!(f, "{}", self.inner)
-        }
-        #[cfg(all(feature = "getrandom", not(feature = "std")))]
-        {
-            getrandom::Error::from(self.code).fmt(f)
-        }
-        #[cfg(not(feature = "getrandom"))]
-        {
-            write!(f, "error code {}", self.code)
-        }
-    }
-}
-
-impl From<NonZeroU32> for Error {
-    #[inline]
-    fn from(code: NonZeroU32) -> Self {
-        #[cfg(feature = "std")]
-        {
-            Error {
-                inner: Box::new(ErrorCode(code)),
-            }
-        }
-        #[cfg(not(feature = "std"))]
-        {
-            Error { code }
-        }
-    }
-}
-
-#[cfg(feature = "getrandom")]
-impl From<getrandom::Error> for Error {
-    #[inline]
-    fn from(error: getrandom::Error) -> Self {
-        #[cfg(feature = "std")]
-        {
-            Error {
-                inner: Box::new(error),
-            }
-        }
-        #[cfg(not(feature = "std"))]
-        {
-            Error { code: error.code() }
-        }
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for Error {
-    #[inline]
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        self.inner.source()
-    }
-}
-
-#[cfg(feature = "std")]
-impl From<Error> for std::io::Error {
-    #[inline]
-    fn from(error: Error) -> Self {
-        if let Some(code) = error.raw_os_error() {
-            std::io::Error::from_raw_os_error(code)
-        } else {
-            std::io::Error::new(std::io::ErrorKind::Other, error)
-        }
-    }
-}
-
-#[cfg(feature = "std")]
-#[derive(Debug, Copy, Clone)]
-struct ErrorCode(NonZeroU32);
-
-#[cfg(feature = "std")]
-impl fmt::Display for ErrorCode {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "error code {}", self.0)
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for ErrorCode {}
-
-#[cfg(test)]
-mod test {
-    #[cfg(feature = "getrandom")]
-    #[test]
-    fn test_error_codes() {
-        // Make sure the values are the same as in `getrandom`.
-        assert_eq!(super::Error::CUSTOM_START, getrandom::Error::CUSTOM_START);
-        assert_eq!(super::Error::INTERNAL_START, getrandom::Error::INTERNAL_START);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/impls.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/impls.rs
deleted file mode 100644
index 4b7688c5c..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/impls.rs
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Helper functions for implementing `RngCore` functions.
-//!
-//! For cross-platform reproducibility, these functions all use Little Endian:
-//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
-//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
-//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
-//!
-//! Byte-swapping (like the std `to_le` functions) is only needed to convert
-//! to/from byte sequences, and since its purpose is reproducibility,
-//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
-
-use crate::RngCore;
-use core::cmp::min;
-
-/// Implement `next_u64` via `next_u32`, little-endian order.
-pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
-    // Use LE; we explicitly generate one value before the next.
-    let x = u64::from(rng.next_u32());
-    let y = u64::from(rng.next_u32());
-    (y << 32) | x
-}
-
-/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
-///
-/// The fastest way to fill a slice is usually to work as long as possible with
-/// integers. That is why this method mostly uses `next_u64`, and only when
-/// there are 4 or less bytes remaining at the end of the slice it uses
-/// `next_u32` once.
-pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
-    let mut left = dest;
-    while left.len() >= 8 {
-        let (l, r) = { left }.split_at_mut(8);
-        left = r;
-        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
-        l.copy_from_slice(&chunk);
-    }
-    let n = left.len();
-    if n > 4 {
-        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
-        left.copy_from_slice(&chunk[..n]);
-    } else if n > 0 {
-        let chunk: [u8; 4] = rng.next_u32().to_le_bytes();
-        left.copy_from_slice(&chunk[..n]);
-    }
-}
-
-trait Observable: Copy {
-    type Bytes: AsRef<[u8]>;
-    fn to_le_bytes(self) -> Self::Bytes;
-
-    // Contract: observing self is memory-safe (implies no uninitialised padding)
-    fn as_byte_slice(x: &[Self]) -> &[u8];
-}
-impl Observable for u32 {
-    type Bytes = [u8; 4];
-    fn to_le_bytes(self) -> Self::Bytes {
-        self.to_le_bytes()
-    }
-    fn as_byte_slice(x: &[Self]) -> &[u8] {
-        let ptr = x.as_ptr() as *const u8;
-        let len = x.len() * core::mem::size_of::<Self>();
-        unsafe { core::slice::from_raw_parts(ptr, len) }
-    }
-}
-impl Observable for u64 {
-    type Bytes = [u8; 8];
-    fn to_le_bytes(self) -> Self::Bytes {
-        self.to_le_bytes()
-    }
-    fn as_byte_slice(x: &[Self]) -> &[u8] {
-        let ptr = x.as_ptr() as *const u8;
-        let len = x.len() * core::mem::size_of::<Self>();
-        unsafe { core::slice::from_raw_parts(ptr, len) }
-    }
-}
-
-fn fill_via_chunks<T: Observable>(src: &[T], dest: &mut [u8]) -> (usize, usize) {
-    let size = core::mem::size_of::<T>();
-    let byte_len = min(src.len() * size, dest.len());
-    let num_chunks = (byte_len + size - 1) / size;
-
-    if cfg!(target_endian = "little") {
-        // On LE we can do a simple copy, which is 25-50% faster:
-        dest[..byte_len].copy_from_slice(&T::as_byte_slice(&src[..num_chunks])[..byte_len]);
-    } else {
-        // This code is valid on all arches, but slower than the above:
-        let mut i = 0;
-        let mut iter = dest[..byte_len].chunks_exact_mut(size);
-        for chunk in &mut iter {
-            chunk.copy_from_slice(src[i].to_le_bytes().as_ref());
-            i += 1;
-        }
-        let chunk = iter.into_remainder();
-        if !chunk.is_empty() {
-            chunk.copy_from_slice(&src[i].to_le_bytes().as_ref()[..chunk.len()]);
-        }
-    }
-
-    (num_chunks, byte_len)
-}
-
-/// Implement `fill_bytes` by reading chunks from the output buffer of a block
-/// based RNG.
-///
-/// The return values are `(consumed_u32, filled_u8)`.
-///
-/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
-/// the length of `dest`.
-/// `consumed_u32` is the number of words consumed from `src`, which is the same
-/// as `filled_u8 / 4` rounded up.
-///
-/// # Example
-/// (from `IsaacRng`)
-///
-/// ```ignore
-/// fn fill_bytes(&mut self, dest: &mut [u8]) {
-///     let mut read_len = 0;
-///     while read_len < dest.len() {
-///         if self.index >= self.rsl.len() {
-///             self.isaac();
-///         }
-///
-///         let (consumed_u32, filled_u8) =
-///             impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
-///                                        &mut dest[read_len..]);
-///
-///         self.index += consumed_u32;
-///         read_len += filled_u8;
-///     }
-/// }
-/// ```
-pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
-    fill_via_chunks(src, dest)
-}
-
-/// Implement `fill_bytes` by reading chunks from the output buffer of a block
-/// based RNG.
-///
-/// The return values are `(consumed_u64, filled_u8)`.
-/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
-/// the length of `dest`.
-/// `consumed_u64` is the number of words consumed from `src`, which is the same
-/// as `filled_u8 / 8` rounded up.
-///
-/// See `fill_via_u32_chunks` for an example.
-pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
-    fill_via_chunks(src, dest)
-}
-
-/// Implement `next_u32` via `fill_bytes`, little-endian order.
-pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
-    let mut buf = [0; 4];
-    rng.fill_bytes(&mut buf);
-    u32::from_le_bytes(buf)
-}
-
-/// Implement `next_u64` via `fill_bytes`, little-endian order.
-pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
-    let mut buf = [0; 8];
-    rng.fill_bytes(&mut buf);
-    u64::from_le_bytes(buf)
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_fill_via_u32_chunks() {
-        let src = [1, 2, 3];
-        let mut dst = [0u8; 11];
-        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 11));
-        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]);
-
-        let mut dst = [0u8; 13];
-        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 12));
-        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]);
-
-        let mut dst = [0u8; 5];
-        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (2, 5));
-        assert_eq!(dst, [1, 0, 0, 0, 2]);
-    }
-
-    #[test]
-    fn test_fill_via_u64_chunks() {
-        let src = [1, 2];
-        let mut dst = [0u8; 11];
-        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 11));
-        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);
-
-        let mut dst = [0u8; 17];
-        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 16));
-        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]);
-
-        let mut dst = [0u8; 5];
-        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (1, 5));
-        assert_eq!(dst, [1, 0, 0, 0, 0]);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/le.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/le.rs
deleted file mode 100644
index ed42e57f..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/le.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Little-Endian utilities
-//!
-//! Little-Endian order has been chosen for internal usage; this makes some
-//! useful functions available.
-
-use core::convert::TryInto;
-
-/// Reads unsigned 32 bit integers from `src` into `dst`.
-#[inline]
-pub fn read_u32_into(src: &[u8], dst: &mut [u32]) {
-    assert!(src.len() >= 4 * dst.len());
-    for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(4)) {
-        *out = u32::from_le_bytes(chunk.try_into().unwrap());
-    }
-}
-
-/// Reads unsigned 64 bit integers from `src` into `dst`.
-#[inline]
-pub fn read_u64_into(src: &[u8], dst: &mut [u64]) {
-    assert!(src.len() >= 8 * dst.len());
-    for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(8)) {
-        *out = u64::from_le_bytes(chunk.try_into().unwrap());
-    }
-}
-
-#[test]
-fn test_read() {
-    let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
-
-    let mut buf = [0u32; 4];
-    read_u32_into(&bytes, &mut buf);
-    assert_eq!(buf[0], 0x04030201);
-    assert_eq!(buf[3], 0x100F0E0D);
-
-    let mut buf = [0u32; 3];
-    read_u32_into(&bytes[1..13], &mut buf); // unaligned
-    assert_eq!(buf[0], 0x05040302);
-    assert_eq!(buf[2], 0x0D0C0B0A);
-
-    let mut buf = [0u64; 2];
-    read_u64_into(&bytes, &mut buf);
-    assert_eq!(buf[0], 0x0807060504030201);
-    assert_eq!(buf[1], 0x100F0E0D0C0B0A09);
-
-    let mut buf = [0u64; 1];
-    read_u64_into(&bytes[7..15], &mut buf); // unaligned
-    assert_eq!(buf[0], 0x0F0E0D0C0B0A0908);
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/lib.rs
deleted file mode 100644
index 1234a566..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/lib.rs
+++ /dev/null
@@ -1,531 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2017-2018 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Random number generation traits
-//!
-//! This crate is mainly of interest to crates publishing implementations of
-//! [`RngCore`]. Other users are encouraged to use the [`rand`] crate instead
-//! which re-exports the main traits and error types.
-//!
-//! [`RngCore`] is the core trait implemented by algorithmic pseudo-random number
-//! generators and external random-number sources.
-//!
-//! [`SeedableRng`] is an extension trait for construction from fixed seeds and
-//! other random number generators.
-//!
-//! [`Error`] is provided for error-handling. It is safe to use in `no_std`
-//! environments.
-//!
-//! The [`impls`] and [`le`] sub-modules include a few small functions to assist
-//! implementation of [`RngCore`].
-//!
-//! [`rand`]: https://docs.rs/rand
-
-#![doc(
-    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
-    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
-    html_root_url = "https://rust-random.github.io/rand/"
-)]
-#![deny(missing_docs)]
-#![deny(missing_debug_implementations)]
-#![doc(test(attr(allow(unused_variables), deny(warnings))))]
-#![cfg_attr(doc_cfg, feature(doc_cfg))]
-#![no_std]
-
-use core::convert::AsMut;
-use core::default::Default;
-
-#[cfg(feature = "std")] extern crate std;
-#[cfg(feature = "alloc")] extern crate alloc;
-#[cfg(feature = "alloc")] use alloc::boxed::Box;
-
-pub use error::Error;
-#[cfg(feature = "getrandom")] pub use os::OsRng;
-
-
-pub mod block;
-mod error;
-pub mod impls;
-pub mod le;
-#[cfg(feature = "getrandom")] mod os;
-
-
-/// The core of a random number generator.
-///
-/// This trait encapsulates the low-level functionality common to all
-/// generators, and is the "back end", to be implemented by generators.
-/// End users should normally use the `Rng` trait from the [`rand`] crate,
-/// which is automatically implemented for every type implementing `RngCore`.
-///
-/// Three different methods for generating random data are provided since the
-/// optimal implementation of each is dependent on the type of generator. There
-/// is no required relationship between the output of each; e.g. many
-/// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64`
-/// values and drop any remaining unused bytes. The same can happen with the
-/// [`next_u32`] and [`next_u64`] methods, implementations may discard some
-/// random bits for efficiency.
-///
-/// The [`try_fill_bytes`] method is a variant of [`fill_bytes`] allowing error
-/// handling; it is not deemed sufficiently useful to add equivalents for
-/// [`next_u32`] or [`next_u64`] since the latter methods are almost always used
-/// with algorithmic generators (PRNGs), which are normally infallible.
-///
-/// Implementers should produce bits uniformly. Pathological RNGs (e.g. always
-/// returning the same value, or never setting certain bits) can break rejection
-/// sampling used by random distributions, and also break other RNGs when
-/// seeding them via [`SeedableRng::from_rng`].
-///
-/// Algorithmic generators implementing [`SeedableRng`] should normally have
-/// *portable, reproducible* output, i.e. fix Endianness when converting values
-/// to avoid platform differences, and avoid making any changes which affect
-/// output (except by communicating that the release has breaking changes).
-///
-/// Typically an RNG will implement only one of the methods available
-/// in this trait directly, then use the helper functions from the
-/// [`impls`] module to implement the other methods.
-///
-/// It is recommended that implementations also implement:
-///
-/// - `Debug` with a custom implementation which *does not* print any internal
-///   state (at least, [`CryptoRng`]s should not risk leaking state through
-///   `Debug`).
-/// - `Serialize` and `Deserialize` (from Serde), preferably making Serde
-///   support optional at the crate level in PRNG libs.
-/// - `Clone`, if possible.
-/// - *never* implement `Copy` (accidental copies may cause repeated values).
-/// - *do not* implement `Default` for pseudorandom generators, but instead
-///   implement [`SeedableRng`], to guide users towards proper seeding.
-///   External / hardware RNGs can choose to implement `Default`.
-/// - `Eq` and `PartialEq` could be implemented, but are probably not useful.
-///
-/// # Example
-///
-/// A simple example, obviously not generating very *random* output:
-///
-/// ```
-/// #![allow(dead_code)]
-/// use rand_core::{RngCore, Error, impls};
-///
-/// struct CountingRng(u64);
-///
-/// impl RngCore for CountingRng {
-///     fn next_u32(&mut self) -> u32 {
-///         self.next_u64() as u32
-///     }
-///
-///     fn next_u64(&mut self) -> u64 {
-///         self.0 += 1;
-///         self.0
-///     }
-///
-///     fn fill_bytes(&mut self, dest: &mut [u8]) {
-///         impls::fill_bytes_via_next(self, dest)
-///     }
-///
-///     fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-///         Ok(self.fill_bytes(dest))
-///     }
-/// }
-/// ```
-///
-/// [`rand`]: https://docs.rs/rand
-/// [`try_fill_bytes`]: RngCore::try_fill_bytes
-/// [`fill_bytes`]: RngCore::fill_bytes
-/// [`next_u32`]: RngCore::next_u32
-/// [`next_u64`]: RngCore::next_u64
-pub trait RngCore {
-    /// Return the next random `u32`.
-    ///
-    /// RNGs must implement at least one method from this trait directly. In
-    /// the case this method is not implemented directly, it can be implemented
-    /// using `self.next_u64() as u32` or via [`impls::next_u32_via_fill`].
-    fn next_u32(&mut self) -> u32;
-
-    /// Return the next random `u64`.
-    ///
-    /// RNGs must implement at least one method from this trait directly. In
-    /// the case this method is not implemented directly, it can be implemented
-    /// via [`impls::next_u64_via_u32`] or via [`impls::next_u64_via_fill`].
-    fn next_u64(&mut self) -> u64;
-
-    /// Fill `dest` with random data.
-    ///
-    /// RNGs must implement at least one method from this trait directly. In
-    /// the case this method is not implemented directly, it can be implemented
-    /// via [`impls::fill_bytes_via_next`] or
-    /// via [`RngCore::try_fill_bytes`]; if this generator can
-    /// fail the implementation must choose how best to handle errors here
-    /// (e.g. panic with a descriptive message or log a warning and retry a few
-    /// times).
-    ///
-    /// This method should guarantee that `dest` is entirely filled
-    /// with new data, and may panic if this is impossible
-    /// (e.g. reading past the end of a file that is being used as the
-    /// source of randomness).
-    fn fill_bytes(&mut self, dest: &mut [u8]);
-
-    /// Fill `dest` entirely with random data.
-    ///
-    /// This is the only method which allows an RNG to report errors while
-    /// generating random data thus making this the primary method implemented
-    /// by external (true) RNGs (e.g. `OsRng`) which can fail. It may be used
-    /// directly to generate keys and to seed (infallible) PRNGs.
-    ///
-    /// Other than error handling, this method is identical to [`RngCore::fill_bytes`];
-    /// thus this may be implemented using `Ok(self.fill_bytes(dest))` or
-    /// `fill_bytes` may be implemented with
-    /// `self.try_fill_bytes(dest).unwrap()` or more specific error handling.
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>;
-}
-
-/// A marker trait used to indicate that an [`RngCore`] or [`BlockRngCore`]
-/// implementation is supposed to be cryptographically secure.
-///
-/// *Cryptographically secure generators*, also known as *CSPRNGs*, should
-/// satisfy an additional properties over other generators: given the first
-/// *k* bits of an algorithm's output
-/// sequence, it should not be possible using polynomial-time algorithms to
-/// predict the next bit with probability significantly greater than 50%.
-///
-/// Some generators may satisfy an additional property, however this is not
-/// required by this trait: if the CSPRNG's state is revealed, it should not be
-/// computationally-feasible to reconstruct output prior to this. Some other
-/// generators allow backwards-computation and are considered *reversible*.
-///
-/// Note that this trait is provided for guidance only and cannot guarantee
-/// suitability for cryptographic applications. In general it should only be
-/// implemented for well-reviewed code implementing well-regarded algorithms.
-///
-/// Note also that use of a `CryptoRng` does not protect against other
-/// weaknesses such as seeding from a weak entropy source or leaking state.
-///
-/// [`BlockRngCore`]: block::BlockRngCore
-pub trait CryptoRng {}
-
-/// An extension trait that is automatically implemented for any type
-/// implementing [`RngCore`] and [`CryptoRng`].
-///
-/// It may be used as a trait object, and supports upcasting to [`RngCore`] via
-/// the [`CryptoRngCore::as_rngcore`] method.
-///
-/// # Example
-///
-/// ```
-/// use rand_core::CryptoRngCore;
-///
-/// #[allow(unused)]
-/// fn make_token(rng: &mut dyn CryptoRngCore) -> [u8; 32] {
-///     let mut buf = [0u8; 32];
-///     rng.fill_bytes(&mut buf);
-///     buf
-/// }
-/// ```
-pub trait CryptoRngCore: CryptoRng + RngCore {
-    /// Upcast to an [`RngCore`] trait object.
-    fn as_rngcore(&mut self) -> &mut dyn RngCore;
-}
-
-impl<T: CryptoRng + RngCore> CryptoRngCore for T {
-    fn as_rngcore(&mut self) -> &mut dyn RngCore {
-        self
-    }
-}
-
-/// A random number generator that can be explicitly seeded.
-///
-/// This trait encapsulates the low-level functionality common to all
-/// pseudo-random number generators (PRNGs, or algorithmic generators).
-///
-/// [`rand`]: https://docs.rs/rand
-pub trait SeedableRng: Sized {
-    /// Seed type, which is restricted to types mutably-dereferenceable as `u8`
-    /// arrays (we recommend `[u8; N]` for some `N`).
-    ///
-    /// It is recommended to seed PRNGs with a seed of at least circa 100 bits,
-    /// which means an array of `[u8; 12]` or greater to avoid picking RNGs with
-    /// partially overlapping periods.
-    ///
-    /// For cryptographic RNG's a seed of 256 bits is recommended, `[u8; 32]`.
-    ///
-    ///
-    /// # Implementing `SeedableRng` for RNGs with large seeds
-    ///
-    /// Note that the required traits `core::default::Default` and
-    /// `core::convert::AsMut<u8>` are not implemented for large arrays
-    /// `[u8; N]` with `N` > 32. To be able to implement the traits required by
-    /// `SeedableRng` for RNGs with such large seeds, the newtype pattern can be
-    /// used:
-    ///
-    /// ```
-    /// use rand_core::SeedableRng;
-    ///
-    /// const N: usize = 64;
-    /// pub struct MyRngSeed(pub [u8; N]);
-    /// pub struct MyRng(MyRngSeed);
-    ///
-    /// impl Default for MyRngSeed {
-    ///     fn default() -> MyRngSeed {
-    ///         MyRngSeed([0; N])
-    ///     }
-    /// }
-    ///
-    /// impl AsMut<[u8]> for MyRngSeed {
-    ///     fn as_mut(&mut self) -> &mut [u8] {
-    ///         &mut self.0
-    ///     }
-    /// }
-    ///
-    /// impl SeedableRng for MyRng {
-    ///     type Seed = MyRngSeed;
-    ///
-    ///     fn from_seed(seed: MyRngSeed) -> MyRng {
-    ///         MyRng(seed)
-    ///     }
-    /// }
-    /// ```
-    type Seed: Sized + Default + AsMut<[u8]>;
-
-    /// Create a new PRNG using the given seed.
-    ///
-    /// PRNG implementations are allowed to assume that bits in the seed are
-    /// well distributed. That means usually that the number of one and zero
-    /// bits are roughly equal, and values like 0, 1 and (size - 1) are unlikely.
-    /// Note that many non-cryptographic PRNGs will show poor quality output
-    /// if this is not adhered to. If you wish to seed from simple numbers, use
-    /// `seed_from_u64` instead.
-    ///
-    /// All PRNG implementations should be reproducible unless otherwise noted:
-    /// given a fixed `seed`, the same sequence of output should be produced
-    /// on all runs, library versions and architectures (e.g. check endianness).
-    /// Any "value-breaking" changes to the generator should require bumping at
-    /// least the minor version and documentation of the change.
-    ///
-    /// It is not required that this function yield the same state as a
-    /// reference implementation of the PRNG given equivalent seed; if necessary
-    /// another constructor replicating behaviour from a reference
-    /// implementation can be added.
-    ///
-    /// PRNG implementations should make sure `from_seed` never panics. In the
-    /// case that some special values (like an all zero seed) are not viable
-    /// seeds it is preferable to map these to alternative constant value(s),
-    /// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad
-    /// seed"). This is assuming only a small number of values must be rejected.
-    fn from_seed(seed: Self::Seed) -> Self;
-
-    /// Create a new PRNG using a `u64` seed.
-    ///
-    /// This is a convenience-wrapper around `from_seed` to allow construction
-    /// of any `SeedableRng` from a simple `u64` value. It is designed such that
-    /// low Hamming Weight numbers like 0 and 1 can be used and should still
-    /// result in good, independent seeds to the PRNG which is returned.
-    ///
-    /// This **is not suitable for cryptography**, as should be clear given that
-    /// the input size is only 64 bits.
-    ///
-    /// Implementations for PRNGs *may* provide their own implementations of
-    /// this function, but the default implementation should be good enough for
-    /// all purposes. *Changing* the implementation of this function should be
-    /// considered a value-breaking change.
-    fn seed_from_u64(mut state: u64) -> Self {
-        // We use PCG32 to generate a u32 sequence, and copy to the seed
-        fn pcg32(state: &mut u64) -> [u8; 4] {
-            const MUL: u64 = 6364136223846793005;
-            const INC: u64 = 11634580027462260723;
-
-            // We advance the state first (to get away from the input value,
-            // in case it has low Hamming Weight).
-            *state = state.wrapping_mul(MUL).wrapping_add(INC);
-            let state = *state;
-
-            // Use PCG output function with to_le to generate x:
-            let xorshifted = (((state >> 18) ^ state) >> 27) as u32;
-            let rot = (state >> 59) as u32;
-            let x = xorshifted.rotate_right(rot);
-            x.to_le_bytes()
-        }
-
-        let mut seed = Self::Seed::default();
-        let mut iter = seed.as_mut().chunks_exact_mut(4);
-        for chunk in &mut iter {
-            chunk.copy_from_slice(&pcg32(&mut state));
-        }
-        let rem = iter.into_remainder();
-        if !rem.is_empty() {
-            rem.copy_from_slice(&pcg32(&mut state)[..rem.len()]);
-        }
-
-        Self::from_seed(seed)
-    }
-
-    /// Create a new PRNG seeded from another `Rng`.
-    ///
-    /// This may be useful when needing to rapidly seed many PRNGs from a master
-    /// PRNG, and to allow forking of PRNGs. It may be considered deterministic.
-    ///
-    /// The master PRNG should be at least as high quality as the child PRNGs.
-    /// When seeding non-cryptographic child PRNGs, we recommend using a
-    /// different algorithm for the master PRNG (ideally a CSPRNG) to avoid
-    /// correlations between the child PRNGs. If this is not possible (e.g.
-    /// forking using small non-crypto PRNGs) ensure that your PRNG has a good
-    /// mixing function on the output or consider use of a hash function with
-    /// `from_seed`.
-    ///
-    /// Note that seeding `XorShiftRng` from another `XorShiftRng` provides an
-    /// extreme example of what can go wrong: the new PRNG will be a clone
-    /// of the parent.
-    ///
-    /// PRNG implementations are allowed to assume that a good RNG is provided
-    /// for seeding, and that it is cryptographically secure when appropriate.
-    /// As of `rand` 0.7 / `rand_core` 0.5, implementations overriding this
-    /// method should ensure the implementation satisfies reproducibility
-    /// (in prior versions this was not required).
-    ///
-    /// [`rand`]: https://docs.rs/rand
-    fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
-        let mut seed = Self::Seed::default();
-        rng.try_fill_bytes(seed.as_mut())?;
-        Ok(Self::from_seed(seed))
-    }
-
-    /// Creates a new instance of the RNG seeded via [`getrandom`].
-    ///
-    /// This method is the recommended way to construct non-deterministic PRNGs
-    /// since it is convenient and secure.
-    ///
-    /// In case the overhead of using [`getrandom`] to seed *many* PRNGs is an
-    /// issue, one may prefer to seed from a local PRNG, e.g.
-    /// `from_rng(thread_rng()).unwrap()`.
-    ///
-    /// # Panics
-    ///
-    /// If [`getrandom`] is unable to provide secure entropy this method will panic.
-    ///
-    /// [`getrandom`]: https://docs.rs/getrandom
-    #[cfg(feature = "getrandom")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
-    fn from_entropy() -> Self {
-        let mut seed = Self::Seed::default();
-        if let Err(err) = getrandom::getrandom(seed.as_mut()) {
-            panic!("from_entropy failed: {}", err);
-        }
-        Self::from_seed(seed)
-    }
-}
-
-// Implement `RngCore` for references to an `RngCore`.
-// Force inlining all functions, so that it is up to the `RngCore`
-// implementation and the optimizer to decide on inlining.
-impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R {
-    #[inline(always)]
-    fn next_u32(&mut self) -> u32 {
-        (**self).next_u32()
-    }
-
-    #[inline(always)]
-    fn next_u64(&mut self) -> u64 {
-        (**self).next_u64()
-    }
-
-    #[inline(always)]
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        (**self).fill_bytes(dest)
-    }
-
-    #[inline(always)]
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-        (**self).try_fill_bytes(dest)
-    }
-}
-
-// Implement `RngCore` for boxed references to an `RngCore`.
-// Force inlining all functions, so that it is up to the `RngCore`
-// implementation and the optimizer to decide on inlining.
-#[cfg(feature = "alloc")]
-impl<R: RngCore + ?Sized> RngCore for Box<R> {
-    #[inline(always)]
-    fn next_u32(&mut self) -> u32 {
-        (**self).next_u32()
-    }
-
-    #[inline(always)]
-    fn next_u64(&mut self) -> u64 {
-        (**self).next_u64()
-    }
-
-    #[inline(always)]
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        (**self).fill_bytes(dest)
-    }
-
-    #[inline(always)]
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-        (**self).try_fill_bytes(dest)
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::io::Read for dyn RngCore {
-    fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
-        self.try_fill_bytes(buf)?;
-        Ok(buf.len())
-    }
-}
-
-// Implement `CryptoRng` for references to a `CryptoRng`.
-impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
-
-// Implement `CryptoRng` for boxed references to a `CryptoRng`.
-#[cfg(feature = "alloc")]
-impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_seed_from_u64() {
-        struct SeedableNum(u64);
-        impl SeedableRng for SeedableNum {
-            type Seed = [u8; 8];
-
-            fn from_seed(seed: Self::Seed) -> Self {
-                let mut x = [0u64; 1];
-                le::read_u64_into(&seed, &mut x);
-                SeedableNum(x[0])
-            }
-        }
-
-        const N: usize = 8;
-        const SEEDS: [u64; N] = [0u64, 1, 2, 3, 4, 8, 16, -1i64 as u64];
-        let mut results = [0u64; N];
-        for (i, seed) in SEEDS.iter().enumerate() {
-            let SeedableNum(x) = SeedableNum::seed_from_u64(*seed);
-            results[i] = x;
-        }
-
-        for (i1, r1) in results.iter().enumerate() {
-            let weight = r1.count_ones();
-            // This is the binomial distribution B(64, 0.5), so chance of
-            // weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for
-            // weight > 44.
-            assert!((20..=44).contains(&weight));
-
-            for (i2, r2) in results.iter().enumerate() {
-                if i1 == i2 {
-                    continue;
-                }
-                let diff_weight = (r1 ^ r2).count_ones();
-                assert!(diff_weight >= 20);
-            }
-        }
-
-        // value-breakage test:
-        assert_eq!(results[0], 5029875928683246316);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/os.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/os.rs
deleted file mode 100644
index 6cd1b9c..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_6/src/os.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2019 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Interface to the random number generator of the operating system.
-
-use crate::{impls, CryptoRng, Error, RngCore};
-use getrandom::getrandom;
-
-/// A random number generator that retrieves randomness from the
-/// operating system.
-///
-/// This is a zero-sized struct. It can be freely constructed with `OsRng`.
-///
-/// The implementation is provided by the [getrandom] crate. Refer to
-/// [getrandom] documentation for details.
-///
-/// This struct is only available when specifying the crate feature `getrandom`
-/// or `std`. When using the `rand` lib, it is also available as `rand::rngs::OsRng`.
-///
-/// # Blocking and error handling
-///
-/// It is possible that when used during early boot the first call to `OsRng`
-/// will block until the system's RNG is initialised. It is also possible
-/// (though highly unlikely) for `OsRng` to fail on some platforms, most
-/// likely due to system mis-configuration.
-///
-/// After the first successful call, it is highly unlikely that failures or
-/// significant delays will occur (although performance should be expected to
-/// be much slower than a user-space PRNG).
-///
-/// # Usage example
-/// ```
-/// use rand_core::{RngCore, OsRng};
-///
-/// let mut key = [0u8; 16];
-/// OsRng.fill_bytes(&mut key);
-/// let random_u64 = OsRng.next_u64();
-/// ```
-///
-/// [getrandom]: https://crates.io/crates/getrandom
-#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
-#[derive(Clone, Copy, Debug, Default)]
-pub struct OsRng;
-
-impl CryptoRng for OsRng {}
-
-impl RngCore for OsRng {
-    fn next_u32(&mut self) -> u32 {
-        impls::next_u32_via_fill(self)
-    }
-
-    fn next_u64(&mut self) -> u64 {
-        impls::next_u64_via_fill(self)
-    }
-
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        if let Err(e) = self.try_fill_bytes(dest) {
-            panic!("Error: {}", e);
-        }
-    }
-
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-        getrandom(dest)?;
-        Ok(())
-    }
-}
-
-#[test]
-fn test_os_rng() {
-    let x = OsRng.next_u64();
-    let y = OsRng.next_u64();
-    assert!(x != 0);
-    assert!(x != y);
-}
-
-#[test]
-fn test_construction() {
-    let mut rng = OsRng::default();
-    assert!(rng.next_u64() != 0);
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/.cargo-checksum.json
deleted file mode 100644
index 697c9ce..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/.cargo-checksum.json
+++ /dev/null
@@ -1 +0,0 @@
-{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/.cargo_vcs_info.json
deleted file mode 100644
index b63edca..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "git": {
-    "sha1": "340849e53b71da0f15af448d10511c2e62e50ba1"
-  },
-  "path_in_vcs": "rand_core"
-}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/CHANGELOG.md
deleted file mode 100644
index 7318dff..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/CHANGELOG.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# Changelog
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [0.9.3] — 2025-02-29
-### Other
-- Remove `zerocopy` dependency (#1607)
-- Deprecate `rand_core::impls::fill_via_u32_chunks`, `fill_via_u64_chunks` (#1607)
-
-## [0.9.2] - 2025-02-22
-### API changes
-- Relax `Sized` bound on impls of `TryRngCore`, `TryCryptoRng` and `UnwrapMut` (#1593)
-- Add `UnwrapMut::re` to reborrow the inner rng with a tighter lifetime (#1595)
-
-## [0.9.1] - 2025-02-16
-### API changes
-- Add `TryRngCore::unwrap_mut`, providing an impl of `RngCore` over `&mut rng` (#1589)
-
-## [0.9.0] - 2025-01-27
-### Dependencies and features
-- Bump the MSRV to 1.63.0 (#1207, #1246, #1269, #1341, #1416, #1536); note that 1.60.0 may work for dependents when using `--ignore-rust-version`
-- Update to `getrandom` v0.3.0 (#1558)
-- Use `zerocopy` to replace some `unsafe` code (#1349, #1393, #1446, #1502)
-- Rename feature `serde1` to `serde` (#1477)
-- Rename feature `getrandom` to `os_rng` (#1537)
-
-### API changes
-- Allow `rand_core::impls::fill_via_u*_chunks` to mutate source (#1182)
-- Add fn `RngCore::read_adapter` implementing `std::io::Read` (#1267)
-- Add trait `CryptoBlockRng: BlockRngCore`; make `trait CryptoRng: RngCore` replacing `CryptoRngCore` (#1273)
-- Add traits `TryRngCore`, `TryCryptoRng` (#1424, #1499)
-- Rename `fn SeedableRng::from_rng` -> `try_from_rng` and add infallible variant `fn from_rng` (#1424)
-- Rename `fn SeedableRng::from_entropy` -> `from_os_rng` and add fallible variant `fn try_from_os_rng` (#1424)
-- Add bounds `Clone` and `AsRef` to associated type `SeedableRng::Seed` (#1491)
-
-## [0.6.4] - 2022-09-15
-- Fix unsoundness in `<BlockRng64 as RngCore>::next_u32` (#1160)
-- Reduce use of `unsafe` and improve gen_bytes performance (#1180)
-- Add `CryptoRngCore` trait (#1187, #1230)
-
-## [0.6.3] - 2021-06-15
-### Changed
-- Improved bound for `serde` impls on `BlockRng` (#1130)
-- Minor doc additions (#1118)
-
-## [0.6.2] - 2021-02-12
-### Fixed
-- Fixed assertions in `le::read_u32_into` and `le::read_u64_into` which could
-  have allowed buffers not to be fully populated (#1096)
-
-## [0.6.1] - 2021-01-03
-### Fixed
-- Avoid panic when using `RngCore::seed_from_u64` with a seed which is not a
-  multiple of four (#1082)
-### Other
-- Enable all stable features in the playground (#1081)
-
-## [0.6.0] - 2020-12-08
-### Breaking changes
-- Bump MSRV to 1.36, various code improvements (#1011)
-- Update to getrandom v0.2 (#1041)
-- Fix: `next_u32_via_fill` and `next_u64_via_fill` now use LE as documented (#1061)
-
-### Other
-- Reduce usage of `unsafe` (#962, #963, #1011)
-- Annotate feature-gates in documentation (#1019)
-- Document available error codes (#1061)
-- Various documentation tweaks
-- Fix some clippy warnings (#1036)
-- Apply rustfmt (#926)
-
-## [0.5.1] - 2019-08-28
-- `OsRng` added to `rand_core` (#863)
-- `Error::INTERNAL_START` and `Error::CUSTOM_START` constants (#864)
-- `Error::raw_os_error` method (#864)
-- `Debug` and `Display` formatting for `getrandom` error codes without `std` (#864)
-### Changed
-- `alloc` feature in `no_std` is available since Rust 1.36 (#856)
-- Added `#[inline]` to `Error` conversion methods (#864)
-
-## [0.5.0] - 2019-06-06
-### Changed
-- Enable testing with Miri and fix incorrect pointer usages (#779, #780, #781, #783, #784)
-- Rewrite `Error` type and adjust API (#800)
-- Adjust usage of `#[inline]` for `BlockRng` and `BlockRng64`
-
-## [0.4.0] - 2019-01-24
-### Changed
-- Disable the `std` feature by default (#702)
-
-## [0.3.0] - 2018-09-24
-### Added
-- Add `SeedableRng::seed_from_u64` for convenient seeding. (#537)
-
-## [0.2.1] - 2018-06-08
-### Added
-- References to a `CryptoRng` now also implement `CryptoRng`. (#470)
-
-## [0.2.0] - 2018-05-21
-### Changed
-- Enable the `std` feature by default. (#409)
-- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public
-- Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419)
-### Added
-- Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419)
-- Implement `std::io::Read` for RngCore. (#434)
-
-## [0.1.0] - 2018-04-17
-(Split out of the Rand crate, changes here are relative to rand 0.4.2.)
-### Added
-- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288)
-- Add modules to help implementing RNGs `impl` and `le`. (#209, #228)
-- Add `Error` and `ErrorKind`. (#225)
-- Add `CryptoRng` marker trait. (#273)
-- Add `BlockRngCore` trait. (#281)
-- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
-- Add `RngCore::try_fill_bytes`. (#225)
-### Changed
-- Revise the `SeedableRng` trait. (#233)
-- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
-
-## [0.0.1] - 2017-09-14 (yanked)
-Experimental version as part of the rand crate refactor.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/COPYRIGHT b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/COPYRIGHT
deleted file mode 100644
index 468d907..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/COPYRIGHT
+++ /dev/null
@@ -1,12 +0,0 @@
-Copyrights in the Rand project are retained by their contributors. No
-copyright assignment is required to contribute to the Rand project.
-
-For full authorship information, see the version control history.
-
-Except as otherwise noted (below and/or in individual files), Rand is
-licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
-<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
-
-The Rand project includes code from the Rust project
-published under these same licenses.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.lock
deleted file mode 100644
index 81a9e82b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.lock
+++ /dev/null
@@ -1,178 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "bitflags"
-version = "2.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "getrandom"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
- "windows-targets",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.169"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.93"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.38"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.9.3"
-dependencies = [
- "getrandom",
- "serde",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.217"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.217"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.96"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
-
-[[package]]
-name = "wasi"
-version = "0.13.3+wasi-0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
-dependencies = [
- "wit-bindgen-rt",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "wit-bindgen-rt"
-version = "0.33.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
-dependencies = [
- "bitflags",
-]
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.toml
deleted file mode 100644
index 824850d..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.toml
+++ /dev/null
@@ -1,67 +0,0 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies.
-#
-# If you are reading this file be aware that the original Cargo.toml
-# will likely look very different (and much more reasonable).
-# See Cargo.toml.orig for the original contents.
-
-[package]
-edition = "2021"
-rust-version = "1.63"
-name = "rand_core"
-version = "0.9.3"
-authors = [
-    "The Rand Project Developers",
-    "The Rust Project Developers",
-]
-build = false
-autolib = false
-autobins = false
-autoexamples = false
-autotests = false
-autobenches = false
-description = """
-Core random number generator traits and tools for implementation.
-"""
-homepage = "https://rust-random.github.io/book"
-documentation = "https://docs.rs/rand_core"
-readme = "README.md"
-keywords = [
-    "random",
-    "rng",
-]
-categories = [
-    "algorithms",
-    "no-std",
-]
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/rust-random/rand"
-
-[package.metadata.docs.rs]
-all-features = true
-rustdoc-args = ["--generate-link-to-definition"]
-
-[package.metadata.playground]
-all-features = true
-
-[features]
-os_rng = ["dep:getrandom"]
-serde = ["dep:serde"]
-std = ["getrandom?/std"]
-
-[lib]
-name = "rand_core"
-path = "src/lib.rs"
-
-[dependencies.getrandom]
-version = "0.3.0"
-optional = true
-
-[dependencies.serde]
-version = "1"
-features = ["derive"]
-optional = true
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.toml.orig
deleted file mode 100644
index 899c359..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/Cargo.toml.orig
+++ /dev/null
@@ -1,34 +0,0 @@
-[package]
-name = "rand_core"
-version = "0.9.3"
-authors = ["The Rand Project Developers", "The Rust Project Developers"]
-license = "MIT OR Apache-2.0"
-readme = "README.md"
-repository = "https://github.com/rust-random/rand"
-documentation = "https://docs.rs/rand_core"
-homepage = "https://rust-random.github.io/book"
-description = """
-Core random number generator traits and tools for implementation.
-"""
-keywords = ["random", "rng"]
-categories = ["algorithms", "no-std"]
-edition = "2021"
-rust-version = "1.63"
-
-[package.metadata.docs.rs]
-# To build locally:
-# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps --open
-all-features = true
-rustdoc-args = ["--generate-link-to-definition"]
-
-[package.metadata.playground]
-all-features = true
-
-[features]
-std = ["getrandom?/std"]
-os_rng = ["dep:getrandom"]
-serde = ["dep:serde"] # enables serde for BlockRng wrapper
-
-[dependencies]
-serde = { version = "1", features = ["derive"], optional = true }
-getrandom = { version = "0.3.0", optional = true }
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/LICENSE-APACHE
deleted file mode 100644
index 455787c2..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/LICENSE-APACHE
+++ /dev/null
@@ -1,187 +0,0 @@
-                              Apache License
-                        Version 2.0, January 2004
-                     https://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.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/LICENSE-MIT
deleted file mode 100644
index d93b5ba..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/LICENSE-MIT
+++ /dev/null
@@ -1,26 +0,0 @@
-Copyright 2018 Developers of the Rand project
-Copyright (c) 2014 The Rust Project Developers
-
-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
-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/rand_core-v0_9/README.md b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/README.md
deleted file mode 100644
index 632afa52..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/README.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# rand_core
-
-[![Test Status](https://github.com/rust-random/rand/actions/workflows/test.yml/badge.svg?event=push)](https://github.com/rust-random/rand/actions)
-[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core)
-[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
-[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core)
-[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core)
-
-Core traits and error types of the [rand] library, plus tools for implementing
-RNGs.
-
-This crate is intended for use when implementing the core trait, `RngCore`; it
-defines the core traits to be implemented as well as several small functions to
-aid in their implementation and types required for error handling.
-
-The main [rand] crate re-exports most items defined in this crate, along with
-tools to convert the integer samples generated by `RngCore` to many different
-applications (including sampling from restricted ranges, conversion to floating
-point, list permutations and secure initialisation of RNGs). Most users should
-prefer to use the main [rand] crate.
-
-Links:
-
--   [API documentation (master)](https://rust-random.github.io/rand/rand_core)
--   [API documentation (docs.rs)](https://docs.rs/rand_core)
--   [Changelog](https://github.com/rust-random/rand/blob/master/rand_core/CHANGELOG.md)
-
-[rand]: https://crates.io/crates/rand
-
-
-## Functionality
-
-The `rand_core` crate provides:
-
--   base random number generator traits
--   error-reporting types
--   functionality to aid implementation of RNGs
-
-The traits and error types are also available via `rand`.
-
-## Versions
-
-The current version is:
-
-```toml
-rand_core = "0.9.0"
-```
-
-
-# License
-
-`rand_core` is distributed under the terms of both the MIT license and the
-Apache License (Version 2.0).
-
-See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
-[COPYRIGHT](COPYRIGHT) for details.
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/block.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/block.rs
deleted file mode 100644
index 667cc0b..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/block.rs
+++ /dev/null
@@ -1,534 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The `BlockRngCore` trait and implementation helpers
-//!
-//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs
-//! which generate a block of data in a cache instead of returning generated
-//! values directly.
-//!
-//! Usage of this trait is optional, but provides two advantages:
-//! implementations only need to concern themselves with generation of the
-//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where
-//! the optimal implementations are not trivial), and this allows
-//! `ReseedingRng` (see [`rand`](https://docs.rs/rand) crate) perform periodic
-//! reseeding with very low overhead.
-//!
-//! # Example
-//!
-//! ```no_run
-//! use rand_core::{RngCore, SeedableRng};
-//! use rand_core::block::{BlockRngCore, BlockRng};
-//!
-//! struct MyRngCore;
-//!
-//! impl BlockRngCore for MyRngCore {
-//!     type Item = u32;
-//!     type Results = [u32; 16];
-//!
-//!     fn generate(&mut self, results: &mut Self::Results) {
-//!         unimplemented!()
-//!     }
-//! }
-//!
-//! impl SeedableRng for MyRngCore {
-//!     type Seed = [u8; 32];
-//!     fn from_seed(seed: Self::Seed) -> Self {
-//!         unimplemented!()
-//!     }
-//! }
-//!
-//! // optionally, also implement CryptoBlockRng for MyRngCore
-//!
-//! // Final RNG.
-//! let mut rng = BlockRng::<MyRngCore>::seed_from_u64(0);
-//! println!("First value: {}", rng.next_u32());
-//! ```
-//!
-//! [`BlockRngCore`]: crate::block::BlockRngCore
-//! [`fill_bytes`]: RngCore::fill_bytes
-
-use crate::impls::fill_via_chunks;
-use crate::{CryptoRng, RngCore, SeedableRng, TryRngCore};
-use core::fmt;
-#[cfg(feature = "serde")]
-use serde::{Deserialize, Serialize};
-
-/// A trait for RNGs which do not generate random numbers individually, but in
-/// blocks (typically `[u32; N]`). This technique is commonly used by
-/// cryptographic RNGs to improve performance.
-///
-/// See the [module][crate::block] documentation for details.
-pub trait BlockRngCore {
-    /// Results element type, e.g. `u32`.
-    type Item;
-
-    /// Results type. This is the 'block' an RNG implementing `BlockRngCore`
-    /// generates, which will usually be an array like `[u32; 16]`.
-    type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default;
-
-    /// Generate a new block of results.
-    fn generate(&mut self, results: &mut Self::Results);
-}
-
-/// A marker trait used to indicate that an [`RngCore`] implementation is
-/// supposed to be cryptographically secure.
-///
-/// See [`CryptoRng`] docs for more information.
-pub trait CryptoBlockRng: BlockRngCore {}
-
-/// A wrapper type implementing [`RngCore`] for some type implementing
-/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement
-/// a full RNG from just a `generate` function.
-///
-/// The `core` field may be accessed directly but the results buffer may not.
-/// PRNG implementations can simply use a type alias
-/// (`pub type MyRng = BlockRng<MyRngCore>;`) but might prefer to use a
-/// wrapper type (`pub struct MyRng(BlockRng<MyRngCore>);`); the latter must
-/// re-implement `RngCore` but hides the implementation details and allows
-/// extra functionality to be defined on the RNG
-/// (e.g. `impl MyRng { fn set_stream(...){...} }`).
-///
-/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods
-/// reading values from the results buffer, as well as
-/// calling [`BlockRngCore::generate`] directly on the output array when
-/// [`fill_bytes`] is called on a large array. These methods also handle
-/// the bookkeeping of when to generate a new batch of values.
-///
-/// No whole generated `u32` values are thrown away and all values are consumed
-/// in-order. [`next_u32`] simply takes the next available `u32` value.
-/// [`next_u64`] is implemented by combining two `u32` values, least
-/// significant first. [`fill_bytes`] consume a whole number of `u32` values,
-/// converting each `u32` to a byte slice in little-endian order. If the requested byte
-/// length is not a multiple of 4, some bytes will be discarded.
-///
-/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is
-/// no direct support for other buffer types.
-///
-/// For easy initialization `BlockRng` also implements [`SeedableRng`].
-///
-/// [`next_u32`]: RngCore::next_u32
-/// [`next_u64`]: RngCore::next_u64
-/// [`fill_bytes`]: RngCore::fill_bytes
-#[derive(Clone)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-#[cfg_attr(
-    feature = "serde",
-    serde(
-        bound = "for<'x> R: Serialize + Deserialize<'x>, for<'x> R::Results: Serialize + Deserialize<'x>"
-    )
-)]
-pub struct BlockRng<R: BlockRngCore> {
-    results: R::Results,
-    index: usize,
-    /// The *core* part of the RNG, implementing the `generate` function.
-    pub core: R,
-}
-
-// Custom Debug implementation that does not expose the contents of `results`.
-impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng<R> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        fmt.debug_struct("BlockRng")
-            .field("core", &self.core)
-            .field("result_len", &self.results.as_ref().len())
-            .field("index", &self.index)
-            .finish()
-    }
-}
-
-impl<R: BlockRngCore> BlockRng<R> {
-    /// Create a new `BlockRng` from an existing RNG implementing
-    /// `BlockRngCore`. Results will be generated on first use.
-    #[inline]
-    pub fn new(core: R) -> BlockRng<R> {
-        let results_empty = R::Results::default();
-        BlockRng {
-            core,
-            index: results_empty.as_ref().len(),
-            results: results_empty,
-        }
-    }
-
-    /// Get the index into the result buffer.
-    ///
-    /// If this is equal to or larger than the size of the result buffer then
-    /// the buffer is "empty" and `generate()` must be called to produce new
-    /// results.
-    #[inline(always)]
-    pub fn index(&self) -> usize {
-        self.index
-    }
-
-    /// Reset the number of available results.
-    /// This will force a new set of results to be generated on next use.
-    #[inline]
-    pub fn reset(&mut self) {
-        self.index = self.results.as_ref().len();
-    }
-
-    /// Generate a new set of results immediately, setting the index to the
-    /// given value.
-    #[inline]
-    pub fn generate_and_set(&mut self, index: usize) {
-        assert!(index < self.results.as_ref().len());
-        self.core.generate(&mut self.results);
-        self.index = index;
-    }
-}
-
-impl<R: BlockRngCore<Item = u32>> RngCore for BlockRng<R> {
-    #[inline]
-    fn next_u32(&mut self) -> u32 {
-        if self.index >= self.results.as_ref().len() {
-            self.generate_and_set(0);
-        }
-
-        let value = self.results.as_ref()[self.index];
-        self.index += 1;
-        value
-    }
-
-    #[inline]
-    fn next_u64(&mut self) -> u64 {
-        let read_u64 = |results: &[u32], index| {
-            let data = &results[index..=index + 1];
-            (u64::from(data[1]) << 32) | u64::from(data[0])
-        };
-
-        let len = self.results.as_ref().len();
-
-        let index = self.index;
-        if index < len - 1 {
-            self.index += 2;
-            // Read an u64 from the current index
-            read_u64(self.results.as_ref(), index)
-        } else if index >= len {
-            self.generate_and_set(2);
-            read_u64(self.results.as_ref(), 0)
-        } else {
-            let x = u64::from(self.results.as_ref()[len - 1]);
-            self.generate_and_set(1);
-            let y = u64::from(self.results.as_ref()[0]);
-            (y << 32) | x
-        }
-    }
-
-    #[inline]
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        let mut read_len = 0;
-        while read_len < dest.len() {
-            if self.index >= self.results.as_ref().len() {
-                self.generate_and_set(0);
-            }
-            let (consumed_u32, filled_u8) =
-                fill_via_chunks(&self.results.as_mut()[self.index..], &mut dest[read_len..]);
-
-            self.index += consumed_u32;
-            read_len += filled_u8;
-        }
-    }
-}
-
-impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
-    type Seed = R::Seed;
-
-    #[inline(always)]
-    fn from_seed(seed: Self::Seed) -> Self {
-        Self::new(R::from_seed(seed))
-    }
-
-    #[inline(always)]
-    fn seed_from_u64(seed: u64) -> Self {
-        Self::new(R::seed_from_u64(seed))
-    }
-
-    #[inline(always)]
-    fn from_rng(rng: &mut impl RngCore) -> Self {
-        Self::new(R::from_rng(rng))
-    }
-
-    #[inline(always)]
-    fn try_from_rng<S: TryRngCore>(rng: &mut S) -> Result<Self, S::Error> {
-        R::try_from_rng(rng).map(Self::new)
-    }
-}
-
-impl<R: CryptoBlockRng + BlockRngCore<Item = u32>> CryptoRng for BlockRng<R> {}
-
-/// A wrapper type implementing [`RngCore`] for some type implementing
-/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement
-/// a full RNG from just a `generate` function.
-///
-/// This is similar to [`BlockRng`], but specialized for algorithms that operate
-/// on `u64` values.
-///
-/// No whole generated `u64` values are thrown away and all values are consumed
-/// in-order. [`next_u64`] simply takes the next available `u64` value.
-/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving
-/// the other half in the buffer. If the next function called is [`next_u32`]
-/// then the other half is then consumed, however both [`next_u64`] and
-/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called.
-///
-/// [`fill_bytes`] consumes a whole number of `u64` values. If the requested length
-/// is not a multiple of 8, some bytes will be discarded.
-///
-/// [`next_u32`]: RngCore::next_u32
-/// [`next_u64`]: RngCore::next_u64
-/// [`fill_bytes`]: RngCore::fill_bytes
-#[derive(Clone)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct BlockRng64<R: BlockRngCore + ?Sized> {
-    results: R::Results,
-    index: usize,
-    half_used: bool, // true if only half of the previous result is used
-    /// The *core* part of the RNG, implementing the `generate` function.
-    pub core: R,
-}
-
-// Custom Debug implementation that does not expose the contents of `results`.
-impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng64<R> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        fmt.debug_struct("BlockRng64")
-            .field("core", &self.core)
-            .field("result_len", &self.results.as_ref().len())
-            .field("index", &self.index)
-            .field("half_used", &self.half_used)
-            .finish()
-    }
-}
-
-impl<R: BlockRngCore> BlockRng64<R> {
-    /// Create a new `BlockRng` from an existing RNG implementing
-    /// `BlockRngCore`. Results will be generated on first use.
-    #[inline]
-    pub fn new(core: R) -> BlockRng64<R> {
-        let results_empty = R::Results::default();
-        BlockRng64 {
-            core,
-            index: results_empty.as_ref().len(),
-            half_used: false,
-            results: results_empty,
-        }
-    }
-
-    /// Get the index into the result buffer.
-    ///
-    /// If this is equal to or larger than the size of the result buffer then
-    /// the buffer is "empty" and `generate()` must be called to produce new
-    /// results.
-    #[inline(always)]
-    pub fn index(&self) -> usize {
-        self.index
-    }
-
-    /// Reset the number of available results.
-    /// This will force a new set of results to be generated on next use.
-    #[inline]
-    pub fn reset(&mut self) {
-        self.index = self.results.as_ref().len();
-        self.half_used = false;
-    }
-
-    /// Generate a new set of results immediately, setting the index to the
-    /// given value.
-    #[inline]
-    pub fn generate_and_set(&mut self, index: usize) {
-        assert!(index < self.results.as_ref().len());
-        self.core.generate(&mut self.results);
-        self.index = index;
-        self.half_used = false;
-    }
-}
-
-impl<R: BlockRngCore<Item = u64>> RngCore for BlockRng64<R> {
-    #[inline]
-    fn next_u32(&mut self) -> u32 {
-        let mut index = self.index - self.half_used as usize;
-        if index >= self.results.as_ref().len() {
-            self.core.generate(&mut self.results);
-            self.index = 0;
-            index = 0;
-            // `self.half_used` is by definition `false`
-            self.half_used = false;
-        }
-
-        let shift = 32 * (self.half_used as usize);
-
-        self.half_used = !self.half_used;
-        self.index += self.half_used as usize;
-
-        (self.results.as_ref()[index] >> shift) as u32
-    }
-
-    #[inline]
-    fn next_u64(&mut self) -> u64 {
-        if self.index >= self.results.as_ref().len() {
-            self.core.generate(&mut self.results);
-            self.index = 0;
-        }
-
-        let value = self.results.as_ref()[self.index];
-        self.index += 1;
-        self.half_used = false;
-        value
-    }
-
-    #[inline]
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        let mut read_len = 0;
-        self.half_used = false;
-        while read_len < dest.len() {
-            if self.index >= self.results.as_ref().len() {
-                self.core.generate(&mut self.results);
-                self.index = 0;
-            }
-
-            let (consumed_u64, filled_u8) =
-                fill_via_chunks(&self.results.as_mut()[self.index..], &mut dest[read_len..]);
-
-            self.index += consumed_u64;
-            read_len += filled_u8;
-        }
-    }
-}
-
-impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
-    type Seed = R::Seed;
-
-    #[inline(always)]
-    fn from_seed(seed: Self::Seed) -> Self {
-        Self::new(R::from_seed(seed))
-    }
-
-    #[inline(always)]
-    fn seed_from_u64(seed: u64) -> Self {
-        Self::new(R::seed_from_u64(seed))
-    }
-
-    #[inline(always)]
-    fn from_rng(rng: &mut impl RngCore) -> Self {
-        Self::new(R::from_rng(rng))
-    }
-
-    #[inline(always)]
-    fn try_from_rng<S: TryRngCore>(rng: &mut S) -> Result<Self, S::Error> {
-        R::try_from_rng(rng).map(Self::new)
-    }
-}
-
-impl<R: CryptoBlockRng + BlockRngCore<Item = u64>> CryptoRng for BlockRng64<R> {}
-
-#[cfg(test)]
-mod test {
-    use crate::block::{BlockRng, BlockRng64, BlockRngCore};
-    use crate::{RngCore, SeedableRng};
-
-    #[derive(Debug, Clone)]
-    struct DummyRng {
-        counter: u32,
-    }
-
-    impl BlockRngCore for DummyRng {
-        type Item = u32;
-        type Results = [u32; 16];
-
-        fn generate(&mut self, results: &mut Self::Results) {
-            for r in results {
-                *r = self.counter;
-                self.counter = self.counter.wrapping_add(3511615421);
-            }
-        }
-    }
-
-    impl SeedableRng for DummyRng {
-        type Seed = [u8; 4];
-
-        fn from_seed(seed: Self::Seed) -> Self {
-            DummyRng {
-                counter: u32::from_le_bytes(seed),
-            }
-        }
-    }
-
-    #[test]
-    fn blockrng_next_u32_vs_next_u64() {
-        let mut rng1 = BlockRng::<DummyRng>::from_seed([1, 2, 3, 4]);
-        let mut rng2 = rng1.clone();
-        let mut rng3 = rng1.clone();
-
-        let mut a = [0; 16];
-        a[..4].copy_from_slice(&rng1.next_u32().to_le_bytes());
-        a[4..12].copy_from_slice(&rng1.next_u64().to_le_bytes());
-        a[12..].copy_from_slice(&rng1.next_u32().to_le_bytes());
-
-        let mut b = [0; 16];
-        b[..4].copy_from_slice(&rng2.next_u32().to_le_bytes());
-        b[4..8].copy_from_slice(&rng2.next_u32().to_le_bytes());
-        b[8..].copy_from_slice(&rng2.next_u64().to_le_bytes());
-        assert_eq!(a, b);
-
-        let mut c = [0; 16];
-        c[..8].copy_from_slice(&rng3.next_u64().to_le_bytes());
-        c[8..12].copy_from_slice(&rng3.next_u32().to_le_bytes());
-        c[12..].copy_from_slice(&rng3.next_u32().to_le_bytes());
-        assert_eq!(a, c);
-    }
-
-    #[derive(Debug, Clone)]
-    struct DummyRng64 {
-        counter: u64,
-    }
-
-    impl BlockRngCore for DummyRng64 {
-        type Item = u64;
-        type Results = [u64; 8];
-
-        fn generate(&mut self, results: &mut Self::Results) {
-            for r in results {
-                *r = self.counter;
-                self.counter = self.counter.wrapping_add(2781463553396133981);
-            }
-        }
-    }
-
-    impl SeedableRng for DummyRng64 {
-        type Seed = [u8; 8];
-
-        fn from_seed(seed: Self::Seed) -> Self {
-            DummyRng64 {
-                counter: u64::from_le_bytes(seed),
-            }
-        }
-    }
-
-    #[test]
-    fn blockrng64_next_u32_vs_next_u64() {
-        let mut rng1 = BlockRng64::<DummyRng64>::from_seed([1, 2, 3, 4, 5, 6, 7, 8]);
-        let mut rng2 = rng1.clone();
-        let mut rng3 = rng1.clone();
-
-        let mut a = [0; 16];
-        a[..4].copy_from_slice(&rng1.next_u32().to_le_bytes());
-        a[4..12].copy_from_slice(&rng1.next_u64().to_le_bytes());
-        a[12..].copy_from_slice(&rng1.next_u32().to_le_bytes());
-
-        let mut b = [0; 16];
-        b[..4].copy_from_slice(&rng2.next_u32().to_le_bytes());
-        b[4..8].copy_from_slice(&rng2.next_u32().to_le_bytes());
-        b[8..].copy_from_slice(&rng2.next_u64().to_le_bytes());
-        assert_ne!(a, b);
-        assert_eq!(&a[..4], &b[..4]);
-        assert_eq!(&a[4..12], &b[8..]);
-
-        let mut c = [0; 16];
-        c[..8].copy_from_slice(&rng3.next_u64().to_le_bytes());
-        c[8..12].copy_from_slice(&rng3.next_u32().to_le_bytes());
-        c[12..].copy_from_slice(&rng3.next_u32().to_le_bytes());
-        assert_eq!(b, c);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/impls.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/impls.rs
deleted file mode 100644
index 4cced0d..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/impls.rs
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Helper functions for implementing `RngCore` functions.
-//!
-//! For cross-platform reproducibility, these functions all use Little Endian:
-//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
-//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
-//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
-//!
-//! Byte-swapping (like the std `to_le` functions) is only needed to convert
-//! to/from byte sequences, and since its purpose is reproducibility,
-//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
-
-use crate::RngCore;
-
-/// Implement `next_u64` via `next_u32`, little-endian order.
-pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
-    // Use LE; we explicitly generate one value before the next.
-    let x = u64::from(rng.next_u32());
-    let y = u64::from(rng.next_u32());
-    (y << 32) | x
-}
-
-/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
-///
-/// The fastest way to fill a slice is usually to work as long as possible with
-/// integers. That is why this method mostly uses `next_u64`, and only when
-/// there are 4 or less bytes remaining at the end of the slice it uses
-/// `next_u32` once.
-pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
-    let mut left = dest;
-    while left.len() >= 8 {
-        let (l, r) = { left }.split_at_mut(8);
-        left = r;
-        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
-        l.copy_from_slice(&chunk);
-    }
-    let n = left.len();
-    if n > 4 {
-        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
-        left.copy_from_slice(&chunk[..n]);
-    } else if n > 0 {
-        let chunk: [u8; 4] = rng.next_u32().to_le_bytes();
-        left.copy_from_slice(&chunk[..n]);
-    }
-}
-
-pub(crate) trait Observable: Copy {
-    type Bytes: Sized + AsRef<[u8]>;
-    fn to_le_bytes(self) -> Self::Bytes;
-}
-impl Observable for u32 {
-    type Bytes = [u8; 4];
-
-    fn to_le_bytes(self) -> Self::Bytes {
-        Self::to_le_bytes(self)
-    }
-}
-impl Observable for u64 {
-    type Bytes = [u8; 8];
-
-    fn to_le_bytes(self) -> Self::Bytes {
-        Self::to_le_bytes(self)
-    }
-}
-
-/// Fill dest from src
-///
-/// Returns `(n, byte_len)`. `src[..n]` is consumed,
-/// `dest[..byte_len]` is filled. `src[n..]` and `dest[byte_len..]` are left
-/// unaltered.
-pub(crate) fn fill_via_chunks<T: Observable>(src: &[T], dest: &mut [u8]) -> (usize, usize) {
-    let size = core::mem::size_of::<T>();
-
-    // Always use little endian for portability of results.
-
-    let mut dest = dest.chunks_exact_mut(size);
-    let mut src = src.iter();
-
-    let zipped = dest.by_ref().zip(src.by_ref());
-    let num_chunks = zipped.len();
-    zipped.for_each(|(dest, src)| dest.copy_from_slice(src.to_le_bytes().as_ref()));
-
-    let byte_len = num_chunks * size;
-    if let Some(src) = src.next() {
-        // We have consumed all full chunks of dest, but not src.
-        let dest = dest.into_remainder();
-        let n = dest.len();
-        if n > 0 {
-            dest.copy_from_slice(&src.to_le_bytes().as_ref()[..n]);
-            return (num_chunks + 1, byte_len + n);
-        }
-    }
-    (num_chunks, byte_len)
-}
-
-/// Implement `fill_bytes` by reading chunks from the output buffer of a block
-/// based RNG.
-///
-/// The return values are `(consumed_u32, filled_u8)`.
-///
-/// `src` is not modified; it is taken as a `&mut` reference for backward
-/// compatibility with previous versions that did change it.
-///
-/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
-/// the length of `dest`.
-/// `consumed_u32` is the number of words consumed from `src`, which is the same
-/// as `filled_u8 / 4` rounded up.
-///
-/// # Example
-/// (from `IsaacRng`)
-///
-/// ```ignore
-/// fn fill_bytes(&mut self, dest: &mut [u8]) {
-///     let mut read_len = 0;
-///     while read_len < dest.len() {
-///         if self.index >= self.rsl.len() {
-///             self.isaac();
-///         }
-///
-///         let (consumed_u32, filled_u8) =
-///             impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
-///                                        &mut dest[read_len..]);
-///
-///         self.index += consumed_u32;
-///         read_len += filled_u8;
-///     }
-/// }
-/// ```
-#[deprecated(since = "0.9.3", note = "use BlockRng instead")]
-pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
-    fill_via_chunks(src, dest)
-}
-
-/// Implement `fill_bytes` by reading chunks from the output buffer of a block
-/// based RNG.
-///
-/// The return values are `(consumed_u64, filled_u8)`.
-///
-/// `src` is not modified; it is taken as a `&mut` reference for backward
-/// compatibility with previous versions that did change it.
-///
-/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
-/// the length of `dest`.
-/// `consumed_u64` is the number of words consumed from `src`, which is the same
-/// as `filled_u8 / 8` rounded up.
-///
-/// See `fill_via_u32_chunks` for an example.
-#[deprecated(since = "0.9.3", note = "use BlockRng64 instead")]
-pub fn fill_via_u64_chunks(src: &mut [u64], dest: &mut [u8]) -> (usize, usize) {
-    fill_via_chunks(src, dest)
-}
-
-/// Implement `next_u32` via `fill_bytes`, little-endian order.
-pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
-    let mut buf = [0; 4];
-    rng.fill_bytes(&mut buf);
-    u32::from_le_bytes(buf)
-}
-
-/// Implement `next_u64` via `fill_bytes`, little-endian order.
-pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
-    let mut buf = [0; 8];
-    rng.fill_bytes(&mut buf);
-    u64::from_le_bytes(buf)
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_fill_via_u32_chunks() {
-        let src_orig = [1u32, 2, 3];
-
-        let mut src = src_orig;
-        let mut dst = [0u8; 11];
-        assert_eq!(fill_via_chunks(&mut src, &mut dst), (3, 11));
-        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]);
-
-        let mut src = src_orig;
-        let mut dst = [0u8; 13];
-        assert_eq!(fill_via_chunks(&mut src, &mut dst), (3, 12));
-        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]);
-
-        let mut src = src_orig;
-        let mut dst = [0u8; 5];
-        assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 5));
-        assert_eq!(dst, [1, 0, 0, 0, 2]);
-    }
-
-    #[test]
-    fn test_fill_via_u64_chunks() {
-        let src_orig = [1u64, 2];
-
-        let mut src = src_orig;
-        let mut dst = [0u8; 11];
-        assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 11));
-        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);
-
-        let mut src = src_orig;
-        let mut dst = [0u8; 17];
-        assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 16));
-        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]);
-
-        let mut src = src_orig;
-        let mut dst = [0u8; 5];
-        assert_eq!(fill_via_chunks(&mut src, &mut dst), (1, 5));
-        assert_eq!(dst, [1, 0, 0, 0, 0]);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/le.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/le.rs
deleted file mode 100644
index cee84c2..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/le.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Little-Endian utilities
-//!
-//! Little-Endian order has been chosen for internal usage; this makes some
-//! useful functions available.
-
-/// Reads unsigned 32 bit integers from `src` into `dst`.
-///
-/// # Panics
-///
-/// If `dst` has insufficient space (`4*dst.len() < src.len()`).
-#[inline]
-#[track_caller]
-pub fn read_u32_into(src: &[u8], dst: &mut [u32]) {
-    assert!(src.len() >= 4 * dst.len());
-    for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(4)) {
-        *out = u32::from_le_bytes(chunk.try_into().unwrap());
-    }
-}
-
-/// Reads unsigned 64 bit integers from `src` into `dst`.
-///
-/// # Panics
-///
-/// If `dst` has insufficient space (`8*dst.len() < src.len()`).
-#[inline]
-#[track_caller]
-pub fn read_u64_into(src: &[u8], dst: &mut [u64]) {
-    assert!(src.len() >= 8 * dst.len());
-    for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(8)) {
-        *out = u64::from_le_bytes(chunk.try_into().unwrap());
-    }
-}
-
-#[test]
-fn test_read() {
-    let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
-
-    let mut buf = [0u32; 4];
-    read_u32_into(&bytes, &mut buf);
-    assert_eq!(buf[0], 0x04030201);
-    assert_eq!(buf[3], 0x100F0E0D);
-
-    let mut buf = [0u32; 3];
-    read_u32_into(&bytes[1..13], &mut buf); // unaligned
-    assert_eq!(buf[0], 0x05040302);
-    assert_eq!(buf[2], 0x0D0C0B0A);
-
-    let mut buf = [0u64; 2];
-    read_u64_into(&bytes, &mut buf);
-    assert_eq!(buf[0], 0x0807060504030201);
-    assert_eq!(buf[1], 0x100F0E0D0C0B0A09);
-
-    let mut buf = [0u64; 1];
-    read_u64_into(&bytes[7..15], &mut buf); // unaligned
-    assert_eq!(buf[0], 0x0F0E0D0C0B0A0908);
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/lib.rs
deleted file mode 100644
index d41d0c0..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/lib.rs
+++ /dev/null
@@ -1,771 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2017-2018 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Random number generation traits
-//!
-//! This crate is mainly of interest to crates publishing implementations of
-//! [`RngCore`]. Other users are encouraged to use the [`rand`] crate instead
-//! which re-exports the main traits and error types.
-//!
-//! [`RngCore`] is the core trait implemented by algorithmic pseudo-random number
-//! generators and external random-number sources.
-//!
-//! [`SeedableRng`] is an extension trait for construction from fixed seeds and
-//! other random number generators.
-//!
-//! The [`impls`] and [`le`] sub-modules include a few small functions to assist
-//! implementation of [`RngCore`].
-//!
-//! [`rand`]: https://docs.rs/rand
-
-#![doc(
-    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
-    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
-    html_root_url = "https://rust-random.github.io/rand/"
-)]
-#![deny(missing_docs)]
-#![deny(missing_debug_implementations)]
-#![doc(test(attr(allow(unused_variables), deny(warnings))))]
-#![cfg_attr(docsrs, feature(doc_auto_cfg))]
-#![no_std]
-
-#[cfg(feature = "std")]
-extern crate std;
-
-use core::{fmt, ops::DerefMut};
-
-pub mod block;
-pub mod impls;
-pub mod le;
-#[cfg(feature = "os_rng")]
-mod os;
-
-#[cfg(feature = "os_rng")]
-pub use os::{OsError, OsRng};
-
-/// Implementation-level interface for RNGs
-///
-/// This trait encapsulates the low-level functionality common to all
-/// generators, and is the "back end", to be implemented by generators.
-/// End users should normally use the [`rand::Rng`] trait
-/// which is automatically implemented for every type implementing `RngCore`.
-///
-/// Three different methods for generating random data are provided since the
-/// optimal implementation of each is dependent on the type of generator. There
-/// is no required relationship between the output of each; e.g. many
-/// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64`
-/// values and drop any remaining unused bytes. The same can happen with the
-/// [`next_u32`] and [`next_u64`] methods, implementations may discard some
-/// random bits for efficiency.
-///
-/// Implementers should produce bits uniformly. Pathological RNGs (e.g. always
-/// returning the same value, or never setting certain bits) can break rejection
-/// sampling used by random distributions, and also break other RNGs when
-/// seeding them via [`SeedableRng::from_rng`].
-///
-/// Algorithmic generators implementing [`SeedableRng`] should normally have
-/// *portable, reproducible* output, i.e. fix Endianness when converting values
-/// to avoid platform differences, and avoid making any changes which affect
-/// output (except by communicating that the release has breaking changes).
-///
-/// Typically an RNG will implement only one of the methods available
-/// in this trait directly, then use the helper functions from the
-/// [`impls`] module to implement the other methods.
-///
-/// Note that implementors of [`RngCore`] also automatically implement
-/// the [`TryRngCore`] trait with the `Error` associated type being
-/// equal to [`Infallible`].
-///
-/// It is recommended that implementations also implement:
-///
-/// - `Debug` with a custom implementation which *does not* print any internal
-///   state (at least, [`CryptoRng`]s should not risk leaking state through
-///   `Debug`).
-/// - `Serialize` and `Deserialize` (from Serde), preferably making Serde
-///   support optional at the crate level in PRNG libs.
-/// - `Clone`, if possible.
-/// - *never* implement `Copy` (accidental copies may cause repeated values).
-/// - *do not* implement `Default` for pseudorandom generators, but instead
-///   implement [`SeedableRng`], to guide users towards proper seeding.
-///   External / hardware RNGs can choose to implement `Default`.
-/// - `Eq` and `PartialEq` could be implemented, but are probably not useful.
-///
-/// # Example
-///
-/// A simple example, obviously not generating very *random* output:
-///
-/// ```
-/// #![allow(dead_code)]
-/// use rand_core::{RngCore, impls};
-///
-/// struct CountingRng(u64);
-///
-/// impl RngCore for CountingRng {
-///     fn next_u32(&mut self) -> u32 {
-///         self.next_u64() as u32
-///     }
-///
-///     fn next_u64(&mut self) -> u64 {
-///         self.0 += 1;
-///         self.0
-///     }
-///
-///     fn fill_bytes(&mut self, dst: &mut [u8]) {
-///         impls::fill_bytes_via_next(self, dst)
-///     }
-/// }
-/// ```
-///
-/// [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html
-/// [`fill_bytes`]: RngCore::fill_bytes
-/// [`next_u32`]: RngCore::next_u32
-/// [`next_u64`]: RngCore::next_u64
-/// [`Infallible`]: core::convert::Infallible
-pub trait RngCore {
-    /// Return the next random `u32`.
-    ///
-    /// RNGs must implement at least one method from this trait directly. In
-    /// the case this method is not implemented directly, it can be implemented
-    /// using `self.next_u64() as u32` or via [`impls::next_u32_via_fill`].
-    fn next_u32(&mut self) -> u32;
-
-    /// Return the next random `u64`.
-    ///
-    /// RNGs must implement at least one method from this trait directly. In
-    /// the case this method is not implemented directly, it can be implemented
-    /// via [`impls::next_u64_via_u32`] or via [`impls::next_u64_via_fill`].
-    fn next_u64(&mut self) -> u64;
-
-    /// Fill `dest` with random data.
-    ///
-    /// RNGs must implement at least one method from this trait directly. In
-    /// the case this method is not implemented directly, it can be implemented
-    /// via [`impls::fill_bytes_via_next`].
-    ///
-    /// This method should guarantee that `dest` is entirely filled
-    /// with new data, and may panic if this is impossible
-    /// (e.g. reading past the end of a file that is being used as the
-    /// source of randomness).
-    fn fill_bytes(&mut self, dst: &mut [u8]);
-}
-
-impl<T: DerefMut> RngCore for T
-where
-    T::Target: RngCore,
-{
-    #[inline]
-    fn next_u32(&mut self) -> u32 {
-        self.deref_mut().next_u32()
-    }
-
-    #[inline]
-    fn next_u64(&mut self) -> u64 {
-        self.deref_mut().next_u64()
-    }
-
-    #[inline]
-    fn fill_bytes(&mut self, dst: &mut [u8]) {
-        self.deref_mut().fill_bytes(dst);
-    }
-}
-
-/// A marker trait over [`RngCore`] for securely unpredictable RNGs
-///
-/// This marker trait indicates that the implementing generator is intended,
-/// when correctly seeded and protected from side-channel attacks such as a
-/// leaking of state, to be a cryptographically secure generator. This trait is
-/// provided as a tool to aid review of cryptographic code, but does not by
-/// itself guarantee suitability for cryptographic applications.
-///
-/// Implementors of `CryptoRng` automatically implement the [`TryCryptoRng`]
-/// trait.
-///
-/// Implementors of `CryptoRng` should only implement [`Default`] if the
-/// `default()` instances are themselves secure generators: for example if the
-/// implementing type is a stateless interface over a secure external generator
-/// (like [`OsRng`]) or if the `default()` instance uses a strong, fresh seed.
-///
-/// Formally, a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator)
-/// should satisfy an additional property over other generators: assuming that
-/// the generator has been appropriately seeded and has unknown state, then
-/// given the first *k* bits of an algorithm's output
-/// sequence, it should not be possible using polynomial-time algorithms to
-/// predict the next bit with probability significantly greater than 50%.
-///
-/// An optional property of CSPRNGs is backtracking resistance: if the CSPRNG's
-/// state is revealed, it will not be computationally-feasible to reconstruct
-/// prior output values. This property is not required by `CryptoRng`.
-pub trait CryptoRng: RngCore {}
-
-impl<T: DerefMut> CryptoRng for T where T::Target: CryptoRng {}
-
-/// A potentially fallible variant of [`RngCore`]
-///
-/// This trait is a generalization of [`RngCore`] to support potentially-
-/// fallible IO-based generators such as [`OsRng`].
-///
-/// All implementations of [`RngCore`] automatically support this `TryRngCore`
-/// trait, using [`Infallible`][core::convert::Infallible] as the associated
-/// `Error` type.
-///
-/// An implementation of this trait may be made compatible with code requiring
-/// an [`RngCore`] through [`TryRngCore::unwrap_err`]. The resulting RNG will
-/// panic in case the underlying fallible RNG yields an error.
-pub trait TryRngCore {
-    /// The type returned in the event of a RNG error.
-    type Error: fmt::Debug + fmt::Display;
-
-    /// Return the next random `u32`.
-    fn try_next_u32(&mut self) -> Result<u32, Self::Error>;
-    /// Return the next random `u64`.
-    fn try_next_u64(&mut self) -> Result<u64, Self::Error>;
-    /// Fill `dest` entirely with random data.
-    fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error>;
-
-    /// Wrap RNG with the [`UnwrapErr`] wrapper.
-    fn unwrap_err(self) -> UnwrapErr<Self>
-    where
-        Self: Sized,
-    {
-        UnwrapErr(self)
-    }
-
-    /// Wrap RNG with the [`UnwrapMut`] wrapper.
-    fn unwrap_mut(&mut self) -> UnwrapMut<'_, Self> {
-        UnwrapMut(self)
-    }
-
-    /// Convert an [`RngCore`] to a [`RngReadAdapter`].
-    #[cfg(feature = "std")]
-    fn read_adapter(&mut self) -> RngReadAdapter<'_, Self>
-    where
-        Self: Sized,
-    {
-        RngReadAdapter { inner: self }
-    }
-}
-
-// Note that, unfortunately, this blanket impl prevents us from implementing
-// `TryRngCore` for types which can be dereferenced to `TryRngCore`, i.e. `TryRngCore`
-// will not be automatically implemented for `&mut R`, `Box<R>`, etc.
-impl<R: RngCore + ?Sized> TryRngCore for R {
-    type Error = core::convert::Infallible;
-
-    #[inline]
-    fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
-        Ok(self.next_u32())
-    }
-
-    #[inline]
-    fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
-        Ok(self.next_u64())
-    }
-
-    #[inline]
-    fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
-        self.fill_bytes(dst);
-        Ok(())
-    }
-}
-
-/// A marker trait over [`TryRngCore`] for securely unpredictable RNGs
-///
-/// This trait is like [`CryptoRng`] but for the trait [`TryRngCore`].
-///
-/// This marker trait indicates that the implementing generator is intended,
-/// when correctly seeded and protected from side-channel attacks such as a
-/// leaking of state, to be a cryptographically secure generator. This trait is
-/// provided as a tool to aid review of cryptographic code, but does not by
-/// itself guarantee suitability for cryptographic applications.
-///
-/// Implementors of `TryCryptoRng` should only implement [`Default`] if the
-/// `default()` instances are themselves secure generators: for example if the
-/// implementing type is a stateless interface over a secure external generator
-/// (like [`OsRng`]) or if the `default()` instance uses a strong, fresh seed.
-pub trait TryCryptoRng: TryRngCore {}
-
-impl<R: CryptoRng + ?Sized> TryCryptoRng for R {}
-
-/// Wrapper around [`TryRngCore`] implementation which implements [`RngCore`]
-/// by panicking on potential errors.
-#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
-pub struct UnwrapErr<R: TryRngCore>(pub R);
-
-impl<R: TryRngCore> RngCore for UnwrapErr<R> {
-    #[inline]
-    fn next_u32(&mut self) -> u32 {
-        self.0.try_next_u32().unwrap()
-    }
-
-    #[inline]
-    fn next_u64(&mut self) -> u64 {
-        self.0.try_next_u64().unwrap()
-    }
-
-    #[inline]
-    fn fill_bytes(&mut self, dst: &mut [u8]) {
-        self.0.try_fill_bytes(dst).unwrap()
-    }
-}
-
-impl<R: TryCryptoRng> CryptoRng for UnwrapErr<R> {}
-
-/// Wrapper around [`TryRngCore`] implementation which implements [`RngCore`]
-/// by panicking on potential errors.
-#[derive(Debug, Eq, PartialEq, Hash)]
-pub struct UnwrapMut<'r, R: TryRngCore + ?Sized>(pub &'r mut R);
-
-impl<'r, R: TryRngCore + ?Sized> UnwrapMut<'r, R> {
-    /// Reborrow with a new lifetime
-    ///
-    /// Rust allows references like `&T` or `&mut T` to be "reborrowed" through
-    /// coercion: essentially, the pointer is copied under a new, shorter, lifetime.
-    /// Until rfcs#1403 lands, reborrows on user types require a method call.
-    #[inline(always)]
-    pub fn re<'b>(&'b mut self) -> UnwrapMut<'b, R>
-    where
-        'r: 'b,
-    {
-        UnwrapMut(self.0)
-    }
-}
-
-impl<R: TryRngCore + ?Sized> RngCore for UnwrapMut<'_, R> {
-    #[inline]
-    fn next_u32(&mut self) -> u32 {
-        self.0.try_next_u32().unwrap()
-    }
-
-    #[inline]
-    fn next_u64(&mut self) -> u64 {
-        self.0.try_next_u64().unwrap()
-    }
-
-    #[inline]
-    fn fill_bytes(&mut self, dst: &mut [u8]) {
-        self.0.try_fill_bytes(dst).unwrap()
-    }
-}
-
-impl<R: TryCryptoRng + ?Sized> CryptoRng for UnwrapMut<'_, R> {}
-
-/// A random number generator that can be explicitly seeded.
-///
-/// This trait encapsulates the low-level functionality common to all
-/// pseudo-random number generators (PRNGs, or algorithmic generators).
-///
-/// A generator implementing `SeedableRng` will usually be deterministic, but
-/// beware that portability and reproducibility of results **is not implied**.
-/// Refer to documentation of the generator, noting that generators named after
-/// a specific algorithm are usually tested for reproducibility against a
-/// reference vector, while `SmallRng` and `StdRng` specifically opt out of
-/// reproducibility guarantees.
-///
-/// [`rand`]: https://docs.rs/rand
-pub trait SeedableRng: Sized {
-    /// Seed type, which is restricted to types mutably-dereferenceable as `u8`
-    /// arrays (we recommend `[u8; N]` for some `N`).
-    ///
-    /// It is recommended to seed PRNGs with a seed of at least circa 100 bits,
-    /// which means an array of `[u8; 12]` or greater to avoid picking RNGs with
-    /// partially overlapping periods.
-    ///
-    /// For cryptographic RNG's a seed of 256 bits is recommended, `[u8; 32]`.
-    ///
-    ///
-    /// # Implementing `SeedableRng` for RNGs with large seeds
-    ///
-    /// Note that [`Default`] is not implemented for large arrays `[u8; N]` with
-    /// `N` > 32. To be able to implement the traits required by `SeedableRng`
-    /// for RNGs with such large seeds, the newtype pattern can be used:
-    ///
-    /// ```
-    /// use rand_core::SeedableRng;
-    ///
-    /// const N: usize = 64;
-    /// #[derive(Clone)]
-    /// pub struct MyRngSeed(pub [u8; N]);
-    /// # #[allow(dead_code)]
-    /// pub struct MyRng(MyRngSeed);
-    ///
-    /// impl Default for MyRngSeed {
-    ///     fn default() -> MyRngSeed {
-    ///         MyRngSeed([0; N])
-    ///     }
-    /// }
-    ///
-    /// impl AsRef<[u8]> for MyRngSeed {
-    ///     fn as_ref(&self) -> &[u8] {
-    ///         &self.0
-    ///     }
-    /// }
-    ///
-    /// impl AsMut<[u8]> for MyRngSeed {
-    ///     fn as_mut(&mut self) -> &mut [u8] {
-    ///         &mut self.0
-    ///     }
-    /// }
-    ///
-    /// impl SeedableRng for MyRng {
-    ///     type Seed = MyRngSeed;
-    ///
-    ///     fn from_seed(seed: MyRngSeed) -> MyRng {
-    ///         MyRng(seed)
-    ///     }
-    /// }
-    /// ```
-    type Seed: Clone + Default + AsRef<[u8]> + AsMut<[u8]>;
-
-    /// Create a new PRNG using the given seed.
-    ///
-    /// PRNG implementations are allowed to assume that bits in the seed are
-    /// well distributed. That means usually that the number of one and zero
-    /// bits are roughly equal, and values like 0, 1 and (size - 1) are unlikely.
-    /// Note that many non-cryptographic PRNGs will show poor quality output
-    /// if this is not adhered to. If you wish to seed from simple numbers, use
-    /// `seed_from_u64` instead.
-    ///
-    /// All PRNG implementations should be reproducible unless otherwise noted:
-    /// given a fixed `seed`, the same sequence of output should be produced
-    /// on all runs, library versions and architectures (e.g. check endianness).
-    /// Any "value-breaking" changes to the generator should require bumping at
-    /// least the minor version and documentation of the change.
-    ///
-    /// It is not required that this function yield the same state as a
-    /// reference implementation of the PRNG given equivalent seed; if necessary
-    /// another constructor replicating behaviour from a reference
-    /// implementation can be added.
-    ///
-    /// PRNG implementations should make sure `from_seed` never panics. In the
-    /// case that some special values (like an all zero seed) are not viable
-    /// seeds it is preferable to map these to alternative constant value(s),
-    /// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad
-    /// seed"). This is assuming only a small number of values must be rejected.
-    fn from_seed(seed: Self::Seed) -> Self;
-
-    /// Create a new PRNG using a `u64` seed.
-    ///
-    /// This is a convenience-wrapper around `from_seed` to allow construction
-    /// of any `SeedableRng` from a simple `u64` value. It is designed such that
-    /// low Hamming Weight numbers like 0 and 1 can be used and should still
-    /// result in good, independent seeds to the PRNG which is returned.
-    ///
-    /// This **is not suitable for cryptography**, as should be clear given that
-    /// the input size is only 64 bits.
-    ///
-    /// Implementations for PRNGs *may* provide their own implementations of
-    /// this function, but the default implementation should be good enough for
-    /// all purposes. *Changing* the implementation of this function should be
-    /// considered a value-breaking change.
-    fn seed_from_u64(mut state: u64) -> Self {
-        // We use PCG32 to generate a u32 sequence, and copy to the seed
-        fn pcg32(state: &mut u64) -> [u8; 4] {
-            const MUL: u64 = 6364136223846793005;
-            const INC: u64 = 11634580027462260723;
-
-            // We advance the state first (to get away from the input value,
-            // in case it has low Hamming Weight).
-            *state = state.wrapping_mul(MUL).wrapping_add(INC);
-            let state = *state;
-
-            // Use PCG output function with to_le to generate x:
-            let xorshifted = (((state >> 18) ^ state) >> 27) as u32;
-            let rot = (state >> 59) as u32;
-            let x = xorshifted.rotate_right(rot);
-            x.to_le_bytes()
-        }
-
-        let mut seed = Self::Seed::default();
-        let mut iter = seed.as_mut().chunks_exact_mut(4);
-        for chunk in &mut iter {
-            chunk.copy_from_slice(&pcg32(&mut state));
-        }
-        let rem = iter.into_remainder();
-        if !rem.is_empty() {
-            rem.copy_from_slice(&pcg32(&mut state)[..rem.len()]);
-        }
-
-        Self::from_seed(seed)
-    }
-
-    /// Create a new PRNG seeded from an infallible `Rng`.
-    ///
-    /// This may be useful when needing to rapidly seed many PRNGs from a master
-    /// PRNG, and to allow forking of PRNGs. It may be considered deterministic.
-    ///
-    /// The master PRNG should be at least as high quality as the child PRNGs.
-    /// When seeding non-cryptographic child PRNGs, we recommend using a
-    /// different algorithm for the master PRNG (ideally a CSPRNG) to avoid
-    /// correlations between the child PRNGs. If this is not possible (e.g.
-    /// forking using small non-crypto PRNGs) ensure that your PRNG has a good
-    /// mixing function on the output or consider use of a hash function with
-    /// `from_seed`.
-    ///
-    /// Note that seeding `XorShiftRng` from another `XorShiftRng` provides an
-    /// extreme example of what can go wrong: the new PRNG will be a clone
-    /// of the parent.
-    ///
-    /// PRNG implementations are allowed to assume that a good RNG is provided
-    /// for seeding, and that it is cryptographically secure when appropriate.
-    /// As of `rand` 0.7 / `rand_core` 0.5, implementations overriding this
-    /// method should ensure the implementation satisfies reproducibility
-    /// (in prior versions this was not required).
-    ///
-    /// [`rand`]: https://docs.rs/rand
-    fn from_rng(rng: &mut impl RngCore) -> Self {
-        let mut seed = Self::Seed::default();
-        rng.fill_bytes(seed.as_mut());
-        Self::from_seed(seed)
-    }
-
-    /// Create a new PRNG seeded from a potentially fallible `Rng`.
-    ///
-    /// See [`from_rng`][SeedableRng::from_rng] docs for more information.
-    fn try_from_rng<R: TryRngCore>(rng: &mut R) -> Result<Self, R::Error> {
-        let mut seed = Self::Seed::default();
-        rng.try_fill_bytes(seed.as_mut())?;
-        Ok(Self::from_seed(seed))
-    }
-
-    /// Creates a new instance of the RNG seeded via [`getrandom`].
-    ///
-    /// This method is the recommended way to construct non-deterministic PRNGs
-    /// since it is convenient and secure.
-    ///
-    /// Note that this method may panic on (extremely unlikely) [`getrandom`] errors.
-    /// If it's not desirable, use the [`try_from_os_rng`] method instead.
-    ///
-    /// In case the overhead of using [`getrandom`] to seed *many* PRNGs is an
-    /// issue, one may prefer to seed from a local PRNG, e.g.
-    /// `from_rng(rand::rng()).unwrap()`.
-    ///
-    /// # Panics
-    ///
-    /// If [`getrandom`] is unable to provide secure entropy this method will panic.
-    ///
-    /// [`getrandom`]: https://docs.rs/getrandom
-    /// [`try_from_os_rng`]: SeedableRng::try_from_os_rng
-    #[cfg(feature = "os_rng")]
-    fn from_os_rng() -> Self {
-        match Self::try_from_os_rng() {
-            Ok(res) => res,
-            Err(err) => panic!("from_os_rng failed: {}", err),
-        }
-    }
-
-    /// Creates a new instance of the RNG seeded via [`getrandom`] without unwrapping
-    /// potential [`getrandom`] errors.
-    ///
-    /// In case the overhead of using [`getrandom`] to seed *many* PRNGs is an
-    /// issue, one may prefer to seed from a local PRNG, e.g.
-    /// `from_rng(&mut rand::rng()).unwrap()`.
-    ///
-    /// [`getrandom`]: https://docs.rs/getrandom
-    #[cfg(feature = "os_rng")]
-    fn try_from_os_rng() -> Result<Self, getrandom::Error> {
-        let mut seed = Self::Seed::default();
-        getrandom::fill(seed.as_mut())?;
-        let res = Self::from_seed(seed);
-        Ok(res)
-    }
-}
-
-/// Adapter that enables reading through a [`io::Read`](std::io::Read) from a [`RngCore`].
-///
-/// # Examples
-///
-/// ```no_run
-/// # use std::{io, io::Read};
-/// # use std::fs::File;
-/// # use rand_core::{OsRng, TryRngCore};
-///
-/// io::copy(&mut OsRng.read_adapter().take(100), &mut File::create("/tmp/random.bytes").unwrap()).unwrap();
-/// ```
-#[cfg(feature = "std")]
-pub struct RngReadAdapter<'a, R: TryRngCore + ?Sized> {
-    inner: &'a mut R,
-}
-
-#[cfg(feature = "std")]
-impl<R: TryRngCore + ?Sized> std::io::Read for RngReadAdapter<'_, R> {
-    #[inline]
-    fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
-        self.inner.try_fill_bytes(buf).map_err(|err| {
-            std::io::Error::new(std::io::ErrorKind::Other, std::format!("RNG error: {err}"))
-        })?;
-        Ok(buf.len())
-    }
-}
-
-#[cfg(feature = "std")]
-impl<R: TryRngCore + ?Sized> std::fmt::Debug for RngReadAdapter<'_, R> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("ReadAdapter").finish()
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_seed_from_u64() {
-        struct SeedableNum(u64);
-        impl SeedableRng for SeedableNum {
-            type Seed = [u8; 8];
-
-            fn from_seed(seed: Self::Seed) -> Self {
-                let mut x = [0u64; 1];
-                le::read_u64_into(&seed, &mut x);
-                SeedableNum(x[0])
-            }
-        }
-
-        const N: usize = 8;
-        const SEEDS: [u64; N] = [0u64, 1, 2, 3, 4, 8, 16, -1i64 as u64];
-        let mut results = [0u64; N];
-        for (i, seed) in SEEDS.iter().enumerate() {
-            let SeedableNum(x) = SeedableNum::seed_from_u64(*seed);
-            results[i] = x;
-        }
-
-        for (i1, r1) in results.iter().enumerate() {
-            let weight = r1.count_ones();
-            // This is the binomial distribution B(64, 0.5), so chance of
-            // weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for
-            // weight > 44.
-            assert!((20..=44).contains(&weight));
-
-            for (i2, r2) in results.iter().enumerate() {
-                if i1 == i2 {
-                    continue;
-                }
-                let diff_weight = (r1 ^ r2).count_ones();
-                assert!(diff_weight >= 20);
-            }
-        }
-
-        // value-breakage test:
-        assert_eq!(results[0], 5029875928683246316);
-    }
-
-    // A stub RNG.
-    struct SomeRng;
-
-    impl RngCore for SomeRng {
-        fn next_u32(&mut self) -> u32 {
-            unimplemented!()
-        }
-        fn next_u64(&mut self) -> u64 {
-            unimplemented!()
-        }
-        fn fill_bytes(&mut self, _: &mut [u8]) {
-            unimplemented!()
-        }
-    }
-
-    impl CryptoRng for SomeRng {}
-
-    #[test]
-    fn dyn_rngcore_to_tryrngcore() {
-        // Illustrates the need for `+ ?Sized` bound in `impl<R: RngCore> TryRngCore for R`.
-
-        // A method in another crate taking a fallible RNG
-        fn third_party_api(_rng: &mut (impl TryRngCore + ?Sized)) -> bool {
-            true
-        }
-
-        // A method in our crate requiring an infallible RNG
-        fn my_api(rng: &mut dyn RngCore) -> bool {
-            // We want to call the method above
-            third_party_api(rng)
-        }
-
-        assert!(my_api(&mut SomeRng));
-    }
-
-    #[test]
-    fn dyn_cryptorng_to_trycryptorng() {
-        // Illustrates the need for `+ ?Sized` bound in `impl<R: CryptoRng> TryCryptoRng for R`.
-
-        // A method in another crate taking a fallible RNG
-        fn third_party_api(_rng: &mut (impl TryCryptoRng + ?Sized)) -> bool {
-            true
-        }
-
-        // A method in our crate requiring an infallible RNG
-        fn my_api(rng: &mut dyn CryptoRng) -> bool {
-            // We want to call the method above
-            third_party_api(rng)
-        }
-
-        assert!(my_api(&mut SomeRng));
-    }
-
-    #[test]
-    fn dyn_unwrap_mut_tryrngcore() {
-        // Illustrates the need for `+ ?Sized` bound in
-        // `impl<R: TryRngCore> RngCore for UnwrapMut<'_, R>`.
-
-        fn third_party_api(_rng: &mut impl RngCore) -> bool {
-            true
-        }
-
-        fn my_api(rng: &mut (impl TryRngCore + ?Sized)) -> bool {
-            let mut infallible_rng = rng.unwrap_mut();
-            third_party_api(&mut infallible_rng)
-        }
-
-        assert!(my_api(&mut SomeRng));
-    }
-
-    #[test]
-    fn dyn_unwrap_mut_trycryptorng() {
-        // Illustrates the need for `+ ?Sized` bound in
-        // `impl<R: TryCryptoRng> CryptoRng for UnwrapMut<'_, R>`.
-
-        fn third_party_api(_rng: &mut impl CryptoRng) -> bool {
-            true
-        }
-
-        fn my_api(rng: &mut (impl TryCryptoRng + ?Sized)) -> bool {
-            let mut infallible_rng = rng.unwrap_mut();
-            third_party_api(&mut infallible_rng)
-        }
-
-        assert!(my_api(&mut SomeRng));
-    }
-
-    #[test]
-    fn reborrow_unwrap_mut() {
-        struct FourRng;
-
-        impl TryRngCore for FourRng {
-            type Error = core::convert::Infallible;
-            fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
-                Ok(4)
-            }
-            fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
-                unimplemented!()
-            }
-            fn try_fill_bytes(&mut self, _: &mut [u8]) -> Result<(), Self::Error> {
-                unimplemented!()
-            }
-        }
-
-        let mut rng = FourRng;
-        let mut rng = rng.unwrap_mut();
-
-        assert_eq!(rng.next_u32(), 4);
-        let mut rng2 = rng.re();
-        assert_eq!(rng2.next_u32(), 4);
-        drop(rng2);
-        assert_eq!(rng.next_u32(), 4);
-    }
-}
diff --git a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/os.rs b/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/os.rs
deleted file mode 100644
index 49111632..0000000
--- a/third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/os.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2019 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Interface to the random number generator of the operating system.
-
-use crate::{TryCryptoRng, TryRngCore};
-
-/// An interface over the operating-system's random data source
-///
-/// This is a zero-sized struct. It can be freely constructed with just `OsRng`.
-///
-/// The implementation is provided by the [getrandom] crate. Refer to
-/// [getrandom] documentation for details.
-///
-/// This struct is available as `rand_core::OsRng` and as `rand::rngs::OsRng`.
-/// In both cases, this requires the crate feature `os_rng` or `std`
-/// (enabled by default in `rand` but not in `rand_core`).
-///
-/// # Blocking and error handling
-///
-/// It is possible that when used during early boot the first call to `OsRng`
-/// will block until the system's RNG is initialised. It is also possible
-/// (though highly unlikely) for `OsRng` to fail on some platforms, most
-/// likely due to system mis-configuration.
-///
-/// After the first successful call, it is highly unlikely that failures or
-/// significant delays will occur (although performance should be expected to
-/// be much slower than a user-space
-/// [PRNG](https://rust-random.github.io/book/guide-gen.html#pseudo-random-number-generators)).
-///
-/// # Usage example
-/// ```
-/// use rand_core::{TryRngCore, OsRng};
-///
-/// let mut key = [0u8; 16];
-/// OsRng.try_fill_bytes(&mut key).unwrap();
-/// let random_u64 = OsRng.try_next_u64().unwrap();
-/// ```
-///
-/// [getrandom]: https://crates.io/crates/getrandom
-#[derive(Clone, Copy, Debug, Default)]
-pub struct OsRng;
-
-/// Error type of [`OsRng`]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct OsError(getrandom::Error);
-
-impl core::fmt::Display for OsError {
-    #[inline]
-    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
-// NOTE: this can use core::error::Error from rustc 1.81.0
-#[cfg(feature = "std")]
-impl std::error::Error for OsError {
-    #[inline]
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        std::error::Error::source(&self.0)
-    }
-}
-
-impl OsError {
-    /// Extract the raw OS error code (if this error came from the OS)
-    ///
-    /// This method is identical to [`std::io::Error::raw_os_error()`][1], except
-    /// that it works in `no_std` contexts. If this method returns `None`, the
-    /// error value can still be formatted via the `Display` implementation.
-    ///
-    /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
-    #[inline]
-    pub fn raw_os_error(self) -> Option<i32> {
-        self.0.raw_os_error()
-    }
-}
-
-impl TryRngCore for OsRng {
-    type Error = OsError;
-
-    #[inline]
-    fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
-        getrandom::u32().map_err(OsError)
-    }
-
-    #[inline]
-    fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
-        getrandom::u64().map_err(OsError)
-    }
-
-    #[inline]
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
-        getrandom::fill(dest).map_err(OsError)
-    }
-}
-
-impl TryCryptoRng for OsRng {}
-
-#[test]
-fn test_os_rng() {
-    let x = OsRng.try_next_u64().unwrap();
-    let y = OsRng.try_next_u64().unwrap();
-    assert!(x != 0);
-    assert!(x != y);
-}
-
-#[test]
-fn test_construction() {
-    assert!(OsRng.try_next_u64().unwrap() != 0);
-}
diff --git a/third_party/rust/crc32fast/OWNERS b/third_party/rust/crc32fast/OWNERS
new file mode 100644
index 0000000..07bd9a4
--- /dev/null
+++ b/third_party/rust/crc32fast/OWNERS
@@ -0,0 +1,2 @@
+# This crate has been brought in as a dependency of the `png` crate.
+file://third_party/rust/png/OWNERS
diff --git a/third_party/rust/cxx/OWNERS b/third_party/rust/cxx/OWNERS
new file mode 100644
index 0000000..59c22b3d
--- /dev/null
+++ b/third_party/rust/cxx/OWNERS
@@ -0,0 +1,5 @@
+# If `enable_rust_cxx` is set to true, then `//build/rust` provides
+# integration of `cxx` with Chromium's build system.  See for example
+# `cxx_bindings` property of the `rust_static_library` template from
+# `//build/rust/rust_static_library.gni`.
+file://build/rust/OWNERS
diff --git a/third_party/rust/cxxbridge_cmd/OWNERS b/third_party/rust/cxxbridge_cmd/OWNERS
new file mode 100644
index 0000000..1b8e379e
--- /dev/null
+++ b/third_party/rust/cxxbridge_cmd/OWNERS
@@ -0,0 +1 @@
+file://third_party/rust/cxx/OWNERS
diff --git a/third_party/rust/cxxbridge_flags/OWNERS b/third_party/rust/cxxbridge_flags/OWNERS
new file mode 100644
index 0000000..1b8e379e
--- /dev/null
+++ b/third_party/rust/cxxbridge_flags/OWNERS
@@ -0,0 +1 @@
+file://third_party/rust/cxx/OWNERS
diff --git a/third_party/rust/cxxbridge_macro/OWNERS b/third_party/rust/cxxbridge_macro/OWNERS
new file mode 100644
index 0000000..1b8e379e
--- /dev/null
+++ b/third_party/rust/cxxbridge_macro/OWNERS
@@ -0,0 +1 @@
+file://third_party/rust/cxx/OWNERS
diff --git a/third_party/rust/derivre/OWNERS b/third_party/rust/derivre/OWNERS
new file mode 100644
index 0000000..608b65a
--- /dev/null
+++ b/third_party/rust/derivre/OWNERS
@@ -0,0 +1,4 @@
+# `derivre` crate has been brought into `chromium_crates_io` as a dependency
+# of the `llguidance` crate.  `derivre` is maintained by the same GitHub org
+# as `llguidance`: https://github.com/guidance-ai/derivre
+file://third_party/rust/llguidance/OWNERS
diff --git a/third_party/rust/fdeflate/OWNERS b/third_party/rust/fdeflate/OWNERS
new file mode 100644
index 0000000..07bd9a4
--- /dev/null
+++ b/third_party/rust/fdeflate/OWNERS
@@ -0,0 +1,2 @@
+# This crate has been brought in as a dependency of the `png` crate.
+file://third_party/rust/png/OWNERS
diff --git a/third_party/rust/ff/v0_13/BUILD.gn b/third_party/rust/ff/v0_13/BUILD.gn
deleted file mode 100644
index c8bacdb..0000000
--- a/third_party/rust/ff/v0_13/BUILD.gn
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 2023 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
-# tools/crates/gnrt.
-# Do not edit!
-
-import("//build/rust/cargo_crate.gni")
-
-cargo_crate("lib") {
-  crate_name = "ff"
-  epoch = "0.13"
-  crate_type = "rlib"
-  crate_root =
-      "//third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/lib.rs"
-  sources = [
-    "//third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/batch.rs",
-    "//third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/helpers.rs",
-    "//third_party/rust/chromium_crates_io/vendor/ff-v0_13/src/lib.rs",
-  ]
-  inputs = []
-
-  build_native_rust_unit_tests = false
-  edition = "2021"
-  cargo_pkg_version = "0.13.1"
-  cargo_pkg_authors =
-      "Sean Bowe <ewillbefull@gmail.com>, Jack Grigg <thestr4d@gmail.com>"
-  cargo_pkg_name = "ff"
-  cargo_pkg_description =
-      "Library for building and interfacing with finite fields"
-  library_configs -= [ "//build/config/coverage:default_coverage" ]
-  library_configs -= [ "//build/config/compiler:chromium_code" ]
-  library_configs += [ "//build/config/compiler:no_chromium_code" ]
-  executable_configs -= [ "//build/config/compiler:chromium_code" ]
-  executable_configs += [ "//build/config/compiler:no_chromium_code" ]
-  proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
-  proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [
-    "//third_party/rust/rand_core/v0_9:lib",
-    "//third_party/rust/subtle/v2:lib",
-  ]
-  rustflags = [
-    "--cap-lints=allow",  # Suppress all warnings in crates.io crates
-  ]
-
-  # Only for usage from third-party crates. Add the crate to
-  # //third_party/rust/chromium_crates_io/Cargo.toml to use
-  # it from first-party code.
-  visibility = [ "//third_party/rust/*" ]
-}
diff --git a/third_party/rust/ff/v0_13/README.chromium b/third_party/rust/ff/v0_13/README.chromium
deleted file mode 100644
index 34665e5..0000000
--- a/third_party/rust/ff/v0_13/README.chromium
+++ /dev/null
@@ -1,10 +0,0 @@
-Name: ff
-URL: https://crates.io/crates/ff
-Version: 0.13.1
-Revision: 851b0f61bbcf9a5b61027307144d8bd1f9b756ba
-License: Apache-2.0
-License File: //third_party/rust/chromium_crates_io/vendor/ff-v0_13/LICENSE-APACHE
-Shipped: yes
-Security Critical: yes
-
-Description: Library for building and interfacing with finite fields
diff --git a/third_party/rust/flate2/OWNERS b/third_party/rust/flate2/OWNERS
new file mode 100644
index 0000000..07bd9a4
--- /dev/null
+++ b/third_party/rust/flate2/OWNERS
@@ -0,0 +1,2 @@
+# This crate has been brought in as a dependency of the `png` crate.
+file://third_party/rust/png/OWNERS
diff --git a/third_party/rust/group/v0_13/BUILD.gn b/third_party/rust/group/v0_13/BUILD.gn
deleted file mode 100644
index 4abe78d..0000000
--- a/third_party/rust/group/v0_13/BUILD.gn
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2023 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
-# tools/crates/gnrt.
-# Do not edit!
-
-import("//build/rust/cargo_crate.gni")
-
-cargo_crate("lib") {
-  crate_name = "group"
-  epoch = "0.13"
-  crate_type = "rlib"
-  crate_root =
-      "//third_party/rust/chromium_crates_io/vendor/group-v0_13/src/lib.rs"
-  sources = [
-    "//third_party/rust/chromium_crates_io/vendor/group-v0_13/src/cofactor.rs",
-    "//third_party/rust/chromium_crates_io/vendor/group-v0_13/src/lib.rs",
-    "//third_party/rust/chromium_crates_io/vendor/group-v0_13/src/prime.rs",
-    "//third_party/rust/chromium_crates_io/vendor/group-v0_13/src/tests/mod.rs",
-    "//third_party/rust/chromium_crates_io/vendor/group-v0_13/src/wnaf.rs",
-  ]
-  inputs = []
-
-  build_native_rust_unit_tests = false
-  edition = "2021"
-  cargo_pkg_version = "0.13.0"
-  cargo_pkg_authors =
-      "Sean Bowe <ewillbefull@gmail.com>, Jack Grigg <jack@z.cash>"
-  cargo_pkg_name = "group"
-  cargo_pkg_description = "Elliptic curve group traits and utilities"
-  library_configs -= [ "//build/config/coverage:default_coverage" ]
-  library_configs -= [ "//build/config/compiler:chromium_code" ]
-  library_configs += [ "//build/config/compiler:no_chromium_code" ]
-  executable_configs -= [ "//build/config/compiler:chromium_code" ]
-  executable_configs += [ "//build/config/compiler:no_chromium_code" ]
-  proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
-  proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [
-    "//third_party/rust/ff/v0_13:lib",
-    "//third_party/rust/rand_core/v0_9:lib",
-    "//third_party/rust/subtle/v2:lib",
-  ]
-  features = [
-    "alloc",
-    "default",
-  ]
-  rustflags = [
-    "--cap-lints=allow",  # Suppress all warnings in crates.io crates
-  ]
-}
diff --git a/third_party/rust/group/v0_13/README.chromium b/third_party/rust/group/v0_13/README.chromium
deleted file mode 100644
index 8f2a4c7..0000000
--- a/third_party/rust/group/v0_13/README.chromium
+++ /dev/null
@@ -1,10 +0,0 @@
-Name: group
-URL: https://crates.io/crates/group
-Version: 0.13.0
-Revision: 090a7ec2f2fca9b4ddec05e39123e57dc0d73a2f
-License: Apache-2.0
-License File: //third_party/rust/chromium_crates_io/vendor/group-v0_13/LICENSE-APACHE
-Shipped: yes
-Security Critical: yes
-
-Description: Elliptic curve group traits and utilities
diff --git a/third_party/rust/iana_time_zone/v0_1/BUILD.gn b/third_party/rust/iana_time_zone/v0_1/BUILD.gn
index 0d656a6..f3c62e6 100644
--- a/third_party/rust/iana_time_zone/v0_1/BUILD.gn
+++ b/third_party/rust/iana_time_zone/v0_1/BUILD.gn
@@ -49,7 +49,7 @@
   if (is_android) {
     deps += [ "//third_party/rust/android_system_properties/v0_1:lib" ]
   }
-  if (is_apple) {
+  if (is_ios || is_mac) {
     deps += [ "//third_party/rust/core_foundation_sys/v0_8:lib" ]
   }
   if (is_win) {
diff --git a/third_party/rust/llguidance/OWNERS b/third_party/rust/llguidance/OWNERS
new file mode 100644
index 0000000..0cb141dc
--- /dev/null
+++ b/third_party/rust/llguidance/OWNERS
@@ -0,0 +1 @@
+file://services/on_device_model/OWNERS
diff --git a/third_party/rust/miniz_oxide/OWNERS b/third_party/rust/miniz_oxide/OWNERS
new file mode 100644
index 0000000..07bd9a4
--- /dev/null
+++ b/third_party/rust/miniz_oxide/OWNERS
@@ -0,0 +1,2 @@
+# This crate has been brought in as a dependency of the `png` crate.
+file://third_party/rust/png/OWNERS
diff --git a/third_party/rust/png/OWNERS b/third_party/rust/png/OWNERS
new file mode 100644
index 0000000..985ccfb
--- /dev/null
+++ b/third_party/rust/png/OWNERS
@@ -0,0 +1,6 @@
+# Owner of the go/rusty-png-in-chromium-and-skia project.
+lukasza@chromium.org
+
+# PNG codec owners from Skia.
+fmalita@chromium.org
+danieldilan@google.com
diff --git a/third_party/rust/qr_code/OWNERS b/third_party/rust/qr_code/OWNERS
new file mode 100644
index 0000000..a0a6900
--- /dev/null
+++ b/third_party/rust/qr_code/OWNERS
@@ -0,0 +1 @@
+file://components/qr_code_generator/OWNERS
diff --git a/third_party/rust/rand_core/v0_9/BUILD.gn b/third_party/rust/rand_core/v0_9/BUILD.gn
deleted file mode 100644
index ef1f2db..0000000
--- a/third_party/rust/rand_core/v0_9/BUILD.gn
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2023 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
-# tools/crates/gnrt.
-# Do not edit!
-
-import("//build/rust/cargo_crate.gni")
-
-cargo_crate("lib") {
-  crate_name = "rand_core"
-  epoch = "0.9"
-  crate_type = "rlib"
-  crate_root =
-      "//third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/lib.rs"
-  sources = [
-    "//third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/block.rs",
-    "//third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/impls.rs",
-    "//third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/le.rs",
-    "//third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/lib.rs",
-    "//third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/src/os.rs",
-  ]
-  inputs = []
-
-  build_native_rust_unit_tests = false
-  edition = "2021"
-  cargo_pkg_version = "0.9.3"
-  cargo_pkg_authors = "The Rand Project Developers, The Rust Project Developers"
-  cargo_pkg_name = "rand_core"
-  cargo_pkg_description =
-      "Core random number generator traits and tools for implementation."
-  library_configs -= [ "//build/config/coverage:default_coverage" ]
-  library_configs -= [ "//build/config/compiler:chromium_code" ]
-  library_configs += [ "//build/config/compiler:no_chromium_code" ]
-  executable_configs -= [ "//build/config/compiler:chromium_code" ]
-  executable_configs += [ "//build/config/compiler:no_chromium_code" ]
-  proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
-  proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  rustflags = [
-    "--cap-lints=allow",  # Suppress all warnings in crates.io crates
-  ]
-}
diff --git a/third_party/rust/rand_core/v0_9/README.chromium b/third_party/rust/rand_core/v0_9/README.chromium
deleted file mode 100644
index 5d28d32..0000000
--- a/third_party/rust/rand_core/v0_9/README.chromium
+++ /dev/null
@@ -1,11 +0,0 @@
-Name: rand_core
-URL: https://crates.io/crates/rand_core
-Version: 0.9.3
-Revision: 340849e53b71da0f15af448d10511c2e62e50ba1
-License: Apache-2.0
-License File: //third_party/rust/chromium_crates_io/vendor/rand_core-v0_9/LICENSE-APACHE
-Shipped: yes
-Security Critical: yes
-
-Description: Core random number generator traits and tools for implementation.
-
diff --git a/third_party/rust/simd_adler32/OWNERS b/third_party/rust/simd_adler32/OWNERS
new file mode 100644
index 0000000..07bd9a4
--- /dev/null
+++ b/third_party/rust/simd_adler32/OWNERS
@@ -0,0 +1,2 @@
+# This crate has been brought in as a dependency of the `png` crate.
+file://third_party/rust/png/OWNERS
diff --git a/third_party/rust/toktrie/OWNERS b/third_party/rust/toktrie/OWNERS
new file mode 100644
index 0000000..30eb84c3
--- /dev/null
+++ b/third_party/rust/toktrie/OWNERS
@@ -0,0 +1,4 @@
+# `toktrie` crate has been brought into `chromium_crates_io` as a dependency
+# of the `llguidance` crate.  `derivre` is maintained in the same GitHub repo
+# as `llguidance`: https://github.com/guidance-ai/llguidance/tree/main/toktrie
+file://third_party/rust/llguidance/OWNERS
diff --git a/third_party/rust/windows_core/v0_61/BUILD.gn b/third_party/rust/windows_core/v0_61/BUILD.gn
index ac052dbb2..cfa16fd 100644
--- a/third_party/rust/windows_core/v0_61/BUILD.gn
+++ b/third_party/rust/windows_core/v0_61/BUILD.gn
@@ -63,13 +63,16 @@
   executable_configs += [ "//build/config/compiler:no_chromium_code" ]
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [
-    "//third_party/rust/windows_implement/v0_60:lib",
-    "//third_party/rust/windows_interface/v0_59:lib",
-    "//third_party/rust/windows_link/v0_1:lib",
-    "//third_party/rust/windows_result/v0_3:lib",
-    "//third_party/rust/windows_strings/v0_4:lib",
-  ]
+  deps = []
+  if (is_win) {
+    deps += [
+      "//third_party/rust/windows_implement/v0_60:lib",
+      "//third_party/rust/windows_interface/v0_59:lib",
+      "//third_party/rust/windows_link/v0_1:lib",
+      "//third_party/rust/windows_result/v0_3:lib",
+      "//third_party/rust/windows_strings/v0_4:lib",
+    ]
+  }
   features = [
     "default",
     "std",
diff --git a/third_party/rust/windows_implement/v0_60/BUILD.gn b/third_party/rust/windows_implement/v0_60/BUILD.gn
index 8f2566af..f990232 100644
--- a/third_party/rust/windows_implement/v0_60/BUILD.gn
+++ b/third_party/rust/windows_implement/v0_60/BUILD.gn
@@ -33,11 +33,14 @@
   executable_configs += [ "//build/config/compiler:no_chromium_code" ]
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [
-    "//third_party/rust/proc_macro2/v1:lib",
-    "//third_party/rust/quote/v1:lib",
-    "//third_party/rust/syn/v2:lib",
-  ]
+  deps = []
+  if (is_win) {
+    deps += [
+      "//third_party/rust/proc_macro2/v1:lib",
+      "//third_party/rust/quote/v1:lib",
+      "//third_party/rust/syn/v2:lib",
+    ]
+  }
   rustflags = [
     "--cap-lints=allow",  # Suppress all warnings in crates.io crates
   ]
diff --git a/third_party/rust/windows_interface/v0_59/BUILD.gn b/third_party/rust/windows_interface/v0_59/BUILD.gn
index 093cd44..2991bdf 100644
--- a/third_party/rust/windows_interface/v0_59/BUILD.gn
+++ b/third_party/rust/windows_interface/v0_59/BUILD.gn
@@ -29,11 +29,14 @@
   executable_configs += [ "//build/config/compiler:no_chromium_code" ]
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [
-    "//third_party/rust/proc_macro2/v1:lib",
-    "//third_party/rust/quote/v1:lib",
-    "//third_party/rust/syn/v2:lib",
-  ]
+  deps = []
+  if (is_win) {
+    deps += [
+      "//third_party/rust/proc_macro2/v1:lib",
+      "//third_party/rust/quote/v1:lib",
+      "//third_party/rust/syn/v2:lib",
+    ]
+  }
   rustflags = [
     "--cap-lints=allow",  # Suppress all warnings in crates.io crates
   ]
diff --git a/third_party/rust/windows_result/v0_3/BUILD.gn b/third_party/rust/windows_result/v0_3/BUILD.gn
index 6cc9b3d..4456fe1 100644
--- a/third_party/rust/windows_result/v0_3/BUILD.gn
+++ b/third_party/rust/windows_result/v0_3/BUILD.gn
@@ -38,7 +38,10 @@
   executable_configs += [ "//build/config/compiler:no_chromium_code" ]
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [ "//third_party/rust/windows_link/v0_1:lib" ]
+  deps = []
+  if (is_win) {
+    deps += [ "//third_party/rust/windows_link/v0_1:lib" ]
+  }
   features = [ "std" ]
   rustflags = [
     "--cap-lints=allow",  # Suppress all warnings in crates.io crates
diff --git a/third_party/rust/windows_strings/v0_4/BUILD.gn b/third_party/rust/windows_strings/v0_4/BUILD.gn
index 18ebf659..58cba9eb 100644
--- a/third_party/rust/windows_strings/v0_4/BUILD.gn
+++ b/third_party/rust/windows_strings/v0_4/BUILD.gn
@@ -43,7 +43,10 @@
   executable_configs += [ "//build/config/compiler:no_chromium_code" ]
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [ "//third_party/rust/windows_link/v0_1:lib" ]
+  deps = []
+  if (is_win) {
+    deps += [ "//third_party/rust/windows_link/v0_1:lib" ]
+  }
   features = [ "std" ]
   rustflags = [
     "--cap-lints=allow",  # Suppress all warnings in crates.io crates
diff --git a/third_party/rust/windows_sys/v0_52/BUILD.gn b/third_party/rust/windows_sys/v0_52/BUILD.gn
index 9ce2d87d..5601e4e 100644
--- a/third_party/rust/windows_sys/v0_52/BUILD.gn
+++ b/third_party/rust/windows_sys/v0_52/BUILD.gn
@@ -265,7 +265,10 @@
   executable_configs += [ "//build/config/compiler:no_chromium_code" ]
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
-  deps = [ "//third_party/rust/windows_targets/v0_52:lib" ]
+  deps = []
+  if (is_win) {
+    deps += [ "//third_party/rust/windows_targets/v0_52:lib" ]
+  }
   features = [
     "Win32",
     "Win32_Foundation",
diff --git a/third_party/rust/windows_targets/v0_52/BUILD.gn b/third_party/rust/windows_targets/v0_52/BUILD.gn
index f39952f29..1d5e03e 100644
--- a/third_party/rust/windows_targets/v0_52/BUILD.gn
+++ b/third_party/rust/windows_targets/v0_52/BUILD.gn
@@ -30,13 +30,13 @@
   proc_macro_configs -= [ "//build/config/compiler:chromium_code" ]
   proc_macro_configs += [ "//build/config/compiler:no_chromium_code" ]
   deps = []
-  if (current_cpu == "arm64") {
+  if (is_win && current_cpu == "arm64") {
     deps += [ "//third_party/rust/windows_aarch64_msvc/v0_52:lib" ]
   }
-  if (current_cpu == "x64") {
+  if (is_win && current_cpu == "x64") {
     deps += [ "//third_party/rust/windows_x86_64_msvc/v0_52:lib" ]
   }
-  if (current_cpu == "x86") {
+  if (is_win && current_cpu == "x86") {
     deps += [ "//third_party/rust/windows_i686_msvc/v0_52:lib" ]
   }
   rustflags = [
diff --git a/third_party/search_engines_data/BUILD.gn b/third_party/search_engines_data/BUILD.gn
index 6d66e1e..73ece79 100644
--- a/third_party/search_engines_data/BUILD.gn
+++ b/third_party/search_engines_data/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//tools/grit/grit_rule.gni")
 import("//tools/json_to_struct/json_to_struct.gni")
 
 json_to_struct("prepopulated_engines") {
@@ -31,3 +32,20 @@
     "//base",
   ]
 }
+
+group("resources") {
+  public_deps = [ ":search_engines_scaled_resources" ]
+}
+
+grit("search_engines_scaled_resources") {
+  source = "resources/search_engines_scaled_resources.grd"
+  outputs = [
+    "search_engines_scaled_resources.h",
+    "search_engines_scaled_resources_map.cc",
+    "search_engines_scaled_resources_map.h",
+    "search_engines_resources_100_percent.pak",
+    "search_engines_resources_200_percent.pak",
+    "search_engines_resources_300_percent.pak",
+  ]
+  output_dir = target_gen_dir
+}
diff --git a/third_party/search_engines_data/prepopulated_engines_schema.json b/third_party/search_engines_data/prepopulated_engines_schema.json
index 1a09b4f..2651ba70 100644
--- a/third_party/search_engines_data/prepopulated_engines_schema.json
+++ b/third_party/search_engines_data/prepopulated_engines_schema.json
@@ -16,6 +16,7 @@
     { "field": "name", "type": "string16" },
     { "field": "keyword", "type": "string16" },
     { "field": "favicon_url", "type": "string" },
+    { "field": "base_builtin_resource_id", "type": "string", "optional": true },
     { "field": "search_url", "type": "string" },
     {
       "field": "encoding",
diff --git a/third_party/skia b/third_party/skia
index 750c73b..32591be 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 750c73b5f3d518c1bdbefaab7b55dd56aef83c1c
+Subproject commit 32591be9cd3bea8c9e1ad39c64bc8230a4c4d499
diff --git a/tools/aggregation_service/aggregation_service_tool.cc b/tools/aggregation_service/aggregation_service_tool.cc
index c1e898d..7553e80 100644
--- a/tools/aggregation_service/aggregation_service_tool.cc
+++ b/tools/aggregation_service/aggregation_service_tool.cc
@@ -35,21 +35,9 @@
 
 std::optional<content::TestAggregationService::Operation> ConvertToOperation(
     std::string_view operation_string) {
-  if (operation_string == "histogram")
+  if (operation_string == "histogram") {
     return content::TestAggregationService::Operation::kHistogram;
-
-  return std::nullopt;
-}
-
-std::optional<content::TestAggregationService::AggregationMode>
-ConvertToAggregationMode(std::string_view aggregation_mode_string) {
-  if (aggregation_mode_string == "tee-based")
-    return content::TestAggregationService::AggregationMode::kTeeBased;
-  if (aggregation_mode_string == "experimental-poplar")
-    return content::TestAggregationService::AggregationMode::
-        kExperimentalPoplar;
-  if (aggregation_mode_string == "default")
-    return content::TestAggregationService::AggregationMode::kDefault;
+  }
 
   return std::nullopt;
 }
@@ -76,17 +64,14 @@
   agg_service_->SetDisablePayloadEncryption(should_disable);
 }
 
-bool AggregationServiceTool::SetPublicKeys(
-    const std::vector<UrlKeyFile>& key_files) {
-  // Send each url's specified public keys to the tool's storage.
-  for (const auto& key_file : key_files) {
-    if (!network::IsUrlPotentiallyTrustworthy(key_file.url)) {
-      LOG(ERROR) << "Invalid processing url: " << key_file.url;
-      return false;
-    }
+bool AggregationServiceTool::SetPublicKeys(const UrlKeyFile& key_file) {
+  if (!network::IsUrlPotentiallyTrustworthy(key_file.url)) {
+    LOG(ERROR) << "Invalid processing url: " << key_file.url;
+    return false;
+  }
 
-    if (!SetPublicKeysFromFile(key_file.url, key_file.key_file))
-      return false;
+  if (!SetPublicKeysFromFile(key_file.url, key_file.key_file)) {
+    return false;
   }
 
   return true;
@@ -121,9 +106,8 @@
     std::string operation_str,
     std::string bucket_str,
     std::string value_str,
-    std::string aggregation_mode_str,
     url::Origin reporting_origin,
-    std::vector<GURL> processing_urls,
+    GURL processing_url,
     bool is_debug_mode_enabled,
     base::Value::Dict additional_fields,
     std::string api_version,
@@ -149,23 +133,16 @@
     return result;
   }
 
-  std::optional<content::TestAggregationService::AggregationMode>
-      aggregation_mode = ConvertToAggregationMode(aggregation_mode_str);
-  if (!aggregation_mode.has_value()) {
-    LOG(ERROR) << "Invalid aggregation mode: " << aggregation_mode_str;
-    return result;
-  }
-
   if (reporting_origin.opaque()) {
     LOG(ERROR) << "Invalid reporting origin: " << reporting_origin;
     return result;
   }
 
   content::TestAggregationService::AssembleRequest request(
-      operation.value(), bucket, value, aggregation_mode.value(),
-      std::move(reporting_origin), std::move(processing_urls),
-      is_debug_mode_enabled, std::move(additional_fields),
-      std::move(api_version), std::move(api_identifier));
+      operation.value(), bucket, value, std::move(reporting_origin),
+      std::move(processing_url), is_debug_mode_enabled,
+      std::move(additional_fields), std::move(api_version),
+      std::move(api_identifier));
 
   base::RunLoop run_loop;
   agg_service_->AssembleReport(
diff --git a/tools/aggregation_service/aggregation_service_tool.h b/tools/aggregation_service/aggregation_service_tool.h
index 3fd512926..6c70c918 100644
--- a/tools/aggregation_service/aggregation_service_tool.h
+++ b/tools/aggregation_service/aggregation_service_tool.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 #include <string_view>
-#include <vector>
 
 #include "base/strings/string_split.h"
 #include "base/values.h"
@@ -49,9 +48,9 @@
   // after serialization.
   void SetDisablePayloadEncryption(bool should_disable);
 
-  // Sets public keys to storage from the url-filename pairs and returns
+  // Sets public keys to storage from the url-filename pair and returns
   // whether it's successful.
-  bool SetPublicKeys(const std::vector<UrlKeyFile>& key_files);
+  bool SetPublicKeys(const UrlKeyFile& key_file);
 
   // Construct an aggregatable report from the specified information and returns
   // a `base::Value::Dict` for its JSON representation. Empty
@@ -59,9 +58,8 @@
   base::Value::Dict AssembleReport(std::string operation_str,
                                    std::string bucket_str,
                                    std::string value_str,
-                                   std::string aggregation_mode_str,
                                    url::Origin reporting_origin,
-                                   std::vector<GURL> processing_urls,
+                                   GURL processing_url,
                                    bool is_debug_mode_enabled,
                                    base::Value::Dict additional_fields,
                                    std::string api_version,
diff --git a/tools/aggregation_service/aggregation_service_tool_main.cc b/tools/aggregation_service/aggregation_service_tool_main.cc
index 80a5614..d8bdad0e 100644
--- a/tools/aggregation_service/aggregation_service_tool_main.cc
+++ b/tools/aggregation_service/aggregation_service_tool_main.cc
@@ -32,11 +32,9 @@
 constexpr std::string_view kSwitchOperation = "operation";
 constexpr std::string_view kSwitchBucket = "bucket";
 constexpr std::string_view kSwitchValue = "value";
-constexpr std::string_view kSwitchAlternativeAggregationMode =
-    "alternative-aggregation-mode";
 constexpr std::string_view kSwitchReportingOrigin = "reporting-origin";
-constexpr std::string_view kSwitchHelperKeyUrls = "helper-key-urls";
-constexpr std::string_view kSwitchHelperKeyFiles = "helper-key-files";
+constexpr std::string_view kSwitchHelperKeyUrl = "helper-key-url";
+constexpr std::string_view kSwitchHelperKeyFile = "helper-key-file";
 constexpr std::string_view kSwitchOutputFile = "output-file";
 constexpr std::string_view kSwitchOutputUrl = "output-url";
 constexpr std::string_view kSwitchDisablePayloadEncryption =
@@ -50,9 +48,10 @@
 
 constexpr std::string_view kHelpMsg = R"(
   aggregation_service_tool [--operation=<operation>] --bucket=<bucket>
-  --value=<value> --aggregation-mode=<aggregation_mode>
+  --value=<value>
   --reporting-origin=<reporting_origin>
-  --helper-keys=<helper_server_keys> [--output=<output_file>]
+  --helper-key-url=<helper_key_url> (or --helper-key-file=<helper_key_file>)
+  [--output=<output_file>]
   [--output-url=<output_url>] [--disable-payload-encryption]
   [--additional-fields=<additional_fields>]
   [--additional-shared-info-fields=<additional_shared_info_fields]
@@ -60,15 +59,15 @@
 
   Examples:
   aggregation_service_tool --operation="histogram" --bucket=1234 --value=5
-  --alternative-aggregation-mode="experimental-poplar" --reporting-origin="https://example.com"
-  --helper-key-urls="https://a.com/keys.json https://b.com/path/to/keys.json"
+  --reporting-origin="https://example.com"
+  --helper-key-url="https://a.com/keys.json"
   --output-file="output.json" --enable-debug-mode --api-version="1.0"
   --api="attribution-reporting" --additional-fields=
   "source_site=https://publisher.example,attribution_destination=https://advertiser.example"
   or
   aggregation_service_tool --bucket=1234 --value=5
   --reporting-origin="https://example.com"
-  --helper-key-files="keys.json"
+  --helper-key-file="keys.json"
   --output-url="https://c.com/reports"
 
   aggregation_service_tool is a command-line tool that accepts report contents
@@ -84,17 +83,13 @@
              integer.
   --value = Bucket value of the histogram contribution, must be non-negative
             integer.
-  --alternative-aggregation-mode = Optional switch to specify an alternative
-                                   aggregation mode. Supports "tee-based",
-                                   "experimental-poplar" and "default"
-                                   (default value, equivalent to "tee-based").
   --reporting-origin = The reporting origin endpoint.
-  --helper-key-urls = Optional switch to specify the URL(s) to fetch the public
-                      key json file(s) from. Spaces are used as separators.
-                      Either this or "--helper-key-files" must be specified.
-  --helper-key-files = Optional switch to specify the local public key json
-                       file(s) to use. Spaces are used as separators. Either
-                       this or "--helper-key-urls" must be specified.
+  --helper-key-url = Optional switch to specify the URL to fetch the public key
+                     json file from. Either this or "--helper-key-file" must be
+                     specified.
+  --helper-key-file = Optional switch to specify the local public key json file
+                      to use. Either this or "--helper-key-url" must be
+                      specified.
   --output-file = Optional switch to specify the output file path. Eiter this or
                   "--output-url" must be specified.
   --output-url = Optional switch to specify the output url. Eiter this or
@@ -145,10 +140,9 @@
       kSwitchOperation,
       kSwitchBucket,
       kSwitchValue,
-      kSwitchAlternativeAggregationMode,
       kSwitchReportingOrigin,
-      kSwitchHelperKeyUrls,
-      kSwitchHelperKeyFiles,
+      kSwitchHelperKeyUrl,
+      kSwitchHelperKeyFile,
       kSwitchOutputFile,
       kSwitchOutputUrl,
       kSwitchDisablePayloadEncryption,
@@ -195,10 +189,10 @@
   }
 
   // Either helper key URL or file should be specified, but not both.
-  if (!(command_line.HasSwitch(kSwitchHelperKeyUrls) ^
-        command_line.HasSwitch(kSwitchHelperKeyFiles))) {
+  if (!(command_line.HasSwitch(kSwitchHelperKeyUrl) ^
+        command_line.HasSwitch(kSwitchHelperKeyFile))) {
     LOG(ERROR) << "aggregation_service_tool expects either "
-               << kSwitchHelperKeyUrls << " or " << kSwitchHelperKeyFiles
+               << kSwitchHelperKeyUrl << " or " << kSwitchHelperKeyFile
                << " to be specified, but not both.";
     PrintHelp();
     return 1;
@@ -210,52 +204,31 @@
       /*should_disable=*/command_line.HasSwitch(
           kSwitchDisablePayloadEncryption));
 
-  std::vector<GURL> processing_urls;
+  GURL processing_url;
 
-  if (command_line.HasSwitch(kSwitchHelperKeyUrls)) {
-    std::string switch_value =
-        command_line.GetSwitchValueASCII(kSwitchHelperKeyUrls);
-    std::vector<std::string> helper_key_url_strings =
-        base::SplitString(switch_value, /*separators=*/" ",
-                          base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-
-    for (std::string_view url_string : helper_key_url_strings) {
-      GURL helper_key_url(url_string);
-      if (!network::IsUrlPotentiallyTrustworthy(helper_key_url)) {
-        LOG(ERROR) << "Helper key URL " << url_string
-                   << " is not potentially trustworthy.";
-        return 1;
-      }
-      processing_urls.emplace_back(std::move(helper_key_url));
-    }
-  } else {
-    std::string switch_value =
-        command_line.GetSwitchValueASCII(kSwitchHelperKeyFiles);
-
-    std::vector<std::string> helper_key_file_strings =
-        base::SplitString(switch_value, /*separators=*/" ",
-                          base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-
-    if (helper_key_file_strings.empty() || helper_key_file_strings.size() > 2) {
-      LOG(ERROR) << kSwitchHelperKeyFiles
-                 << " specified an invalid number of files: "
-                 << helper_key_file_strings.size();
+  if (command_line.HasSwitch(kSwitchHelperKeyUrl)) {
+    std::string url_string =
+        command_line.GetSwitchValueASCII(kSwitchHelperKeyUrl);
+    processing_url = GURL(url_string);
+    if (!network::IsUrlPotentiallyTrustworthy(processing_url)) {
+      LOG(ERROR) << "Helper key URL " << url_string
+                 << " is not potentially trustworthy.";
       return 1;
     }
+  } else {
+    std::string file_string =
+        command_line.GetSwitchValueASCII(kSwitchHelperKeyFile);
 
-    std::vector<aggregation_service::UrlKeyFile> key_files;
-    for (size_t i = 0; i < helper_key_file_strings.size(); ++i) {
-      // We need to choose some URL to store each set of public keys under.
-      std::string fake_helper_url =
-          base::StringPrintf("https://fake_%zu.example/keys.json", i);
-      key_files.emplace_back(GURL(fake_helper_url), helper_key_file_strings[i]);
-      processing_urls.emplace_back(std::move(fake_helper_url));
-    }
+    // We need to choose some URL to store the set of public keys under.
+    aggregation_service::UrlKeyFile key_file(
+        GURL("https://fake.example/keys.json"), file_string);
 
-    if (!tool.SetPublicKeys(key_files)) {
+    if (!tool.SetPublicKeys(key_file)) {
       LOG(ERROR) << "aggregation_service_tool failed to set public keys.";
       return 1;
     }
+
+    processing_url = std::move(key_file.url);
   }
 
   std::string operation =
@@ -263,11 +236,6 @@
           ? command_line.GetSwitchValueASCII(kSwitchOperation)
           : "histogram";
 
-  std::string aggregation_mode =
-      command_line.HasSwitch(kSwitchAlternativeAggregationMode)
-          ? command_line.GetSwitchValueASCII(kSwitchAlternativeAggregationMode)
-          : "default";
-
   url::Origin reporting_origin = url::Origin::Create(
       GURL(command_line.GetSwitchValueASCII(kSwitchReportingOrigin)));
 
@@ -302,10 +270,9 @@
   base::Value::Dict report_dict = tool.AssembleReport(
       std::move(operation), command_line.GetSwitchValueASCII(kSwitchBucket),
       command_line.GetSwitchValueASCII(kSwitchValue),
-      std::move(aggregation_mode), std::move(reporting_origin),
-      std::move(processing_urls), is_debug_mode_enabled,
-      std::move(additional_shared_info_fields), std::move(api_version),
-      std::move(api_identifier));
+      std::move(reporting_origin), std::move(processing_url),
+      is_debug_mode_enabled, std::move(additional_shared_info_fields),
+      std::move(api_version), std::move(api_identifier));
   if (report_dict.empty()) {
     LOG(ERROR)
         << "aggregation_service_tool failed to create the aggregatable report.";
@@ -347,8 +314,9 @@
     }
   }
 
-  if (!succeeded)
+  if (!succeeded) {
     return 1;
+  }
 
   return 0;
 }
diff --git a/tools/aggregation_service/aggregation_service_tool_network_initializer.h b/tools/aggregation_service/aggregation_service_tool_network_initializer.h
index 983a701..53b8a89 100644
--- a/tools/aggregation_service/aggregation_service_tool_network_initializer.h
+++ b/tools/aggregation_service/aggregation_service_tool_network_initializer.h
@@ -51,4 +51,4 @@
 
 }  // namespace aggregation_service
 
-#endif  // TOOLS_AGGREGATION_SERVICE_AGGREGATION_SERVICE_TOOL_NETWORK_INITIALIZER_H_
\ No newline at end of file
+#endif  // TOOLS_AGGREGATION_SERVICE_AGGREGATION_SERVICE_TOOL_NETWORK_INITIALIZER_H_
diff --git a/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/ChromeNullAwayLibraryModel.java b/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/ChromeNullAwayLibraryModel.java
index 3905b65..3ae8b261 100644
--- a/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/ChromeNullAwayLibraryModel.java
+++ b/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/ChromeNullAwayLibraryModel.java
@@ -98,13 +98,32 @@
 
     @Override
     public ImmutableSetMultimap<String, Integer> typeVariablesWithNullableUpperBounds() {
+        // TODO(https://github.com/uber/NullAway/issues/1212): Add FutureTask:
+        //      .put("java.util.concurrent.FutureTask", 0)
         return new ImmutableSetMultimap.Builder<String, Integer>()
+                .put("java.util.concurrent.Callable", 0)
+                .put("java.util.concurrent.CompletableFuture", 0)
+                .put("java.util.concurrent.CompletionStage", 0)
+                .put("java.util.concurrent.Future", 0)
+                .put("java.util.concurrent.RunnableFuture", 0)
+                .put("java.util.function.BiConsumer", 0)
+                .put("java.util.function.BiConsumer", 1)
+                .put("java.util.function.BiFunction", 0)
+                .put("java.util.function.BiFunction", 1)
+                .put("java.util.function.BiFunction", 2)
+                .put("java.util.function.Consumer", 0)
+                .put("java.util.function.DoubleFunction", 0)
+                .put("java.util.function.IntFunction", 0)
+                .put("java.util.function.Function", 0)
+                .put("java.util.function.Function", 1)
+                .put("java.util.function.LongFunction", 0)
+                .put("java.util.function.Predicate", 0)
                 .put("java.util.function.Supplier", 0)
                 .build();
     }
 
     @Override
     public ImmutableSet<String> nullMarkedClasses() {
-        return ImmutableSet.of("java.util.function.Supplier");
+        return typeVariablesWithNullableUpperBounds().keySet();
     }
 }
diff --git a/tools/android/nullaway/null_mark.py b/tools/android/nullaway/null_mark.py
new file mode 100755
index 0000000..a998c2e
--- /dev/null
+++ b/tools/android/nullaway/null_mark.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import logging
+import pathlib
+import re
+import subprocess
+
+_SRC_ROOT = (pathlib.Path(__file__).parents[3])
+
+_GOOGLE_JAVA_FORMAT = (_SRC_ROOT / 'third_party' / 'google-java-format' /
+                       'google-java-format')
+
+_IMPORTS = """import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.build.annotations.MonotonicNonNull;
+import org.chromium.build.annotations.Contract;
+import org.chromium.build.annotations.EnsuresNonNull;
+import org.chromium.build.annotations.EnsuresNonNullIf;
+import org.chromium.build.annotations.Initializer;
+import org.chromium.build.annotations.RequiresNonNull;
+import static org.chromium.build.NullUtil.assumeNonNull;
+import static org.chromium.build.NullUtil.assertNonNull;
+"""
+
+_MODIFIER_KEYWORDS = (r'(?:(?:' + '|'.join([
+    'abstract',
+    'default',
+    'final',
+    'native',
+    'private',
+    'protected',
+    'public',
+    'static',
+    'synchronized',
+    r'/\*\s*package\s*\*/',
+]) + r')\s+)*')
+
+_NULLABLE_RE = re.compile(r'(\n *)@Nullable'
+                          r'('
+                          r'(?:\s*@\w+(?:\(.*?\))?)*'
+                          r'\s+(?:' + _MODIFIER_KEYWORDS + r')?' +
+                          r'(?:<.*?>)?'
+                          r')')
+_CLASSES_REGEX = re.compile(
+    r'(^(?:public|protected|private|/\*\s*package\s*\*/)?\s*'
+    r'(?:(?:static|abstract|final|sealed)\s+)*'
+    r'(?:class|@?interface|enum)\s+\w+)',
+    flags=re.MULTILINE)
+
+
+def _mark_file(path):
+    data = path.read_text()
+    if '@NullMarked' in data:
+        logging.warning('Skipping %s. Already has @NullMarked', path)
+        return False
+    if '@NullUnmarked' in data:
+        logging.warning('Skipping %s. Already has @NullUnmarked', path)
+        return False
+
+    data = data.replace('import androidx.annotation.Nullable;\n', '')
+    # Move @Nullable before methods to right before return type.
+    data = _NULLABLE_RE.sub(r'\1\2 @Nullable ', data)
+    # Fix up type-use position.
+    data = re.sub(r'@Nullable\s+((?:\w+\.)+)(\w+)', r'\1@Nullable \2', data)
+    data = re.sub(r'@Nullable\s+([\w<>]+)\[\]', r'\1 @Nullable[]', data)
+
+    # Remove @NonNull
+    data = data.replace('@NonNull', '')
+    # Add imports
+    data = re.sub(r'(^package .*\n)',
+                  r'\1' + _IMPORTS,
+                  data,
+                  flags=re.MULTILINE,
+                  count=1)
+
+    # Add @NullMarked
+    data = _CLASSES_REGEX.sub(r'@NullMarked\n\1', data, count=1)
+
+    # Make all Void's @Nullable
+    if re.search(r'\bVoid\b', data):
+        data = re.sub(r'\bVoid\b', '@Nullable Void', data)
+        data = data.replace('@Nullable @Nullable Void', '@Nullable Void')
+
+    # Make all Supplier<Tab> -> Supplier<@Nullable Tab>
+    if 'Supplier<Tab>' in data:
+        data = data.replace('Supplier<Tab>', 'Supplier<@Nullable Tab>')
+
+    logging.info('Processed: %s', path)
+    path.write_text(data)
+    return True
+
+
+def main():
+    logging.basicConfig(format='%(message)s', level=logging.INFO)
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('files', nargs='+')
+    args = parser.parse_args()
+
+    changed_paths = []
+    for f in args.files:
+        if _mark_file(pathlib.Path(f)):
+            changed_paths.append(f)
+
+    if changed_paths:
+        cmd = [
+            str(_GOOGLE_JAVA_FORMAT), '--aosp', '--skip-javadoc-formatting',
+            '--skip-removing-unused-imports', '--replace'
+        ] + changed_paths
+        logging.info('Running: %s', ' '.join(cmd))
+        subprocess.check_call(cmd)
+    print(f'Added @NullMarked to {len(changed_paths)} path(s).')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/crates/gnrt/Cargo.lock b/tools/crates/gnrt/Cargo.lock
index baf5ffc..a7e7268f 100644
--- a/tools/crates/gnrt/Cargo.lock
+++ b/tools/crates/gnrt/Cargo.lock
@@ -180,9 +180,9 @@
 
 [[package]]
 name = "cc"
-version = "1.2.20"
+version = "1.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
+checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
 dependencies = [
  "shlex",
 ]
@@ -517,19 +517,26 @@
 version = "0.0.0"
 dependencies = [
  "anyhow",
+ "bitflags 2.9.0",
  "cargo-platform",
  "clap",
  "env_logger",
  "flate2",
  "guppy",
  "handlebars",
+ "heck",
  "itertools 0.12.1",
+ "itertools 0.14.0",
  "log",
  "once_cell",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
  "reqwest",
  "semver",
  "serde",
  "serde_json",
+ "syn",
  "tar",
  "target-spec",
  "tempfile",
@@ -604,9 +611,9 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.15.2"
+version = "0.15.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
 
 [[package]]
 name = "heck"
@@ -1019,9 +1026,9 @@
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.107"
+version = "0.9.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
+checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
 dependencies = [
  "cc",
  "libc",
@@ -1118,6 +1125,16 @@
 checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
 
 [[package]]
+name = "prettyplease"
+version = "0.2.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1143,9 +1160,9 @@
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.11"
+version = "0.5.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
+checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
 dependencies = [
  "bitflags 2.9.0",
 ]
@@ -1198,9 +1215,9 @@
 
 [[package]]
 name = "rustix"
-version = "1.0.5"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
 dependencies = [
  "bitflags 2.9.0",
  "errno",
@@ -1326,9 +1343,9 @@
 
 [[package]]
 name = "sha2"
-version = "0.10.8"
+version = "0.10.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -1403,9 +1420,9 @@
 
 [[package]]
 name = "synstructure"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1966,9 +1983,9 @@
 
 [[package]]
 name = "winnow"
-version = "0.7.7"
+version = "0.7.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5"
+checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
 dependencies = [
  "memchr",
 ]
diff --git a/tools/crates/gnrt/Cargo.toml b/tools/crates/gnrt/Cargo.toml
index a0999aa..578127c 100644
--- a/tools/crates/gnrt/Cargo.toml
+++ b/tools/crates/gnrt/Cargo.toml
@@ -2,6 +2,7 @@
 name = "gnrt"
 version = "0.0.0"
 edition = "2021"
+build = "build/build.rs"
 
 [lib]
 name = "gnrt_lib"
@@ -13,11 +14,12 @@
 
 [dependencies]
 anyhow = "1"
+bitflags = "2.9.0"
 cargo-platform = "0.1"
 clap = {version = "4", features = ["derive"]}
 guppy = "0.17.18"
 handlebars = "4.3.7"
-itertools = "0.12"
+itertools = "0.14"
 flate2 = "1"
 reqwest = {version = "0.11", features = ["blocking"]}
 log = { version = "0.4", features = ["std"] }
@@ -34,3 +36,12 @@
 version = "0.10"
 default-features = false
 features = ["color"]
+
+[build-dependencies]
+anyhow = "1.0.97"
+heck = "0.5.0"
+itertools = "0.12"
+prettyplease = "0.2.31"
+proc-macro2 = "1.0.94"
+quote = "1.0.40"
+syn = "2.0.100"
diff --git a/tools/crates/gnrt/build/build.rs b/tools/crates/gnrt/build/build.rs
new file mode 100644
index 0000000..e16be25
--- /dev/null
+++ b/tools/crates/gnrt/build/build.rs
@@ -0,0 +1,233 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! This `build.rs` file invokes `rustc --print=cfg <target triple>` to
+//! discover how each of Chromium-supported target triples maps to
+//! how `rustc` sets `#[cfg(target_os = "...")]`, etc.
+//!
+//! This is written as `build.rs` and not as a proc macro, because only
+//! the former gets `RUSTC` environment variable set by `cargo`:
+//! https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
+
+use anyhow::{ensure, Result};
+use heck::{ToPascalCase, ToShoutySnakeCase};
+use itertools::Itertools;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use std::{env, fs::File, io::Write, path::Path, process::Command};
+
+fn write_pretty_file_fragment(mut w: impl Write, contents: TokenStream) -> Result<()> {
+    let syn_file = syn::parse2(contents)?;
+    write!(w, "{}", prettyplease::unparse(&syn_file))?;
+    Ok(())
+}
+
+fn format_ident(s: &str) -> syn::Ident {
+    format_ident!("{}", s.to_pascal_case())
+}
+
+fn format_const_ident(s: &str) -> syn::Ident {
+    format_ident!("{}", s.to_shouty_snake_case())
+}
+
+/// Represents one line of output from `rustc --print=cfg <triple_name>`.
+struct CfgLine {
+    triple_name: &'static str,
+    property_name: String,
+    property_value: String,
+}
+
+fn get_cfg_lines(triple_name: &'static str) -> Result<Vec<CfgLine>> {
+    let rustc = env::var_os("RUSTC").unwrap();
+    let output =
+        Command::new(&rustc).arg("--print=cfg").arg(format!("--target={triple_name}")).output()?;
+    ensure!(
+        output.status.success(),
+        "`rustc` returned a non-zero exit status: {}",
+        std::str::from_utf8(&output.stderr).unwrap_or("<non utf-8 stderr>"),
+    );
+    Ok(std::str::from_utf8(&output.stdout)?
+        .lines()
+        .filter_map(|line| {
+            line.split_once("=")
+                .filter(|(property_name, _)| property_name.starts_with("target_"))
+                .map(|(property_name, property_value)| {
+                    let property_name = property_name.to_string();
+                    let property_value = property_value.trim_matches('"').to_string();
+                    CfgLine { triple_name, property_name, property_value }
+                })
+        })
+        .collect_vec())
+}
+
+fn generate_enum_for_named_property(
+    cfg_lines: &[CfgLine],
+    doc_string: TokenStream,
+    enum_ident: TokenStream,
+    property_name: &str,
+) -> TokenStream {
+    let triple_and_property_value_idents = cfg_lines
+        .iter()
+        .filter_map(|cfg| {
+            if cfg.property_name == property_name {
+                Some((format_const_ident(cfg.triple_name), format_ident(&cfg.property_value)))
+            } else {
+                None
+            }
+        })
+        .collect_vec();
+
+    let unique_property_value_idents = triple_and_property_value_idents
+        .clone()
+        .into_iter()
+        .map(|(_, property_value)| property_value)
+        .unique()
+        .collect_vec();
+    let (triple_idents, property_value_idents) =
+        triple_and_property_value_idents.into_iter().unzip::<_, _, Vec<_>, Vec<_>>();
+    quote! {
+        #doc_string
+        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+        pub enum #enum_ident {
+            #( #unique_property_value_idents ),*
+        }
+
+        impl TryFrom<RustTargetTriple> for #enum_ident {
+            type Error = anyhow::Error;
+
+            fn try_from(value: RustTargetTriple) -> Result<Self> {
+                match value {
+                    #( RustTargetTriple :: #triple_idents
+                        => Ok(#enum_ident :: #property_value_idents), )*
+                    other => Err(anyhow!("Not a single triple?: {other:?}")),
+                }
+            }
+        }
+    }
+}
+
+fn write_target_triples_rs(path: &Path) -> Result<()> {
+    let mut output_file = File::create(path)?;
+
+    println!("cargo::rerun-if-changed=../../../build/rust/known-target-triples.txt");
+    let triple_names = include_str!("../../../../build/rust/known-target-triples.txt")
+        .lines()
+        .filter(|line| !line.starts_with('#'))
+        .filter(|line| !line.trim().is_empty())
+        .sorted()
+        .collect_vec();
+    let triple_idents = triple_names.iter().map(|triple| format_const_ident(triple)).collect_vec();
+    let cfg_lines = triple_names
+        .iter()
+        .map(|&triple| get_cfg_lines(triple))
+        .collect::<Result<Vec<_>>>()?
+        .into_iter()
+        .flatten()
+        .collect_vec();
+
+    let target_properties = {
+        let tuple_elem0s = cfg_lines.iter().map(|cfg| &cfg.triple_name);
+        let tuple_elem1s = cfg_lines.iter().map(|cfg| &cfg.property_name);
+        let tuple_elem2s = cfg_lines.iter().map(|cfg| &cfg.property_value);
+        let len = cfg_lines.len();
+        quote! {
+            /// Each tuple below represents one line of output from
+            /// `rustc --print=cfg <triple_name>`, where:
+            ///
+            /// * The 0th tuple element is the name of the target triple
+            ///   (e.g. `x86_64-pc-windows-msvc`)
+            /// * The 1st tuple element is the name of a property (e.g. `target_env`)
+            /// * The 2nd tuple element is the value of the property (e.g. `msvc`)
+            pub static RUST_TRIPLE_PROPERTIES: [(&str, &str, &str); #len] = [
+                #( (#tuple_elem0s, #tuple_elem1s, #tuple_elem2s) ),*
+            ];
+        }
+    };
+    let target_arch = generate_enum_for_named_property(
+        &cfg_lines,
+        quote! {
+            /// Target architecture as seen/reported by `rustc`.
+        },
+        quote! { RustTargetArch },
+        "target_arch",
+    );
+    let target_os = generate_enum_for_named_property(
+        &cfg_lines,
+        quote! {
+            /// Target OS as seen/reported by `rustc`.
+        },
+        quote! { RustTargetOs },
+        "target_os",
+    );
+
+    write_pretty_file_fragment(
+        &mut output_file,
+        quote! {
+            use anyhow::{anyhow, Result};
+            use bitflags::bitflags;
+            use std::convert::TryFrom;
+            use std::str::FromStr;
+        },
+    )?;
+    writeln!(&mut output_file)?;
+
+    // `bitflags!` doesn't format well using `prettyplease`, so let's just
+    // manually `writeln!` it out.
+    writeln!(
+        &mut output_file,
+        r#"
+bitflags! {{
+    /// `RustTargetTriple` enum exhaustively names all target triples that are
+    /// supported by Chromium when compiling Rust libraries.
+    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+    pub struct RustTargetTriple: u64 {{"#
+    )?;
+    for (index, ident) in triple_idents.iter().enumerate() {
+        writeln!(&mut output_file, "        const {ident} = 1 << {index};")?;
+    }
+    writeln!(&mut output_file, "    }}")?;
+    writeln!(&mut output_file, "}}")?;
+
+    write_pretty_file_fragment(
+        &mut output_file,
+        quote! {
+            impl RustTargetTriple {
+                pub fn as_triple_name(&self) -> Result<&'static str> {
+                    match *self {
+                        #( RustTargetTriple :: #triple_idents
+                            => Ok(#triple_names), )*
+                        other => Err(anyhow!("Not a single triple?: {other:?}")),
+                    }
+                }
+            }
+
+            impl FromStr for RustTargetTriple {
+                type Err = anyhow::Error;
+                fn from_str(input: &str) -> Result<RustTargetTriple> {
+                    for (s, t) in &[
+                        #( (#triple_names, RustTargetTriple::#triple_idents) ),*
+                    ] {
+                        if input == *s {
+                            return Ok(*t);
+                        }
+                    }
+                    Err(anyhow!("Unrecognized target triple: `{input}`"))
+                }
+            }
+
+            #target_arch
+            #target_os
+
+            #target_properties
+        },
+    )?;
+    Ok(())
+}
+
+fn main() -> Result<()> {
+    let out_dir = env::var_os("OUT_DIR").unwrap();
+    let out_dir = Path::new(&out_dir);
+    write_target_triples_rs(&out_dir.join("target_triple.rs"))?;
+    Ok(())
+}
diff --git a/tools/crates/gnrt/lib/condition.rs b/tools/crates/gnrt/lib/condition.rs
index 9b00d78..2487e51 100644
--- a/tools/crates/gnrt/lib/condition.rs
+++ b/tools/crates/gnrt/lib/condition.rs
@@ -2,7 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Note that `target_triple.rs` module is auto-generated by `gnrt`'s `build.rs`.
+use crate::target_triple::{RustTargetTriple, RUST_TRIPLE_PROPERTIES};
+
 use anyhow::{anyhow, Result};
+use std::{collections::HashMap, sync::LazyLock};
 
 /// Representation of a `Condition` associated with a conditional/optional
 /// dependency.
@@ -17,17 +21,12 @@
     ///
     /// Example: `#[cfg(not(target_arch = "powerpc"))]`.
     AlwaysTrue,
-    /// Ignored terms.  For example we ignore `target_abi` and assume that
-    /// `target_env` is sufficient for picking the right dependencies.
-    Ignored,
-    /// The condition requires evaluating the nested GN expression.
-    /// The `String` payload is the condition expressed in GN syntax (e.g.
-    /// `is_win`).
+    /// The conditional dependency applies to a subset of target triples
+    /// (`RustTargetTriple` is a bit flag - it may have more than 1 bit set).
     ///
     /// For example `#[cfg(target_os = "windows")]` translates into
-    /// `Condition::Expr("is_win".to_string())`.
-    Expr(String),
-    ///
+    /// `Condition::TripleSet(...)`.
+    TripleSet(RustTargetTriple),
     /// Some of the [conditional
     /// compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) directives
     /// weren't recognized by `gnrt`.
@@ -46,37 +45,37 @@
         *self == Condition::AlwaysFalse
     }
 
-    pub fn or(lhs: Condition, rhs: Condition) -> Self {
-        // Avoiding unnecessarily constructing `is_win || is_win`.
-        // This is mostly needed for `or`, because this is where
-        // different dependency edge kinds (e.g. `Build` vs `Normal`)
-        // result in `or`-ing of conditions as driven by `deps.rs`.
-        if lhs == rhs {
-            return lhs;
+    fn from_triple_set(set: RustTargetTriple) -> Self {
+        if set.is_empty() {
+            Condition::AlwaysFalse
+        } else if set.is_all() {
+            Condition::AlwaysTrue
+        } else {
+            Condition::TripleSet(set)
         }
+    }
 
+    pub fn or(lhs: Condition, rhs: Condition) -> Self {
         match (lhs, rhs) {
             (Condition::AlwaysFalse, other) | (other, Condition::AlwaysFalse) => other.clone(),
             (Condition::AlwaysTrue, _) | (_, Condition::AlwaysTrue) => Condition::AlwaysTrue,
-            (Condition::Ignored, other) | (other, Condition::Ignored) => other.clone(),
-            (Condition::Expr(lhs), Condition::Expr(rhs)) => {
-                Condition::Expr(format!("({lhs}) || ({rhs})"))
-            }
             (err @ Condition::Unsupported(_), _) | (_, err @ Condition::Unsupported(_)) => {
                 err.clone()
             }
+            (Condition::TripleSet(lhs), Condition::TripleSet(rhs)) => {
+                Condition::from_triple_set(lhs | rhs)
+            }
         }
     }
 
-    fn and(lhs: Condition, rhs: Condition) -> Self {
+    pub fn and(lhs: Condition, rhs: Condition) -> Self {
         match (lhs, rhs) {
             (Condition::AlwaysFalse, _) | (_, Condition::AlwaysFalse) => Condition::AlwaysFalse,
             (Condition::AlwaysTrue, other) | (other, Condition::AlwaysTrue) => other,
-            (Condition::Ignored, other) | (other, Condition::Ignored) => other,
-            (Condition::Expr(lhs), Condition::Expr(rhs)) => {
-                Condition::Expr(format!("({lhs}) && ({rhs})"))
-            }
             (err @ Condition::Unsupported(_), _) | (_, err @ Condition::Unsupported(_)) => err,
+            (Condition::TripleSet(lhs), Condition::TripleSet(rhs)) => {
+                Condition::from_triple_set(lhs & rhs)
+            }
         }
     }
 
@@ -84,16 +83,15 @@
         match other {
             Condition::AlwaysFalse => Condition::AlwaysTrue,
             Condition::AlwaysTrue => Condition::AlwaysFalse,
-            Condition::Ignored => Condition::Ignored,
-            Condition::Expr(expr) => Condition::Expr(format!("!({expr})")),
             err @ Condition::Unsupported(_) => err,
+            Condition::TripleSet(value) => Condition::TripleSet(!value),
         }
     }
 
     pub fn to_handlebars_value(&self) -> Result<Option<String>> {
         match self {
-            Condition::AlwaysTrue | Condition::Ignored => Ok(None),
-            Condition::Expr(expr) => Ok(Some(expr.clone())),
+            Condition::AlwaysTrue => Ok(None),
+            Condition::TripleSet(set) => Ok(Some(format_as_gn_expr::format(*set))),
             Condition::AlwaysFalse => unreachable!(
                 "AlwaysFalse dependencies should be filtered out \
                               by `fn collect_dependencies` from `deps.rs`"
@@ -117,6 +115,188 @@
     }
 }
 
+/// Module for converting a set of target triples into a conditional expression
+/// that uses GN/Chromium variables and syntax.
+///
+/// The main entrypoint is the `pub fn format` function below.
+///
+/// The conditional expression is built as a combination of:
+///
+/// * OS filters (e.g. `"is_win"`, see `fn get_gn_os_expr`)
+/// * CPU filters (e.g. `"current_cpu == \"x64\""`, see `fn get_gn_arch_expr`)
+/// * Triple filters (e.g. `"rust_abi_target == \"aarch64-apple-ios-sim\"`, see
+///   `gn get_gn_target_triple_expr`).  This is used as a last resort, because
+///   this results in long and not very readable expressions.
+mod format_as_gn_expr {
+    use crate::target_triple::{RustTargetArch, RustTargetOs, RustTargetTriple};
+    use itertools::Itertools;
+    use std::collections::HashSet;
+
+    /// Translates `target_triples` (where 1 or more bits/triples can be set)
+    /// into a condition expressed in GN/Chromium syntax (e.g.  `is_win &&
+    /// current_cpu == "x64"`).  Tries to use heuristics to return a short,
+    /// readable expression.
+    pub fn format(target_triples: RustTargetTriple) -> String {
+        assert!(!target_triples.is_empty());
+        assert!(!target_triples.is_all());
+
+        if let Some(expr) = get_single_filter(target_triples, get_gn_os_expr) {
+            return expr;
+        }
+        if let Some(expr) = get_single_filter(target_triples, get_gn_arch_expr) {
+            return expr;
+        }
+
+        let result1 = get_double_filter(target_triples, get_gn_os_expr, get_gn_arch_expr);
+        let result2 = get_double_filter(target_triples, get_gn_arch_expr, get_gn_os_expr);
+        if let Some((result1, result2)) = result1.zip(result2) {
+            if result1.len() <= result2.len() {
+                return result1;
+            } else {
+                return result2;
+            }
+        }
+
+        target_triples.iter().map(get_gn_target_triple_expr).sorted().join(" || ")
+    }
+
+    /// If `target_triples` can be calculated with a single-dimensional filter
+    /// (e.g. "all triples with OS=A or OS=B" or "all triples with Arch=x86
+    /// or Arch=x64") then returns an expression that represents such a
+    /// filter. `get_expr` should typically be `get_gn_os_expr` or
+    /// `get_gn_arch_expr`.
+    fn get_single_filter(
+        target_triples: RustTargetTriple,
+        get_expr: fn(RustTargetTriple) -> &'static str,
+    ) -> Option<String> {
+        let get_expr_set = |triples: RustTargetTriple| -> HashSet<&'static str> {
+            triples.iter().map(get_expr).collect()
+        };
+        fn negate(expr: &str) -> String {
+            if expr.contains("==") {
+                expr.replace("==", "!=")
+            } else {
+                format!("!{expr}")
+            }
+        }
+        let expr_in_target = get_expr_set(target_triples);
+        let expr_in_rest = get_expr_set(!target_triples);
+        if !expr_in_target.is_disjoint(&expr_in_rest)
+            || expr_in_target.is_empty()
+            || expr_in_rest.is_empty()
+        {
+            return None;
+        }
+        if expr_in_target.len() <= expr_in_rest.len() {
+            Some(expr_in_target.iter().sorted().join(" || "))
+        } else {
+            Some(expr_in_rest.iter().sorted().map(|&expr| negate(expr)).join(" && "))
+        }
+    }
+
+    /// If `target_triples` can be calculated with a two-dimensional filter
+    /// (e.g. "all triples with (OS=A && Arch=X) or (OS=B && Arch=Y)") then
+    /// returns an expression that represents such a filter.  `get_expr1`
+    /// and or `get_expr2` should typically be `get_gn_os_expr` or
+    /// `get_gn_arch_expr`.
+    fn get_double_filter(
+        target_triples: RustTargetTriple,
+        get_expr1: fn(RustTargetTriple) -> &'static str,
+        get_expr2: fn(RustTargetTriple) -> &'static str,
+    ) -> Option<String> {
+        let mut or_operands = vec![];
+        let chunked = target_triples
+            .iter()
+            .sorted_by_key(|&triple| get_expr1(triple))
+            .chunk_by(|&triple| get_expr1(triple));
+        for (expr1, chunk) in chunked.into_iter() {
+            let target_triples_matching_expr1 = chunk.reduce(|x, y| x | y).unwrap();
+            let all_triples_matching_expr1 = RustTargetTriple::all()
+                .iter()
+                .filter(|&triple| get_expr1(triple) == expr1)
+                .reduce(|x, y| x | y)
+                .expect("Expecting that at least one triple matches");
+            assert!(all_triples_matching_expr1.contains(target_triples_matching_expr1));
+            if target_triples_matching_expr1 == all_triples_matching_expr1 {
+                or_operands.push(expr1.to_string());
+            } else {
+                let expr2_or_operands = target_triples_matching_expr1
+                    .iter()
+                    .map(get_expr2)
+                    .sorted()
+                    .dedup()
+                    .collect_vec();
+                let all_triples_matching_expr1_and_expr2 = all_triples_matching_expr1
+                    .iter()
+                    .filter(|&triple| expr2_or_operands.contains(&get_expr2(triple)))
+                    .reduce(|x, y| x | y)
+                    .expect("Expecting that at least one triple matches");
+                if all_triples_matching_expr1_and_expr2 != target_triples_matching_expr1 {
+                    return None;
+                }
+                let final_expr_for_chunk = match expr2_or_operands.as_slice() {
+                    [] => unreachable!(),
+                    [single_operand] => format!("{expr1} && {single_operand}"),
+                    multiple_operands => {
+                        format!("{expr1} && ({})", multiple_operands.iter().join(" || "),)
+                    }
+                };
+                or_operands.push(final_expr_for_chunk);
+            }
+        }
+        let final_expr_for_target_triples = match or_operands.as_slice() {
+            [] => unreachable!(),
+            [single_operand] => single_operand.clone(),
+            multiple_operands => {
+                multiple_operands.iter().map(|operand| format!("({operand})")).join(" || ")
+            }
+        };
+        Some(final_expr_for_target_triples)
+    }
+
+    /// Translates `RustTargetTriple` into a GN conditional expression that will
+    /// match the GN notion of the OS of that triple.
+    fn get_gn_os_expr(rust_triple: RustTargetTriple) -> &'static str {
+        // `RustTargetOs` and `try_into` come from `target_triples.rs` which is
+        // auto-generated by `gnrt`'s `build.rs`.
+        let rust_os = rust_triple.try_into().expect("`rust_triple` should specify a single triple");
+        match rust_os {
+            RustTargetOs::Android => "is_android",
+            RustTargetOs::Fuchsia => "is_fuchsia",
+            RustTargetOs::Linux => "(is_linux || is_chromeos)",
+            RustTargetOs::Macos => "is_mac",
+            RustTargetOs::Windows => "is_win",
+            RustTargetOs::Ios | RustTargetOs::Tvos => "is_ios",
+        }
+    }
+
+    /// Translates `RustTargetTriple` into a GN conditional expression that will
+    /// match the GN notion of the CPU architecture of that triple.
+    fn get_gn_arch_expr(rust_triple: RustTargetTriple) -> &'static str {
+        // `RustTargetArch` and `try_into` come from `target_triples.rs` which is
+        // auto-generated by `gnrt`'s `build.rs`.
+        let rust_os = rust_triple.try_into().expect("`rust_triple` should specify a single triple");
+        match rust_os {
+            RustTargetArch::Aarch64 => "current_cpu == \"arm64\"",
+            RustTargetArch::Arm => "current_cpu == \"arm\"",
+            RustTargetArch::Riscv64 => "current_cpu == \"riscv64\"",
+            RustTargetArch::X86 => "current_cpu == \"x86\"",
+            RustTargetArch::X8664 => "current_cpu == \"x64\"",
+        }
+    }
+
+    /// Translates `RustTargetTriple` into a GN conditional expression that will
+    /// match the value of `rust_abi_target` as set by
+    /// `//build/config/rust.gni`.
+    fn get_gn_target_triple_expr(rust_triple: RustTargetTriple) -> String {
+        // `as_triple_name` comes from `target_triples.rs` which is auto-generated by
+        // `gnrt`'s `build.rs`.
+        let rust_triple_name =
+            rust_triple.as_triple_name().expect("`rust_triple` should specify a single triple");
+        format!("rust_abi_target == \"{rust_triple_name}\"")
+    }
+}
+
 fn cfg_expr_to_condition(cfg_expr: &cargo_platform::CfgExpr) -> Condition {
     match cfg_expr {
         cargo_platform::CfgExpr::Not(expr) => Condition::not(cfg_expr_to_condition(expr)),
@@ -151,44 +331,57 @@
 fn cfg_to_condition(cfg: &cargo_platform::Cfg) -> Condition {
     match cfg {
         cargo_platform::Cfg::Name(name) => cfg_name_to_condition(name),
-        cargo_platform::Cfg::KeyPair(key, value) => match key.as_ref() {
-            "target_abi" => Condition::Ignored,
-            "target_arch" => target_arch_to_condition(value),
-            "target_env" => target_env_to_condition(value),
-            "target_family" => target_family_to_condition(value),
-            "target_os" => target_os_to_condition(value),
-            "target_vendor" => target_vendor_to_condition(value),
-            "panic" => panic_cfg_to_condition(value),
-            _ => {
-                // Keys that start with `target_` are the only remaining ones that are 1) not
-                // handled above, but 2) listed as set by `rustc` by the documentation at
-                // https://doc.rust-lang.org/reference/conditional-compilation.html
-                if key.starts_with("target_") {
-                    // TODO(https://crbug.com/402096443): Add support for more keys set by `rustc`.
-                    Condition::Unsupported(format!("Not yet supported key `{key}` in `{cfg}`"))
-                } else {
-                    // `key` is not set by `rustc` (i.e. it is not documented in
-                    // https://doc.rust-lang.org/reference/conditional-compilation.html and not
-                    // handled above).  Therefore we assume that Chromium will never ask GN/ninja
-                    // to pass `--cfg 'this_unrecognized_key="something"'` to `rustc`.  And
-                    // therefore we treat this as `AlwaysFalse`.  See also
-                    // https://crbug.com/404598090#comment4.
-                    log::warn!(
-                        "Treating unrecogized `#[cfg({key} = \"{value}\")]` as `AlwaysFalse"
-                    );
-                    Condition::AlwaysFalse
-                }
-            }
-        },
+        cargo_platform::Cfg::KeyPair(key, value) => cfg_key_value_pair_to_condition(key, value),
     }
 }
 
+/// A mapping from 1) name of Rust condition key (e.g. `target_os`,
+/// `target_env`, etc) and 2) value of Rust condition key (e.g. `msvc` or `gnu`
+/// for `target_env`) into 3) a set of `RustTargetTriple`s where this condition
+/// is true (e.g. `target_env = "msvc"` is true for all 3 of Chromium Windows
+/// target triples).
+static PROP_NAME_TO_PROP_VALUE_TO_TRIPLE_SET: LazyLock<
+    HashMap<&str, HashMap<&str, RustTargetTriple>>,
+> = LazyLock::new(|| {
+    // `RUST_TRIPLE_PROPERTIES` comes from `target_triples.rs` which is
+    // auto-generated by `gnrt`'s `build.rs`.
+    let mut result: HashMap<_, HashMap<_, _>> = HashMap::new();
+    for (triple, prop_name, prop_value) in RUST_TRIPLE_PROPERTIES {
+        let triple = triple.parse().unwrap();
+        let sets = result.entry(prop_name).or_default().entry(prop_value).or_insert(triple);
+        *sets |= triple;
+    }
+    result
+});
+
+fn cfg_key_value_pair_to_condition(key: &str, value: &str) -> Condition {
+    if key == "panic" {
+        return panic_cfg_to_condition(value);
+    }
+
+    if let Some(value_to_triple_set_map) = PROP_NAME_TO_PROP_VALUE_TO_TRIPLE_SET.get(key) {
+        match value_to_triple_set_map.get(value) {
+            None => return Condition::AlwaysFalse,
+            Some(set) => return Condition::TripleSet(*set),
+        }
+    }
+
+    // `key` is not set by `rustc` (i.e. it is not documented in
+    // https://doc.rust-lang.org/reference/conditional-compilation.html and not
+    // handled above).  Therefore we assume that Chromium will never ask GN/ninja
+    // to pass `--cfg 'this_unrecognized_key="something"'` to `rustc`.  And
+    // therefore we treat this as `AlwaysFalse`.  See also
+    // https://crbug.com/404598090#comment4.
+    log::warn!("Treating unrecogized `#[cfg({key} = \"{value}\")]` as `AlwaysFalse");
+    Condition::AlwaysFalse
+}
+
 /// `name` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#r-cfg.option-name
 fn cfg_name_to_condition(name: &str) -> Condition {
     // See https://doc.rust-lang.org/reference/conditional-compilation.html#unix-and-windows
     const FAMILY_NAMES: [&str; 2] = ["unix", "windows"];
     if FAMILY_NAMES.contains(&name) {
-        return target_family_to_condition(name);
+        return cfg_key_value_pair_to_condition("target_family", name);
     }
 
     // We don't support `windows_raw_dylib` in Chromium.  See also
@@ -199,20 +392,34 @@
 
     // See https://doc.rust-lang.org/reference/conditional-compilation.html#debug_assertions
     if name == "debug_assertions" {
-        return Condition::Expr("is_debug".to_string());
+        // Returning `AlwaysTrue` is not 100% correct and may bring in unnecessary
+        // dependencies. But this conservative behavior shouldn't cause any
+        // major issues.
+        //
+        // TODO(https://crbug.com/402096443): Handle this by tracking not only a set of
+        // `RustTargetTriple` but also a parallel bitflag of `RustDebugConfig` (with
+        // just two bits - on and off).
+        return Condition::AlwaysTrue;
     }
 
     // See https://doc.rust-lang.org/reference/conditional-compilation.html#test
-    //
-    // TODO(https://crbug.com/402096443): Add support for `#[cfg(test)]`.
     if name == "test" {
-        return Condition::Unsupported("`#[cfg(test)]` is not yet supported by `gnrt`".to_string());
+        // Returning `AlwaysTrue` is not 100% correct and may bring in unnecessary
+        // dependencies. But this seems unlikely, given that test-only
+        // dependencies should be listed in the `[dev-dependencies]` section of
+        // `Cargo.toml` and reported as `guppy::DependencyKind::Development`.
+        // At any rate, this conservative behavior shouldn't cause any major
+        // issues.
+        //
+        // TODO(https://crbug.com/402096443): Handle this better.
+        return Condition::AlwaysTrue;
     }
 
     // `name` is not something that is documented in
     // https://doc.rust-lang.org/reference/conditional-compilation.html.  We assume that Chromium
     // will never ask GN/ninja to pass `--cfg this_unrecognized_name` to `rustc`.
-    // And therefore we treat this as `AlwaysFalse`.  See also https://crbug.com/404598090#comment4.
+    // And therefore we treat this as `AlwaysFalse`.  See also
+    // https://crbug.com/404598090#comment4.
     log::warn!("Treating unrecogized `#[cfg({name})]` as `AlwaysFalse");
     Condition::AlwaysFalse
 }
@@ -231,168 +438,16 @@
 }
 
 fn triple_to_condition(triple: &str) -> Condition {
-    for (t, c) in &[
-        ("i686-linux-android", "is_android && current_cpu == \"x86\""),
-        ("x86_64-linux-android", "is_android && current_cpu == \"x64\""),
-        ("armv7-linux-android", "is_android && current_cpu == \"arm\""),
-        ("aarch64-linux-android", "is_android && current_cpu == \"arm64\""),
-        ("aarch64-fuchsia", "is_fuchsia && current_cpu == \"arm64\""),
-        ("x86_64-fuchsia", "is_fuchsia && current_cpu == \"x64\""),
-        ("aarch64-apple-ios", "is_ios && current_cpu == \"arm64\""),
-        ("armv7-apple-ios", "is_ios && current_cpu == \"arm\""),
-        ("x86_64-apple-ios", "is_ios && current_cpu == \"x64\""),
-        ("i386-apple-ios", "is_ios && current_cpu == \"x86\""),
-        ("i686-pc-windows-msvc", "is_win && current_cpu == \"x86\""),
-        ("x86_64-pc-windows-msvc", "is_win && current_cpu == \"x64\""),
-        ("i686-unknown-linux-gnu", "(is_linux || is_chromeos) && current_cpu == \"x86\""),
-        ("x86_64-unknown-linux-gnu", "(is_linux || is_chromeos) && current_cpu == \"x64\""),
-        ("x86_64-apple-darwin", "is_mac && current_cpu == \"x64\""),
-        ("aarch64-apple-darwin", "is_mac && current_cpu == \"arm64\""),
-    ] {
-        if *t == triple {
-            return Condition::Expr(c.to_string());
-        }
+    match triple.parse() {
+        Ok(set) => Condition::TripleSet(set),
+        Err(_) => Condition::AlwaysFalse,
     }
-
-    // Other target triples are never used in Chromium builds.
-    Condition::AlwaysFalse
 }
 
-/// `target_arch` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch
-fn target_arch_to_condition(target_arch: &str) -> Condition {
-    for (t, c) in &[
-        ("aarch64", "current_cpu == \"arm64\""),
-        ("arm", "current_cpu == \"arm\""),
-        ("x86", "current_cpu == \"x86\""),
-        ("x86_64", "current_cpu == \"x64\""),
-        // `riscv64gc-unknown-linux-gnu` from `build/config/rust.gni` resolves to
-        // `target_os = "riscv64"`.  And `gn help target_cpu` says that this has
-        // the same spelling as GN's `current_cpu`.
-        ("riscv64", "current_cpu == \"riscv64\""),
-    ] {
-        if *t == target_arch {
-            return Condition::Expr(c.to_string());
-        }
-    }
-
-    // Other `target_arch` values are never used in Chromium builds.
-    // Examples: "mipc", "powerpc".
-    Condition::AlwaysFalse
-}
-
-/// `target_env` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#target_env
-fn target_env_to_condition(target_env: &str) -> Condition {
-    // Based on https://crbug.com/402096443#comment6 target triples supported by Chromium
-    // only use `target_env` set to either `msvc`, `gnu`, or an empty string.
-    for (t, c) in &[
-        // `msvc` is the only supported environment on Windows.
-        //
-        // TODO(https://crbug.com/402096443): Would returning `Condition::Expr("is_win")` be more
-        // correct?
-        ("msvc", Condition::AlwaysTrue),
-        // Treating `gnu` as `AlwaysFalse`, because:
-        //
-        // * This is how `gnrt` worked in the past
-        // * This helps to filter out packages like `windows_i686_gnu` (this is desirable, because
-        //   Chromium only supports `msvc` environment on Windows.
-        //
-        // OTOH, maybe this is not quite right, because Chromium also supports triples like
-        // "i686-unknown-linux-gnu".
-        //
-        // TODO(https://crbug.com/402096443): Would returning
-        // `Condition::Expr(CONDITION_FOR_TARGET_OS_LINUX.to_string())` be more correct?
-        // OTOH `AlwaysFalse` will trim a dependency, but a more complicated
-        // expression that may be equivalent to `AlwaysFalse` will not trim...
-        ("gnu", Condition::AlwaysFalse),
-        // Based on https://crbug.com/402096443#comment6, an empty `target_env` is only
-        // used in the following cases:
-        ("", Condition::Expr("is_android || is_apple || is_fuchsia".to_string())),
-    ] {
-        if *t == target_env {
-            return c.clone();
-        }
-    }
-
-    // Other `target_env` values are never used by target triples supported by
-    // Chromium. For example, `sgx` is used as condition in `dlmalloc` package
-    // in `std` library, but this condition will never be true in Chromium
-    // builds.
-    Condition::AlwaysFalse
-}
-
-/// `target_family` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#target_family
-fn target_family_to_condition(target_family: &str) -> Condition {
-    for (t, c) in &[
-        // Note that while Fuchsia is not a unix, rustc sets the unix cfg
-        // anyway. We must be consistent with rustc. This may change with
-        // https://github.com/rust-lang/rust/issues/58590
-        ("unix", "!is_win"),
-        ("windows", "is_win"),
-    ] {
-        if *t == target_family {
-            return Condition::Expr(c.to_string());
-        }
-    }
-
-    // Other `target_family` values are never used in Chromium builds.
-    // Example: "wasm".
-    Condition::AlwaysFalse
-}
-
-/// `target_os` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#target_os
-fn target_os_to_condition(target_os: &str) -> Condition {
-    for (t, c) in &[
-        ("android", "is_android"),
-        // `rustc --print=cfg --target=aarch64-apple-darwin` prints `macos`, not `darwin`.
-        ("macos", "is_mac"),
-        ("fuchsia", "is_fuchsia"),
-        ("ios", "is_ios"),
-        ("linux", CONDITION_FOR_TARGET_OS_LINUX),
-        ("windows", "is_win"),
-        // TODO(https://crbug.com/402096443): Consider also mapping "tvos"
-        // (since `aarch64-apple-tvos` is listed in `build/config/rust.gni`)
-    ] {
-        if *t == target_os {
-            return Condition::Expr(c.to_string());
-        }
-    }
-
-    // Other `target_os` values are never used in Chromium builds.
-    // Examples: "freebsd", "macos" (not sure why "darwin" is preferred...).
-    Condition::AlwaysFalse
-}
-
-/// `target_vendor` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor
-fn target_vendor_to_condition(target_vendor: &str) -> Condition {
-    for (t, c) in &[("apple", "is_apple"), ("pc", "is_win")] {
-        if *t == target_vendor {
-            return Condition::Expr(c.to_string());
-        }
-    }
-
-    const UNSUPPORTED_VENDORS: [&str; 2] = [
-        "fortanix", // Used as condition in `dlmalloc` package used in `std` library.
-        "uwp",      // Used as condition in some `windows...` crates.
-    ];
-    if UNSUPPORTED_VENDORS.contains(&target_vendor) {
-        return Condition::AlwaysFalse;
-    }
-
-    Condition::Unsupported(format!("unknown `target_vendor` name: `{target_vendor}`"))
-}
-
-/// GN condition corresponding to `target_os` being set to `linux` in `rustc`.
-///
-/// `//build/config/BUILDCONFIG.gn` treats `is_linux` and `is_chromeos` as
-/// mutually exclusive, but at `rustc`-level they are both `target_os = "linux"`
-/// (and `target_env = "gnu"`).  Both of these `rustc`-level values can be taken
-/// directly from the target triple, but we have also directly verified via
-/// `rustc --print=cfg` - see https://crbug.com/402096443#comment6.
-const CONDITION_FOR_TARGET_OS_LINUX: &str = "is_linux || is_chromeos";
-
 #[cfg(test)]
 mod tests {
     use super::Condition;
+    use crate::target_triple::RustTargetTriple;
 
     fn condition_from_test_triple(triple: &str) -> Condition {
         let spec = target_spec::TargetSpec::PlainString(
@@ -408,58 +463,109 @@
         Condition::from_target_spec(&spec)
     }
 
+    fn gn_condition_from_test_expr(expr: &str) -> String {
+        let condition = condition_from_test_expr(expr);
+        match condition.to_handlebars_value() {
+            Ok(Some(s)) => s,
+            Ok(None) => panic!("Got `AlwaysTrue` / `None` when formatting `{expr}`"),
+            Err(err) => panic!("Error when formatting `{expr}`: `{err}`"),
+        }
+    }
+
     #[test]
     fn test_target_spec_to_condition() {
         // Try a target triple.
         assert_eq!(
-            condition_from_test_triple("x86_64-pc-windows-msvc"),
-            Condition::Expr("is_win && current_cpu == \"x64\"".to_string()),
+            condition_from_test_triple("x86_64-pc-windows-msvc").to_handlebars_value().unwrap(),
+            Some("is_win && current_cpu == \"x64\"".to_string()),
         );
 
         // Try a cfg expression.
         assert_eq!(
-            condition_from_test_expr("any(windows, target_os = \"android\")"),
-            Condition::Expr("(is_android) || (is_win)".to_string()),
+            gn_condition_from_test_expr("any(windows, target_os = \"android\")"),
+            "is_android || is_win",
         );
 
         // Redundant cfg expression.
+        assert_eq!(gn_condition_from_test_expr("any(windows, windows)"), "is_win",);
+
+        // Testing for brevity (e.g. `!is_win` is shorted than `is_ios || is_linux ||
+        // ...`).
+        assert_eq!(gn_condition_from_test_expr("windows"), "is_win",);
+        assert_eq!(gn_condition_from_test_expr("unix"), "!is_win",);
         assert_eq!(
-            condition_from_test_expr("any(windows, windows)"),
-            Condition::Expr("is_win".to_string()),
+            gn_condition_from_test_expr("target_arch = \"x86_64\""),
+            "current_cpu == \"x64\"",
+        );
+        assert_eq!(
+            gn_condition_from_test_expr("not(target_arch = \"x86_64\")"),
+            "current_cpu != \"x64\"",
+        );
+
+        // Try sets of target triples that cannot be uniquely identified with GN
+        // OS+arch.
+        let triple1 = condition_from_test_triple("aarch64-apple-tvos");
+        let triple2 = condition_from_test_triple("aarch64-apple-tvos-sim");
+        assert_eq!(
+            triple1.to_handlebars_value().unwrap(),
+            Some("rust_abi_target == \"aarch64-apple-tvos\"".to_string()),
+        );
+        assert_eq!(
+            Condition::or(triple1, triple2).to_handlebars_value().unwrap(),
+            Some(
+                "\
+                rust_abi_target == \"aarch64-apple-tvos\" || \
+                rust_abi_target == \"aarch64-apple-tvos-sim\""
+                    .to_string()
+            ),
         );
 
         // Try a PlatformSet with multiple filters.
-        let filter1 = condition_from_test_triple("armv7-linux-android");
+        let filter1 = condition_from_test_expr(
+            "all(target_os = \"android\", \
+                                                    target_arch = \"arm\")",
+        );
         let filter2 = condition_from_test_expr("windows");
         assert_eq!(
-            Condition::or(filter1, filter2),
-            Condition::Expr("(is_android && current_cpu == \"arm\") || (is_win)".to_string()),
+            Condition::or(filter1, filter2).to_handlebars_value().unwrap(),
+            Some("(is_android && current_cpu == \"arm\") || (is_win)".to_string()),
         );
 
         // A cfg expression on arch only.
         assert_eq!(
-            condition_from_test_expr("target_arch = \"aarch64\""),
-            Condition::Expr("current_cpu == \"arm64\"".to_string()),
+            gn_condition_from_test_expr("target_arch = \"aarch64\""),
+            "current_cpu == \"arm64\"",
         );
 
         // A cfg expression on arch and OS (but not via the target triple string).
         assert_eq!(
-            condition_from_test_expr("all(target_arch = \"aarch64\", unix)"),
-            Condition::Expr("(!is_win) && (current_cpu == \"arm64\")".to_string()),
+            gn_condition_from_test_expr("all(target_arch = \"aarch64\", unix)"),
+            "current_cpu == \"arm64\" && (\
+                (is_linux || is_chromeos) || \
+                is_android || \
+                is_fuchsia || \
+                is_ios || \
+                is_mac)",
         );
 
-        // A cfg expression taken from `windows_aarch64_msvc` package.
+        // A cfg expression taken from `windows-targets-v0_52/Cargo.toml`
+        // (condition for depending on `windows_x86_64_msvc`).
         assert_eq!(
-            condition_from_test_expr(
+            gn_condition_from_test_expr(
                 "all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), \
                      target_env = \"msvc\", \
                      not(windows_raw_dylib))"
             ),
-            Condition::Expr("current_cpu == \"x64\"".to_string()),
+            "is_win && current_cpu == \"x64\"",
         );
 
-        // A cfg expression taken from `windows-targets` => `windows_i686_gnu`
-        // dependency.
+        // A cfg expression taken from `windows-targets-v0_52/Cargo.toml` (condition for
+        // depending on `windows_i686_gnu`).  When Chromium targets Windows, it
+        // always uses `msvc` (rather than `gnu`) environment - this is why we'd
+        // like to expect `AlwaysFalse` result here. But to get `AlwaysFalse` we
+        // need to know that this condition is only evaluated when the parent/
+        // dependent crate is a Windows-only crate - this is covered by unit tests
+        // in `deps.rs`.
         assert_eq!(
             condition_from_test_expr(
                 "all(target_arch = \"x86\", \
@@ -467,45 +573,39 @@
                      not(target_abi = \"llvm\"), \
                      not(windows_raw_dylib))"
             ),
-            Condition::AlwaysFalse,
+            Condition::TripleSet(RustTargetTriple::I686_UNKNOWN_LINUX_GNU),
         );
 
         // Cfg expressions taken from `getrandom-0.3` => `libc` dependency.
         assert_eq!(
-            condition_from_test_expr(
+            gn_condition_from_test_expr(
                 "any(                         \
                     target_os = \"ios\",      \
                     target_os = \"visionos\", \
                     target_os = \"watchos\",  \
                     target_os = \"tvos\")",
             ),
-            Condition::Expr("is_ios".to_string()),
+            "is_ios",
         );
         assert_eq!(
-            condition_from_test_expr(
+            gn_condition_from_test_expr(
                 "any(                        \
                     target_os = \"macos\",   \
                     target_os = \"openbsd\", \
                     target_os = \"vita\",    \
                     target_os = \"emscripten\")",
             ),
-            Condition::Expr("is_mac".to_string()),
+            "is_mac",
         );
         assert_eq!(
             condition_from_test_expr(
                 // Simplification of one of the real expressions below.
                 "all(target_os = \"linux\", target_env = \"\")",
             ),
-            // TODO(lukasza): Ideally `gnrt` would understand that the condition below is kind of
-            // equivalent to `AlwaysFalse`... :-/
-            Condition::Expr(
-                "(is_android || is_apple || is_fuchsia) && \
-                 (is_linux || is_chromeos)"
-                    .to_string()
-            ),
+            Condition::AlwaysFalse,
         );
         assert_eq!(
-            condition_from_test_expr(
+            gn_condition_from_test_expr(
                 "all(                                                      \
                     any(target_os = \"linux\", target_os = \"android\"),   \
                     not(any(                                               \
@@ -515,11 +615,7 @@
                             getrandom_backend = \"rdrand\",                \
                             getrandom_backend = \"rndr\")))",
             ),
-            Condition::Expr(
-                "(!((is_android || is_apple || is_fuchsia) && (is_linux || is_chromeos))) && \
-                 ((is_android) || (is_linux || is_chromeos))"
-                    .to_string()
-            ),
+            "(is_linux || is_chromeos) || is_android",
         );
     }
 }
diff --git a/tools/crates/gnrt/lib/deps.rs b/tools/crates/gnrt/lib/deps.rs
index 9cec1f4..eae2413 100644
--- a/tools/crates/gnrt/lib/deps.rs
+++ b/tools/crates/gnrt/lib/deps.rs
@@ -247,12 +247,14 @@
     extra_config: &BuildConfig,
 ) -> Result<Vec<Package>> {
     // Ask `guppy` to run Cargo feature/dependency resolution.
+    let mut memoization_tables = MemoizationTables::new();
     let cargo_set = {
         let cargo_options = CargoOptions::new();
         let initials = resolve_root_package_set(graph, root_package_name)?
             .to_feature_set(StandardFeatures::Default);
         let no_extra_features = graph.resolve_none().to_feature_set(StandardFeatures::Default);
-        let resolver = PackageResolver { extra_config };
+        let resolver =
+            PackageResolver { extra_config, memoization_tables: &mut memoization_tables };
         CargoSet::with_package_resolver(initials, no_extra_features, resolver, &cargo_options)?
     };
     let cargo_set_links = cargo_set
@@ -276,17 +278,18 @@
     let is_toplevel_dep = |package: &PackageMetadata| -> bool {
         package.reverse_direct_links().any(|link| link.from().name() == root_package_name)
     };
-    let get_dependency_condition = |link: &PackageLink, dep_kind: DependencyKind| -> Condition {
-        let key = get_link_key(link);
-        if !cargo_set_links.contains(&key) {
-            return Condition::AlwaysFalse;
-        }
-        let dep_kind = match dep_kind {
-            DependencyKind::Normal => guppy::DependencyKind::Normal,
-            DependencyKind::Build => guppy::DependencyKind::Build,
+    let mut get_dependency_condition =
+        |link: &PackageLink, dep_kind: DependencyKind| -> Condition {
+            let key = get_link_key(link);
+            if !cargo_set_links.contains(&key) {
+                return Condition::AlwaysFalse;
+            }
+            let dep_kind = match dep_kind {
+                DependencyKind::Normal => guppy::DependencyKind::Normal,
+                DependencyKind::Build => guppy::DependencyKind::Build,
+            };
+            memoization_tables.get_link_condition(link, dep_kind)
         };
-        get_link_condition(link, dep_kind)
-    };
     let mut packages = package_set
         .packages(DependencyDirection::Forward)
         .filter(|package| package.name() != root_package_name)
@@ -299,7 +302,7 @@
                 get_dependency_condition(link, DependencyKind::Build)
             });
             let dependency_kinds =
-                get_reverse_dependency_kinds(&package, &cargo_set, get_dependency_condition);
+                get_reverse_dependency_kinds(&package, &cargo_set, &mut get_dependency_condition);
 
             let BuildTargets { lib_target, bin_targets, build_script } =
                 get_build_targets(&package, extra_config).with_context(err_context)?;
@@ -354,6 +357,7 @@
 /// `AlwaysFalse` on Chromium platforms.
 struct PackageResolver<'a> {
     extra_config: &'a BuildConfig,
+    memoization_tables: &'a mut MemoizationTables,
 }
 
 /// Gets the key to use in `cargo_set_links` `HashSet`.
@@ -363,15 +367,52 @@
     (from.into(), to.into())
 }
 
-fn get_link_condition(link: &PackageLink, dep_kind: guppy::DependencyKind) -> Condition {
-    let req = link.req_for_kind(dep_kind);
-    if !req.is_present() {
-        Condition::AlwaysFalse
-    } else {
-        Condition::or(
-            get_condition(req.status().required_status()),
-            get_condition(req.status().optional_status()),
-        )
+struct MemoizationTables {
+    package_conditions: HashMap<PackageId, Condition>,
+}
+
+impl MemoizationTables {
+    fn new() -> Self {
+        Self { package_conditions: HashMap::new() }
+    }
+
+    fn get_package_condition(&mut self, package: &PackageMetadata) -> Condition {
+        if let Some(condition) = self.package_conditions.get(&package.into()) {
+            return condition.clone();
+        }
+
+        let condition = package
+            .reverse_direct_links()
+            .flat_map(|link| {
+                [
+                    self.get_link_condition(&link, guppy::DependencyKind::Normal),
+                    self.get_link_condition(&link, guppy::DependencyKind::Build),
+                ]
+            })
+            .reduce(Condition::or)
+            .unwrap_or(Condition::AlwaysTrue);
+        self.package_conditions.insert(package.into(), condition.clone());
+        condition
+    }
+
+    fn get_link_condition(
+        &mut self,
+        link: &PackageLink,
+        dep_kind: guppy::DependencyKind,
+    ) -> Condition {
+        let req = link.req_for_kind(dep_kind);
+        if !req.is_present() {
+            Condition::AlwaysFalse
+        } else {
+            let baseline_condition = self.get_package_condition(&link.from());
+            Condition::and(
+                baseline_condition,
+                Condition::or(
+                    get_condition(req.status().required_status()),
+                    get_condition(req.status().optional_status()),
+                ),
+            )
+        }
     }
 }
 
@@ -389,8 +430,9 @@
 
         // Check if the dependency is conditional, and reject the dependency if
         // the condition is never met on Chromium platforms.
-        let normal_condition = get_link_condition(&link, guppy::DependencyKind::Normal);
-        let build_condition = get_link_condition(&link, guppy::DependencyKind::Build);
+        let mut get_condition = |kind| self.memoization_tables.get_link_condition(&link, kind);
+        let normal_condition = get_condition(guppy::DependencyKind::Normal);
+        let build_condition = get_condition(guppy::DependencyKind::Build);
         if normal_condition.is_always_false() && build_condition.is_always_false() {
             return false;
         }
@@ -403,7 +445,7 @@
 fn get_reverse_dependency_kinds(
     package: &PackageMetadata,
     cargo_set: &CargoSet,
-    condition_getter: impl for<'a> Fn(&PackageLink<'a>, DependencyKind) -> Condition,
+    mut condition_getter: impl for<'a> FnMut(&PackageLink<'a>, DependencyKind) -> Condition,
 ) -> HashMap<DependencyKind, PerKindInfo> {
     let get_features = |feature_set: &FeatureSet| -> Vec<String> {
         feature_set
@@ -460,7 +502,7 @@
 
 fn get_package_dependencies(
     package: &PackageMetadata,
-    condition_getter: impl for<'a> Fn(&PackageLink<'a>) -> Condition,
+    mut condition_getter: impl for<'a> FnMut(&PackageLink<'a>) -> Condition,
 ) -> Vec<DepOfDep> {
     package
         .direct_links()
@@ -836,14 +878,12 @@
         );
         assert_eq!(dependencies[i].dependencies.len(), 1);
         assert_eq!(dependencies[i].build_dependencies.len(), 0);
+        assert_eq!(dependencies[i].dependencies[0].package_name, "winapi-util");
+        assert_eq!(dependencies[i].dependencies[0].use_name, "winapi_util");
+        assert_eq!(dependencies[i].dependencies[0].version, Version::new(0, 1, 5));
         assert_eq!(
-            dependencies[i].dependencies[0],
-            DepOfDep {
-                package_name: "winapi-util".to_string(),
-                use_name: "winapi_util".to_string(),
-                version: Version::new(0, 1, 5),
-                condition: Condition::Expr("is_win".to_string()),
-            }
+            dependencies[i].dependencies[0].condition.to_handlebars_value().unwrap(),
+            Some("is_win".to_string()),
         );
 
         i += 1;
@@ -857,23 +897,17 @@
             &["alloc", "default", "std"]
         );
         assert_eq!(dependencies[i].dependencies.len(), 2);
+        assert_eq!(dependencies[i].dependencies[0].package_name, "libc");
+        assert_eq!(dependencies[i].dependencies[0].version, Version::new(0, 2, 133));
         assert_eq!(
-            dependencies[i].dependencies[0],
-            DepOfDep {
-                package_name: "libc".to_string(),
-                use_name: "libc".to_string(),
-                version: Version::new(0, 2, 133),
-                condition: Condition::Expr("!is_win".to_string()),
-            }
+            dependencies[i].dependencies[0].condition.to_handlebars_value().unwrap(),
+            Some("!is_win".to_string()),
         );
+        assert_eq!(dependencies[i].dependencies[1].package_name, "num_threads");
+        assert_eq!(dependencies[i].dependencies[1].version, Version::new(0, 1, 6));
         assert_eq!(
-            dependencies[i].dependencies[1],
-            DepOfDep {
-                package_name: "num_threads".to_string(),
-                use_name: "num_threads".to_string(),
-                version: Version::new(0, 1, 6),
-                condition: Condition::Expr("!is_win".to_string()),
-            }
+            dependencies[i].dependencies[1].condition.to_handlebars_value().unwrap(),
+            Some("!is_win".to_string()),
         );
 
         i += 1;
@@ -913,19 +947,16 @@
         assert_eq!(dependencies[i].version, Version::new(0, 1, 5));
         assert!(dependencies[i].dependency_kinds.get(&DependencyKind::Normal).is_some_and(|d| {
             assert_eq!(d.features, empty_str_slice);
-            assert_eq!(d.condition, Condition::Expr("is_win".to_string()));
+            assert_eq!(d.condition.to_handlebars_value().unwrap(), Some("is_win".to_string()),);
             true
         }));
         assert_eq!(dependencies[i].dependencies.len(), 1);
         assert_eq!(dependencies[i].build_dependencies.len(), 0);
+        assert_eq!(dependencies[i].dependencies[0].package_name, "winapi");
+        assert_eq!(dependencies[i].dependencies[0].version, Version::new(0, 3, 9));
         assert_eq!(
-            dependencies[i].dependencies[0],
-            DepOfDep {
-                package_name: "winapi".to_string(),
-                use_name: "winapi".to_string(),
-                version: Version::new(0, 3, 9),
-                condition: Condition::Expr("is_win".to_string()),
-            }
+            dependencies[i].dependencies[0].condition.to_handlebars_value().unwrap(),
+            Some("is_win".to_string()),
         );
 
         i += 1;
@@ -988,7 +1019,6 @@
 
         // Verify that `num_threads` got removed.
         for package in dependencies.iter() {
-            dbg!(&package.package_name);
             assert_ne!(package.package_name, "num_threads");
             assert!(!package
                 .build_dependencies
@@ -1077,4 +1107,28 @@
     // `gnrt/sample_package2` directory.  See the `Cargo.toml` for more
     // information.
     static SAMPLE_CARGO_METADATA2: &str = include_str!("test_metadata2.json");
+
+    #[test]
+    fn collect_dependencies_on_sample_output3() {
+        let config = BuildConfig::default();
+        let metadata = PackageGraph::from_json(SAMPLE_CARGO_METADATA3).unwrap();
+        let dependencies = collect_dependencies(&metadata, "sample_package3", &config).unwrap();
+        let dependencies = dependencies
+            .into_iter()
+            .map(|package| (package.package_name.to_string(), package))
+            .collect::<HashMap<_, _>>();
+        assert!(!dependencies.contains_key("windows_aarch64_gnullvm"));
+        assert!(dependencies.contains_key("windows_aarch64_msvc"));
+        assert!(!dependencies.contains_key("windows_i686_gnu"));
+        assert!(!dependencies.contains_key("windows_i686_gnullvm"));
+        assert!(dependencies.contains_key("windows_i686_msvc"));
+        assert!(!dependencies.contains_key("windows_x86_64_gnu"));
+        assert!(!dependencies.contains_key("windows_x86_64_gnullvm"));
+        assert!(dependencies.contains_key("windows_x86_64_msvc"));
+    }
+
+    // `test_metadata3.json` contains the output of `cargo metadata` run in
+    // `gnrt/sample_package3` directory.  See the `Cargo.toml` for more
+    // information.
+    static SAMPLE_CARGO_METADATA3: &str = include_str!("test_metadata3.json");
 }
diff --git a/tools/crates/gnrt/lib/lib.rs b/tools/crates/gnrt/lib/lib.rs
index f99d53c2..b022e5f 100644
--- a/tools/crates/gnrt/lib/lib.rs
+++ b/tools/crates/gnrt/lib/lib.rs
@@ -15,5 +15,8 @@
 pub mod manifest;
 pub mod paths;
 pub mod readme;
+pub mod target_triple {
+    include!(concat!(env!("OUT_DIR"), "/target_triple.rs"));
+}
 pub mod util;
 pub mod vet;
diff --git a/tools/crates/gnrt/lib/test_metadata3.json b/tools/crates/gnrt/lib/test_metadata3.json
new file mode 100644
index 0000000..0bdbd3e
--- /dev/null
+++ b/tools/crates/gnrt/lib/test_metadata3.json
@@ -0,0 +1 @@
+{"packages":[{"name":"sample_package3","version":"0.1.0","id":"path+file:///usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3#0.1.0","license":null,"license_file":null,"description":null,"source":null,"dependencies":[{"name":"termcolor","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^1.4.1","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":null,"registry":null}],"targets":[{"kind":["bin"],"crate_types":["bin"],"name":"sample_package3","src_path":"/usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3/src/main.rs","edition":"2021","doc":true,"doctest":false,"test":true}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3/Cargo.toml","metadata":null,"publish":null,"authors":[],"categories":[],"keywords":[],"readme":"README.md","repository":null,"homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":null},{"name":"termcolor","version":"1.4.1","id":"registry+https://github.com/rust-lang/crates.io-index#termcolor@1.4.1","license":"Unlicense OR MIT","license_file":null,"description":"A simple cross platform library for writing colored text to a terminal.\n","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[{"name":"winapi-util","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.1.3","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"cfg(windows)","registry":null}],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"termcolor","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/termcolor-1.4.1/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/termcolor-1.4.1/Cargo.toml","metadata":null,"publish":null,"authors":["Andrew Gallant <jamslam@gmail.com>"],"categories":[],"keywords":["windows","win","color","ansi","console"],"readme":"README.md","repository":"https://github.com/BurntSushi/termcolor","homepage":"https://github.com/BurntSushi/termcolor","documentation":"https://docs.rs/termcolor","edition":"2018","links":null,"default_run":null,"rust_version":null},{"name":"winapi-util","version":"0.1.9","id":"registry+https://github.com/rust-lang/crates.io-index#winapi-util@0.1.9","license":"Unlicense OR MIT","license_file":null,"description":"A dumping ground for high level safe wrappers over windows-sys.","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[{"name":"windows-sys","source":"registry+https://github.com/rust-lang/crates.io-index","req":">=0.48.0, <=0.59","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":["Win32_Foundation","Win32_Storage_FileSystem","Win32_System_Console","Win32_System_SystemInformation"],"target":"cfg(windows)","registry":null}],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"winapi_util","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/winapi-util-0.1.9/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/winapi-util-0.1.9/Cargo.toml","metadata":{"docs":{"rs":{"targets":["x86_64-pc-windows-msvc"]}}},"publish":null,"authors":["Andrew Gallant <jamslam@gmail.com>"],"categories":["os::windows-apis","external-ffi-bindings"],"keywords":["windows","windows-sys","util","win"],"readme":"README.md","repository":"https://github.com/BurntSushi/winapi-util","homepage":"https://github.com/BurntSushi/winapi-util","documentation":"https://docs.rs/winapi-util","edition":"2021","links":null,"default_run":null,"rust_version":null},{"name":"windows-sys","version":"0.59.0","id":"registry+https://github.com/rust-lang/crates.io-index#windows-sys@0.59.0","license":"MIT OR Apache-2.0","license_file":null,"description":"Rust for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[{"name":"windows-targets","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":null,"registry":null}],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_sys","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows-sys-0.59.0/src/lib.rs","edition":"2021","doc":true,"doctest":false,"test":false}],"features":{"Wdk":["Win32_Foundation"],"Wdk_Devices":["Wdk"],"Wdk_Devices_Bluetooth":["Wdk_Devices"],"Wdk_Devices_HumanInterfaceDevice":["Wdk_Devices"],"Wdk_Foundation":["Wdk"],"Wdk_Graphics":["Wdk"],"Wdk_Graphics_Direct3D":["Wdk_Graphics"],"Wdk_NetworkManagement":["Wdk"],"Wdk_NetworkManagement_Ndis":["Wdk_NetworkManagement"],"Wdk_NetworkManagement_WindowsFilteringPlatform":["Wdk_NetworkManagement"],"Wdk_Storage":["Wdk"],"Wdk_Storage_FileSystem":["Wdk_Storage"],"Wdk_Storage_FileSystem_Minifilters":["Wdk_Storage_FileSystem"],"Wdk_System":["Wdk"],"Wdk_System_IO":["Wdk_System"],"Wdk_System_Memory":["Wdk_System"],"Wdk_System_OfflineRegistry":["Wdk_System"],"Wdk_System_Registry":["Wdk_System"],"Wdk_System_SystemInformation":["Wdk_System"],"Wdk_System_SystemServices":["Wdk_System"],"Wdk_System_Threading":["Wdk_System"],"Win32":["Win32_Foundation"],"Win32_Data":["Win32"],"Win32_Data_HtmlHelp":["Win32_Data"],"Win32_Data_RightsManagement":["Win32_Data"],"Win32_Devices":["Win32"],"Win32_Devices_AllJoyn":["Win32_Devices"],"Win32_Devices_BiometricFramework":["Win32_Devices"],"Win32_Devices_Bluetooth":["Win32_Devices"],"Win32_Devices_Communication":["Win32_Devices"],"Win32_Devices_DeviceAndDriverInstallation":["Win32_Devices"],"Win32_Devices_DeviceQuery":["Win32_Devices"],"Win32_Devices_Display":["Win32_Devices"],"Win32_Devices_Enumeration":["Win32_Devices"],"Win32_Devices_Enumeration_Pnp":["Win32_Devices_Enumeration"],"Win32_Devices_Fax":["Win32_Devices"],"Win32_Devices_HumanInterfaceDevice":["Win32_Devices"],"Win32_Devices_PortableDevices":["Win32_Devices"],"Win32_Devices_Properties":["Win32_Devices"],"Win32_Devices_Pwm":["Win32_Devices"],"Win32_Devices_Sensors":["Win32_Devices"],"Win32_Devices_SerialCommunication":["Win32_Devices"],"Win32_Devices_Tapi":["Win32_Devices"],"Win32_Devices_Usb":["Win32_Devices"],"Win32_Devices_WebServicesOnDevices":["Win32_Devices"],"Win32_Foundation":["Win32"],"Win32_Gaming":["Win32"],"Win32_Globalization":["Win32"],"Win32_Graphics":["Win32"],"Win32_Graphics_Dwm":["Win32_Graphics"],"Win32_Graphics_Gdi":["Win32_Graphics"],"Win32_Graphics_GdiPlus":["Win32_Graphics"],"Win32_Graphics_Hlsl":["Win32_Graphics"],"Win32_Graphics_OpenGL":["Win32_Graphics"],"Win32_Graphics_Printing":["Win32_Graphics"],"Win32_Graphics_Printing_PrintTicket":["Win32_Graphics_Printing"],"Win32_Management":["Win32"],"Win32_Management_MobileDeviceManagementRegistration":["Win32_Management"],"Win32_Media":["Win32"],"Win32_Media_Audio":["Win32_Media"],"Win32_Media_DxMediaObjects":["Win32_Media"],"Win32_Media_KernelStreaming":["Win32_Media"],"Win32_Media_Multimedia":["Win32_Media"],"Win32_Media_Streaming":["Win32_Media"],"Win32_Media_WindowsMediaFormat":["Win32_Media"],"Win32_NetworkManagement":["Win32"],"Win32_NetworkManagement_Dhcp":["Win32_NetworkManagement"],"Win32_NetworkManagement_Dns":["Win32_NetworkManagement"],"Win32_NetworkManagement_InternetConnectionWizard":["Win32_NetworkManagement"],"Win32_NetworkManagement_IpHelper":["Win32_NetworkManagement"],"Win32_NetworkManagement_Multicast":["Win32_NetworkManagement"],"Win32_NetworkManagement_Ndis":["Win32_NetworkManagement"],"Win32_NetworkManagement_NetBios":["Win32_NetworkManagement"],"Win32_NetworkManagement_NetManagement":["Win32_NetworkManagement"],"Win32_NetworkManagement_NetShell":["Win32_NetworkManagement"],"Win32_NetworkManagement_NetworkDiagnosticsFramework":["Win32_NetworkManagement"],"Win32_NetworkManagement_P2P":["Win32_NetworkManagement"],"Win32_NetworkManagement_QoS":["Win32_NetworkManagement"],"Win32_NetworkManagement_Rras":["Win32_NetworkManagement"],"Win32_NetworkManagement_Snmp":["Win32_NetworkManagement"],"Win32_NetworkManagement_WNet":["Win32_NetworkManagement"],"Win32_NetworkManagement_WebDav":["Win32_NetworkManagement"],"Win32_NetworkManagement_WiFi":["Win32_NetworkManagement"],"Win32_NetworkManagement_WindowsConnectionManager":["Win32_NetworkManagement"],"Win32_NetworkManagement_WindowsFilteringPlatform":["Win32_NetworkManagement"],"Win32_NetworkManagement_WindowsFirewall":["Win32_NetworkManagement"],"Win32_NetworkManagement_WindowsNetworkVirtualization":["Win32_NetworkManagement"],"Win32_Networking":["Win32"],"Win32_Networking_ActiveDirectory":["Win32_Networking"],"Win32_Networking_Clustering":["Win32_Networking"],"Win32_Networking_HttpServer":["Win32_Networking"],"Win32_Networking_Ldap":["Win32_Networking"],"Win32_Networking_WebSocket":["Win32_Networking"],"Win32_Networking_WinHttp":["Win32_Networking"],"Win32_Networking_WinInet":["Win32_Networking"],"Win32_Networking_WinSock":["Win32_Networking"],"Win32_Networking_WindowsWebServices":["Win32_Networking"],"Win32_Security":["Win32"],"Win32_Security_AppLocker":["Win32_Security"],"Win32_Security_Authentication":["Win32_Security"],"Win32_Security_Authentication_Identity":["Win32_Security_Authentication"],"Win32_Security_Authorization":["Win32_Security"],"Win32_Security_Credentials":["Win32_Security"],"Win32_Security_Cryptography":["Win32_Security"],"Win32_Security_Cryptography_Catalog":["Win32_Security_Cryptography"],"Win32_Security_Cryptography_Certificates":["Win32_Security_Cryptography"],"Win32_Security_Cryptography_Sip":["Win32_Security_Cryptography"],"Win32_Security_Cryptography_UI":["Win32_Security_Cryptography"],"Win32_Security_DiagnosticDataQuery":["Win32_Security"],"Win32_Security_DirectoryServices":["Win32_Security"],"Win32_Security_EnterpriseData":["Win32_Security"],"Win32_Security_ExtensibleAuthenticationProtocol":["Win32_Security"],"Win32_Security_Isolation":["Win32_Security"],"Win32_Security_LicenseProtection":["Win32_Security"],"Win32_Security_NetworkAccessProtection":["Win32_Security"],"Win32_Security_WinTrust":["Win32_Security"],"Win32_Security_WinWlx":["Win32_Security"],"Win32_Storage":["Win32"],"Win32_Storage_Cabinets":["Win32_Storage"],"Win32_Storage_CloudFilters":["Win32_Storage"],"Win32_Storage_Compression":["Win32_Storage"],"Win32_Storage_DistributedFileSystem":["Win32_Storage"],"Win32_Storage_FileHistory":["Win32_Storage"],"Win32_Storage_FileSystem":["Win32_Storage"],"Win32_Storage_Imapi":["Win32_Storage"],"Win32_Storage_IndexServer":["Win32_Storage"],"Win32_Storage_InstallableFileSystems":["Win32_Storage"],"Win32_Storage_IscsiDisc":["Win32_Storage"],"Win32_Storage_Jet":["Win32_Storage"],"Win32_Storage_Nvme":["Win32_Storage"],"Win32_Storage_OfflineFiles":["Win32_Storage"],"Win32_Storage_OperationRecorder":["Win32_Storage"],"Win32_Storage_Packaging":["Win32_Storage"],"Win32_Storage_Packaging_Appx":["Win32_Storage_Packaging"],"Win32_Storage_ProjectedFileSystem":["Win32_Storage"],"Win32_Storage_StructuredStorage":["Win32_Storage"],"Win32_Storage_Vhd":["Win32_Storage"],"Win32_Storage_Xps":["Win32_Storage"],"Win32_System":["Win32"],"Win32_System_AddressBook":["Win32_System"],"Win32_System_Antimalware":["Win32_System"],"Win32_System_ApplicationInstallationAndServicing":["Win32_System"],"Win32_System_ApplicationVerifier":["Win32_System"],"Win32_System_ClrHosting":["Win32_System"],"Win32_System_Com":["Win32_System"],"Win32_System_Com_Marshal":["Win32_System_Com"],"Win32_System_Com_StructuredStorage":["Win32_System_Com"],"Win32_System_Com_Urlmon":["Win32_System_Com"],"Win32_System_ComponentServices":["Win32_System"],"Win32_System_Console":["Win32_System"],"Win32_System_CorrelationVector":["Win32_System"],"Win32_System_DataExchange":["Win32_System"],"Win32_System_DeploymentServices":["Win32_System"],"Win32_System_DeveloperLicensing":["Win32_System"],"Win32_System_Diagnostics":["Win32_System"],"Win32_System_Diagnostics_Ceip":["Win32_System_Diagnostics"],"Win32_System_Diagnostics_Debug":["Win32_System_Diagnostics"],"Win32_System_Diagnostics_Debug_Extensions":["Win32_System_Diagnostics_Debug"],"Win32_System_Diagnostics_Etw":["Win32_System_Diagnostics"],"Win32_System_Diagnostics_ProcessSnapshotting":["Win32_System_Diagnostics"],"Win32_System_Diagnostics_ToolHelp":["Win32_System_Diagnostics"],"Win32_System_Diagnostics_TraceLogging":["Win32_System_Diagnostics"],"Win32_System_DistributedTransactionCoordinator":["Win32_System"],"Win32_System_Environment":["Win32_System"],"Win32_System_ErrorReporting":["Win32_System"],"Win32_System_EventCollector":["Win32_System"],"Win32_System_EventLog":["Win32_System"],"Win32_System_EventNotificationService":["Win32_System"],"Win32_System_GroupPolicy":["Win32_System"],"Win32_System_HostCompute":["Win32_System"],"Win32_System_HostComputeNetwork":["Win32_System"],"Win32_System_HostComputeSystem":["Win32_System"],"Win32_System_Hypervisor":["Win32_System"],"Win32_System_IO":["Win32_System"],"Win32_System_Iis":["Win32_System"],"Win32_System_Ioctl":["Win32_System"],"Win32_System_JobObjects":["Win32_System"],"Win32_System_Js":["Win32_System"],"Win32_System_Kernel":["Win32_System"],"Win32_System_LibraryLoader":["Win32_System"],"Win32_System_Mailslots":["Win32_System"],"Win32_System_Mapi":["Win32_System"],"Win32_System_Memory":["Win32_System"],"Win32_System_Memory_NonVolatile":["Win32_System_Memory"],"Win32_System_MessageQueuing":["Win32_System"],"Win32_System_MixedReality":["Win32_System"],"Win32_System_Ole":["Win32_System"],"Win32_System_PasswordManagement":["Win32_System"],"Win32_System_Performance":["Win32_System"],"Win32_System_Performance_HardwareCounterProfiling":["Win32_System_Performance"],"Win32_System_Pipes":["Win32_System"],"Win32_System_Power":["Win32_System"],"Win32_System_ProcessStatus":["Win32_System"],"Win32_System_Recovery":["Win32_System"],"Win32_System_Registry":["Win32_System"],"Win32_System_RemoteDesktop":["Win32_System"],"Win32_System_RemoteManagement":["Win32_System"],"Win32_System_RestartManager":["Win32_System"],"Win32_System_Restore":["Win32_System"],"Win32_System_Rpc":["Win32_System"],"Win32_System_Search":["Win32_System"],"Win32_System_Search_Common":["Win32_System_Search"],"Win32_System_SecurityCenter":["Win32_System"],"Win32_System_Services":["Win32_System"],"Win32_System_SetupAndMigration":["Win32_System"],"Win32_System_Shutdown":["Win32_System"],"Win32_System_StationsAndDesktops":["Win32_System"],"Win32_System_SubsystemForLinux":["Win32_System"],"Win32_System_SystemInformation":["Win32_System"],"Win32_System_SystemServices":["Win32_System"],"Win32_System_Threading":["Win32_System"],"Win32_System_Time":["Win32_System"],"Win32_System_TpmBaseServices":["Win32_System"],"Win32_System_UserAccessLogging":["Win32_System"],"Win32_System_Variant":["Win32_System"],"Win32_System_VirtualDosMachines":["Win32_System"],"Win32_System_WindowsProgramming":["Win32_System"],"Win32_System_Wmi":["Win32_System"],"Win32_UI":["Win32"],"Win32_UI_Accessibility":["Win32_UI"],"Win32_UI_ColorSystem":["Win32_UI"],"Win32_UI_Controls":["Win32_UI"],"Win32_UI_Controls_Dialogs":["Win32_UI_Controls"],"Win32_UI_HiDpi":["Win32_UI"],"Win32_UI_Input":["Win32_UI"],"Win32_UI_Input_Ime":["Win32_UI_Input"],"Win32_UI_Input_KeyboardAndMouse":["Win32_UI_Input"],"Win32_UI_Input_Pointer":["Win32_UI_Input"],"Win32_UI_Input_Touch":["Win32_UI_Input"],"Win32_UI_Input_XboxController":["Win32_UI_Input"],"Win32_UI_InteractionContext":["Win32_UI"],"Win32_UI_Magnification":["Win32_UI"],"Win32_UI_Shell":["Win32_UI"],"Win32_UI_Shell_Common":["Win32_UI_Shell"],"Win32_UI_Shell_PropertiesSystem":["Win32_UI_Shell"],"Win32_UI_TabletPC":["Win32_UI"],"Win32_UI_TextServices":["Win32_UI"],"Win32_UI_WindowsAndMessaging":["Win32_UI"],"Win32_Web":["Win32"],"Win32_Web_InternetExplorer":["Win32_Web"],"default":[],"docs":[]},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows-sys-0.59.0/Cargo.toml","metadata":{"docs":{"rs":{"all-features":true,"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":["os::windows-apis"],"keywords":[],"readme":"readme.md","repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.60"},{"name":"windows-targets","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows-targets@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import libs for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[{"name":"windows_aarch64_gnullvm","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"aarch64-pc-windows-gnullvm","registry":null},{"name":"windows_x86_64_msvc","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))","registry":null},{"name":"windows_aarch64_msvc","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))","registry":null},{"name":"windows_i686_gnu","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))","registry":null},{"name":"windows_i686_msvc","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))","registry":null},{"name":"windows_x86_64_gnu","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))","registry":null},{"name":"windows_i686_gnullvm","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"i686-pc-windows-gnullvm","registry":null},{"name":"windows_x86_64_gnullvm","source":"registry+https://github.com/rust-lang/crates.io-index","req":"^0.52.6","kind":null,"rename":null,"optional":false,"uses_default_features":true,"features":[],"target":"x86_64-pc-windows-gnullvm","registry":null}],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_targets","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows-targets-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows-targets-0.52.6/Cargo.toml","metadata":null,"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":"readme.md","repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_aarch64_gnullvm","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_gnullvm@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_aarch64_gnullvm","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_aarch64_gnullvm-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_aarch64_gnullvm-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_aarch64_gnullvm-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_aarch64_msvc","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_msvc@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_aarch64_msvc","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_aarch64_msvc-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_aarch64_msvc-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_aarch64_msvc-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_i686_gnu","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnu@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_i686_gnu","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_gnu-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_gnu-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_gnu-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_i686_gnullvm","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnullvm@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_i686_gnullvm","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_gnullvm-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_gnullvm-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_gnullvm-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_i686_msvc","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_msvc@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_i686_msvc","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_msvc-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_msvc-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_i686_msvc-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_x86_64_gnu","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnu@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_x86_64_gnu","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_gnu-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_gnu-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_gnu-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_x86_64_gnullvm","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnullvm@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_x86_64_gnullvm","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_gnullvm-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_gnullvm-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_gnullvm-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"},{"name":"windows_x86_64_msvc","version":"0.52.6","id":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_msvc@0.52.6","license":"MIT OR Apache-2.0","license_file":null,"description":"Import lib for Windows","source":"registry+https://github.com/rust-lang/crates.io-index","dependencies":[],"targets":[{"kind":["lib"],"crate_types":["lib"],"name":"windows_x86_64_msvc","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_msvc-0.52.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_msvc-0.52.6/build.rs","edition":"2021","doc":false,"doctest":false,"test":false}],"features":{},"manifest_path":"/usr/local/google/home/lukasza/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_msvc-0.52.6/Cargo.toml","metadata":{"docs":{"rs":{"default-target":"x86_64-pc-windows-msvc","targets":[]}}},"publish":null,"authors":["Microsoft"],"categories":[],"keywords":[],"readme":null,"repository":"https://github.com/microsoft/windows-rs","homepage":null,"documentation":null,"edition":"2021","links":null,"default_run":null,"rust_version":"1.56"}],"workspace_members":["path+file:///usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3#0.1.0"],"workspace_default_members":["path+file:///usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3#0.1.0"],"resolve":{"nodes":[{"id":"path+file:///usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3#0.1.0","dependencies":["registry+https://github.com/rust-lang/crates.io-index#termcolor@1.4.1"],"deps":[{"name":"termcolor","pkg":"registry+https://github.com/rust-lang/crates.io-index#termcolor@1.4.1","dep_kinds":[{"kind":null,"target":null}]}],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#termcolor@1.4.1","dependencies":["registry+https://github.com/rust-lang/crates.io-index#winapi-util@0.1.9"],"deps":[{"name":"winapi_util","pkg":"registry+https://github.com/rust-lang/crates.io-index#winapi-util@0.1.9","dep_kinds":[{"kind":null,"target":"cfg(windows)"}]}],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#winapi-util@0.1.9","dependencies":["registry+https://github.com/rust-lang/crates.io-index#windows-sys@0.59.0"],"deps":[{"name":"windows_sys","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows-sys@0.59.0","dep_kinds":[{"kind":null,"target":"cfg(windows)"}]}],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows-sys@0.59.0","dependencies":["registry+https://github.com/rust-lang/crates.io-index#windows-targets@0.52.6"],"deps":[{"name":"windows_targets","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows-targets@0.52.6","dep_kinds":[{"kind":null,"target":null}]}],"features":["Win32","Win32_Foundation","Win32_Storage","Win32_Storage_FileSystem","Win32_System","Win32_System_Console","Win32_System_SystemInformation","default"]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows-targets@0.52.6","dependencies":["registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_gnullvm@0.52.6","registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_msvc@0.52.6","registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnu@0.52.6","registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnullvm@0.52.6","registry+https://github.com/rust-lang/crates.io-index#windows_i686_msvc@0.52.6","registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnu@0.52.6","registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnullvm@0.52.6","registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_msvc@0.52.6"],"deps":[{"name":"windows_aarch64_gnullvm","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_gnullvm@0.52.6","dep_kinds":[{"kind":null,"target":"aarch64-pc-windows-gnullvm"}]},{"name":"windows_aarch64_msvc","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_msvc@0.52.6","dep_kinds":[{"kind":null,"target":"cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))"}]},{"name":"windows_i686_gnu","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnu@0.52.6","dep_kinds":[{"kind":null,"target":"cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))"}]},{"name":"windows_i686_gnullvm","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnullvm@0.52.6","dep_kinds":[{"kind":null,"target":"i686-pc-windows-gnullvm"}]},{"name":"windows_i686_msvc","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_msvc@0.52.6","dep_kinds":[{"kind":null,"target":"cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))"}]},{"name":"windows_x86_64_gnu","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnu@0.52.6","dep_kinds":[{"kind":null,"target":"cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))"}]},{"name":"windows_x86_64_gnullvm","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnullvm@0.52.6","dep_kinds":[{"kind":null,"target":"x86_64-pc-windows-gnullvm"}]},{"name":"windows_x86_64_msvc","pkg":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_msvc@0.52.6","dep_kinds":[{"kind":null,"target":"cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))"}]}],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_gnullvm@0.52.6","dependencies":[],"deps":[],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_aarch64_msvc@0.52.6","dependencies":[],"deps":[],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnu@0.52.6","dependencies":[],"deps":[],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_gnullvm@0.52.6","dependencies":[],"deps":[],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_i686_msvc@0.52.6","dependencies":[],"deps":[],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnu@0.52.6","dependencies":[],"deps":[],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_gnullvm@0.52.6","dependencies":[],"deps":[],"features":[]},{"id":"registry+https://github.com/rust-lang/crates.io-index#windows_x86_64_msvc@0.52.6","dependencies":[],"deps":[],"features":[]}],"root":"path+file:///usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3#0.1.0"},"target_directory":"/usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3/target","version":1,"workspace_root":"/usr/local/google/home/lukasza/src/chromium2/src/tools/crates/gnrt/sample_package3","metadata":null}
diff --git a/tools/crates/gnrt/sample_package3/Cargo.lock b/tools/crates/gnrt/sample_package3/Cargo.lock
new file mode 100644
index 0000000..1363070
--- /dev/null
+++ b/tools/crates/gnrt/sample_package3/Cargo.lock
@@ -0,0 +1,101 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "sample_package3"
+version = "0.1.0"
+dependencies = [
+ "termcolor",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/tools/crates/gnrt/sample_package3/Cargo.toml b/tools/crates/gnrt/sample_package3/Cargo.toml
new file mode 100644
index 0000000..873bae8
--- /dev/null
+++ b/tools/crates/gnrt/sample_package3/Cargo.toml
@@ -0,0 +1,21 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This `Cargo.toml` is a test input for Windows gnu-vs-msvc dependencies.
+# Chromium only supports `msvc` `target_env` and so only the last of
+# the crates below should be in the set of transitive dependencies:
+#
+# * `windows_x86_64_gnu`
+# * `windows_x86_64_gnullvm`
+# * `windows_x86_64_msvc`
+#
+# Output from `cargo metadata` has been saved in `gnrt/lib/test_metadata3.json`.
+
+[package]
+name = "sample_package3"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+termcolor = "1.4.1"
diff --git a/tools/crates/gnrt/sample_package3/README.md b/tools/crates/gnrt/sample_package3/README.md
new file mode 100644
index 0000000..8ac9d87
--- /dev/null
+++ b/tools/crates/gnrt/sample_package3/README.md
@@ -0,0 +1,5 @@
+This is a sample Cargo package to test `gnrt`'s dependency resolution. The
+output of `cargo metadata` is recorded and used as test data.
+
+`tools/crates/gnrt/lib/test_metadata3.json` is generated by the output of
+running `cargo metadata --format-version 1` in this directory.
diff --git a/tools/crates/gnrt/sample_package3/src/main.rs b/tools/crates/gnrt/sample_package3/src/main.rs
new file mode 100644
index 0000000..46a864e
--- /dev/null
+++ b/tools/crates/gnrt/sample_package3/src/main.rs
@@ -0,0 +1,7 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/tools/cygprofile/generate_orderfile.pydeps b/tools/cygprofile/generate_orderfile.pydeps
index 7555de0..08b16e8 100644
--- a/tools/cygprofile/generate_orderfile.pydeps
+++ b/tools/cygprofile/generate_orderfile.pydeps
@@ -54,7 +54,6 @@
 //third_party/catapult/devil/devil/devil_env.py
 //third_party/catapult/devil/devil/utils/__init__.py
 //third_party/catapult/devil/devil/utils/cmd_helper.py
-//third_party/catapult/devil/devil/utils/host_utils.py
 //third_party/catapult/devil/devil/utils/lazy/__init__.py
 //third_party/catapult/devil/devil/utils/lazy/weak_constant.py
 //third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/tools/grit/grit/testdata/substitute_android.grd b/tools/grit/grit/testdata/substitute_android.grd
new file mode 100644
index 0000000..e26939a
--- /dev/null
+++ b/tools/grit/grit/testdata/substitute_android.grd
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
+<grit
+    base_dir="."
+    source_lang_id="en"
+    tc_project="GoogleDesktopWindowsClient"
+    latest_public_release="0"
+    current_release="1"
+    enc_check="möl">
+  <outputs>
+    <output filename="resource.h" type="rc_header" />
+    <output filename="en_generated_resources.rc" type="rc_all" lang="en" />
+    <output filename="sv_generated_resources.rc" type="rc_all" lang="sv" />
+    <output filename="java/res/values-af/components_strings.xml" lang="af" type="android" context="android_java" />
+    <output filename="java/res/values-am/components_strings.xml" lang="am" type="android" context="android_java" />
+    <output filename="values-ar/components_strings.xml" lang="ar" type="android" context="android_java" />
+  </outputs>
+  <translations>
+    <file path="substitute.xmb" lang="sv" />
+  </translations>
+  <release seq="1">
+    <messages first_id="8192">
+      <message name="IDS_COPYRIGHT_GOOGLE_LONG" sub_variable="true" desc="Gadget copyright notice.  Needs to be updated every year.">
+        Copyright 2008 Google Inc. All Rights Reserved.
+      </message>
+      <message name="IDS_NEWS_PANEL_COPYRIGHT">
+        Google Desktop News gadget
+[IDS_COPYRIGHT_GOOGLE_LONG]
+View news that is personalized based on the articles you read.
+
+For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles.
+      </message>
+    </messages>
+  </release>
+</grit>
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py
index 987ec3c..d59dd472 100644
--- a/tools/grit/grit/tool/build.py
+++ b/tools/grit/grit/tool/build.py
@@ -12,12 +12,15 @@
 import getopt
 import gzip
 import os
+import pathlib
+import re
 import shutil
 import sys
 
 from grit import grd_reader
 from grit import shortcuts
 from grit import util
+from grit import zip_helpers
 from grit.format import minifier
 from grit.node import brotli_util
 from grit.node import include
@@ -26,6 +29,9 @@
 from grit.tool import interface
 
 
+JAVA_STRINGS_PATH_RE = re.compile(r'^.*/(values.*)$')
+
+
 # It would be cleaner to have each module register itself, but that would
 # require importing all of them on every run of GRIT.
 '''Map from <output> node types to modules under grit.format.'''
@@ -146,6 +152,12 @@
                     language, for 'OTHER', 'FEMININE', 'MASCULINE', and 'NEUTER'
                     genders.
 
+  --android-output-zip
+                    Output a single zip file containing all the android
+                    strings.xml files instead of outputting each xml
+                    individually. This is a convenient way to skip some work in
+                    GN.
+
 Conditional inclusion of resources only affects the output of files which
 control which resources get linked into a binary, e.g. it affects .rc files
 meant for compilation but it does not affect resource header files (that define
@@ -178,8 +190,8 @@
         ('depdir=', 'depfile=', 'assert-file-list=', 'help',
          'output-all-resource-defines', 'no-output-all-resource-defines',
          'no-replace-ellipsis', 'depend-on-stamp', 'css-minifier=',
-         'write-only-new=', 'allowlist-support', 'brotli=',
-         'translate-genders'))
+         'write-only-new=', 'allowlist-support', 'brotli=', 'translate-genders',
+         'android-output-zip='))
     for (key, val) in own_opts:
       if key == '-a':
         assert_output_files.append(val)
@@ -223,6 +235,8 @@
         brotli_util.SetBrotliCommand([os.path.abspath(val)])
       elif key == '--translate-genders':
         translate_genders = True
+      elif key == '--android-output-zip':
+        self.android_output_zip_path = val
       elif key == '--help':
         self.ShowUsage()
         sys.exit(0)
@@ -299,6 +313,10 @@
     # Whether to compare outputs to their old contents before writing.
     self.write_only_new = False
 
+    # If not None, this will cause Android xml resources to be zipped in the
+    # specified file.
+    self.android_output_zip_path = None
+
   @staticmethod
   def AddAllowlistTags(start_node, allowlist_names):
     # Walk the tree of nodes added attributes for the nodes that shouldn't
@@ -376,6 +394,7 @@
     if self.allowlist_names:
       self.AddAllowlistTags(self.res, self.allowlist_names)
 
+    zippable_android_xml_outputs = []
     for output in self.res.GetOutputFiles():
       self.VerboseOut('Creating %s...' % output.GetOutputFilename())
 
@@ -416,6 +435,9 @@
         os.remove(tmp_filename)
         tmp_filename = gz_filename
 
+      if output_type == 'android':
+        zippable_android_xml_outputs.append(out_filename)
+
       # Now copy from the temp file back to the real output, but on Windows,
       # only if the real output doesn't exist or the contents of the file
       # changed.  This prevents identical headers from being written and .cc
@@ -438,6 +460,14 @@
 
       self.VerboseOut(' done.\n')
 
+    # Move all the Android xml files into a single zip file. This simplifies gn
+    # logic, since the next step in the build process would be to zip the files
+    # anyway.
+    #
+    # Asserts that each path contains '/values'.
+    if self.android_output_zip_path is not None:
+      self.ZipAndroidOutputs(zippable_android_xml_outputs)
+
     # Print warnings if there are any duplicate shortcuts.
     warnings = shortcuts.GenerateDuplicateShortcutsWarnings(
         self.res.UberClique(), self.res.GetTcProject())
@@ -457,6 +487,54 @@
       sys.exit(-1)
 
 
+  # zip_helpers.add_files_to_zip takes in a list of tuples (zip_filename,
+  # fs_filename). We are given a list of fs_filenames, and must construct
+  # zip_filenames. We do so by converting the path to posix-style (ie, replacing
+  # \ with /), then trimming everything up to but not including '/values'.
+  #
+  # Returns [(zip_filename, fs_filename)], or raises an AssertionError.
+  def MakeAndroidZipOutputPaths(self, xml_outputs):
+    ret = []
+    for fs_filename in xml_outputs:
+      zip_filename = str(pathlib.Path(fs_filename).as_posix())
+      match = JAVA_STRINGS_PATH_RE.match(zip_filename)
+      assert match is not None, ('fs_filename does not contain "/values": '
+                                 f'"{fs_filename}"')
+      zip_filename = match.group(1)
+      ret.append((zip_filename, fs_filename))
+
+    return ret
+
+  # Takes the files in |xml_outputs|, zips them into
+  # |self.android_output_zip_path|, and then deletes the originals. Assumes
+  # |self.android_output_zip_path| is not None.
+  #
+  # Raises an AssertionError if any of the paths does not contain '/values'.
+  def ZipAndroidOutputs(self, xml_outputs):
+    xml_outputs = self.MakeAndroidZipOutputPaths(xml_outputs)
+    zip_helpers.add_files_to_zip(xml_outputs, self.android_output_zip_path)
+
+    for zipped_file in xml_outputs:
+      os.remove(zipped_file[1])
+
+  # If |self.android_output_zip_path| isn't specified, this simply returns the
+  # full output paths from each output node. If |self.android_output_zip_path|
+  # is specified, then Android output nodes are suppressed in favour of
+  # including a single zip file instead.
+  def GetFinalOutputFileList(self):
+    files = [
+        os.path.abspath(
+            os.path.join(self.output_directory, i.GetOutputFilename()))
+        for i in self.res.GetOutputFiles()
+        if i.GetType() != 'android' or self.android_output_zip_path is None
+    ]
+
+    if self.android_output_zip_path is not None:
+      files.append(os.path.abspath(self.android_output_zip_path))
+
+    return sorted(files)
+
+
   def CheckAssertedOutputFiles(self, assert_output_files):
     '''Checks that the asserted output files are specified in the given list.
 
@@ -465,10 +543,7 @@
     '''
     # Compare the absolute path names, sorted.
     asserted = sorted([os.path.abspath(i) for i in assert_output_files])
-    actual = sorted([
-        os.path.abspath(os.path.join(self.output_directory,
-                                     i.GetOutputFilename()))
-        for i in self.res.GetOutputFiles()])
+    actual = self.GetFinalOutputFileList()
 
     if asserted != actual:
       missing = list(set(asserted) - set(actual))
diff --git a/tools/grit/grit/tool/build_unittest.py b/tools/grit/grit/tool/build_unittest.py
index 8610bbe6..931f7d7 100755
--- a/tools/grit/grit/tool/build_unittest.py
+++ b/tools/grit/grit/tool/build_unittest.py
@@ -9,7 +9,9 @@
 
 import codecs
 import os
+import re
 import sys
+import zipfile
 if __name__ == '__main__':
   sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
 
@@ -19,6 +21,9 @@
 from grit.tool import build
 
 
+ZIP_ENTRY_PATH_TRIMMED_RE = re.compile(r'^values-\w{2}/components_strings.xml$')
+
+
 class BuildUnittest(unittest.TestCase):
 
   # IDs should not change based on allowlisting.
@@ -170,6 +175,180 @@
             '-a', os.path.abspath(output_dir.GetPath('resource.h'))]))
     output_dir.CleanUp()
 
+  def testAssertZippedAndroidOutputs(self):
+    output_dir = util.TempDir({})
+
+    class DummyOpts:
+
+      def __init__(self):
+        self.input = util.PathFromRoot('grit/testdata/substitute_android.grd')
+        self.verbose = False
+        self.extra_verbose = False
+
+    # Incomplete output file list (without zipping XMLs) should fail.
+    builder_fail = build.RcBuilder()
+    self.assertEqual(
+        2,
+        builder_fail.Run(DummyOpts(), [
+            '-o',
+            output_dir.GetPath(),
+            '-a',
+            os.path.abspath(output_dir.GetPath('en_generated_resources.rc')),
+        ]))
+
+    # Complete output file list  (without zipping XMLs) should succeed.
+    builder_ok = build.RcBuilder()
+    self.assertEqual(
+        0,
+        builder_ok.Run(DummyOpts(), [
+            '-o',
+            output_dir.GetPath(),
+            '-a',
+            os.path.abspath(output_dir.GetPath('en_generated_resources.rc')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('sv_generated_resources.rc')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('resource.h')),
+            '-a',
+            os.path.abspath(
+                output_dir.GetPath(
+                    'java/res/values-af/components_strings.xml')),
+            '-a',
+            os.path.abspath(
+                output_dir.GetPath(
+                    'java/res/values-am/components_strings.xml')),
+            '-a',
+            os.path.abspath(
+                output_dir.GetPath('values-ar/components_strings.xml')),
+        ]))
+
+    # Incomplete output file list (while zipping XMLs) should fail.
+    builder_fail = build.RcBuilder()
+    self.assertEqual(
+        2,
+        builder_fail.Run(DummyOpts(), [
+            '-o',
+            output_dir.GetPath(),
+            '-a',
+            os.path.abspath(output_dir.GetPath('en_generated_resources.rc')),
+            '--android-output-zip',
+            os.path.abspath(output_dir.GetPath('android_resources.zip')),
+        ]))
+
+    # Complete output file list (while zipping XMLs) should succeed.
+    builder_ok = build.RcBuilder()
+    self.assertEqual(
+        0,
+        builder_ok.Run(DummyOpts(), [
+            '-o',
+            output_dir.GetPath(),
+            '-a',
+            os.path.abspath(output_dir.GetPath('en_generated_resources.rc')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('sv_generated_resources.rc')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('resource.h')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('android_resources.zip')),
+            '--android-output-zip',
+            os.path.abspath(output_dir.GetPath('android_resources.zip')),
+        ]))
+
+    # Complete output file list (while zipping XMLs) should succeed, even when
+    # --android-output-zip is a relative path.
+    builder_ok = build.RcBuilder()
+    self.assertEqual(
+        0,
+        builder_ok.Run(DummyOpts(), [
+            '-o',
+            output_dir.GetPath(),
+            '-a',
+            os.path.abspath(output_dir.GetPath('en_generated_resources.rc')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('sv_generated_resources.rc')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('resource.h')),
+            '-a',
+            os.path.abspath(output_dir.GetPath('android_resources.zip')),
+            '--android-output-zip',
+            os.path.relpath(output_dir.GetPath('android_resources.zip')),
+        ]))
+
+    output_dir.CleanUp()
+
+  def testZippedAndroidOutputs(self):
+
+    class DummyOpts:
+
+      def __init__(self):
+        self.input = util.PathFromRoot('grit/testdata/substitute_android.grd')
+        self.verbose = False
+        self.extra_verbose = False
+
+    # Don't supply a '--android-output-zip' path: each of the 3 xml outputs gets
+    # its own file.
+    output_dir = util.TempDir({})
+
+    builder_ok = build.RcBuilder()
+    builder_ok.Run(DummyOpts(), [
+        '-o',
+        output_dir.GetPath(),
+    ])
+
+    self.assertTrue(
+        os.path.exists(
+            os.path.abspath(
+                output_dir.GetPath(
+                    'java/res/values-af/components_strings.xml'))))
+    self.assertTrue(
+        os.path.exists(
+            os.path.abspath(
+                output_dir.GetPath(
+                    'java/res/values-am/components_strings.xml'))))
+    self.assertTrue(
+        os.path.exists(
+            os.path.abspath(
+                output_dir.GetPath('values-ar/components_strings.xml'))))
+
+    output_dir.CleanUp()
+
+    def getZipPath():
+      return os.path.abspath(output_dir.GetPath('android_resources.zip'))
+
+    # Supply a '--android-output-zip' xml files don't exist, but zip file does.
+    # Zip file has trimmed paths.
+    output_dir = util.TempDir({})
+    zip_path = getZipPath()
+
+    builder_ok = build.RcBuilder()
+    builder_ok.Run(
+        DummyOpts(),
+        ['-o', output_dir.GetPath(), '--android-output-zip', zip_path])
+
+    self.assertTrue(os.path.exists(zip_path))
+    self.assertFalse(
+        os.path.exists(
+            os.path.abspath(
+                output_dir.GetPath(
+                    'java/res/values-af/components_strings.xml'))))
+    self.assertFalse(
+        os.path.exists(
+            os.path.abspath(
+                output_dir.GetPath(
+                    'java/res/values-am/components_strings.xml'))))
+    self.assertFalse(
+        os.path.exists(
+            os.path.abspath(
+                output_dir.GetPath('values-ar/components_strings.xml'))))
+
+    with zipfile.ZipFile(zip_path, 'r') as zip_file:
+      for info in zip_file.infolist():
+        self.assertIsNotNone(ZIP_ENTRY_PATH_TRIMMED_RE.match(info.filename))
+        self.assertEqual(info.date_time, (2001, 1, 1, 0, 0, 0))
+        self.assertGreater(info.file_size, 0)
+
+    output_dir.CleanUp()
+
   def _verifyAllowlistedOutput(self,
                                filename,
                                allowlisted_ids,
diff --git a/tools/grit/grit/zip_helpers.py b/tools/grit/grit/zip_helpers.py
new file mode 100644
index 0000000..6a73b9f
--- /dev/null
+++ b/tools/grit/grit/zip_helpers.py
@@ -0,0 +1,137 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Helper functions for dealing with .zip files.
+
+Copied from
+https://source.chromium.org/chromium/chromium/src/+/main:build/zip_helpers.py;drc=86180695506584e8226a4ed14259e6f0eceabe4e
+"""
+
+import os
+import pathlib
+import posixpath
+import stat
+import time
+import zipfile
+
+
+def _hermetic_date_time(timestamp=None):
+  if not timestamp:
+    return (2001, 1, 1, 0, 0, 0)
+  utc_time = time.gmtime(timestamp)
+  return (utc_time.tm_year, utc_time.tm_mon, utc_time.tm_mday, utc_time.tm_hour,
+          utc_time.tm_min, utc_time.tm_sec)
+
+
+def add_to_zip_hermetic(zip_file,
+                        zip_path,
+                        *,
+                        src_path=None,
+                        data=None,
+                        compress=None,
+                        timestamp=None):
+  """Adds a file to the given ZipFile with a hard-coded modified time.
+
+  Args:
+    zip_file: ZipFile instance to add the file to.
+    zip_path: Destination path within the zip file (or ZipInfo instance).
+    src_path: Path of the source file. Mutually exclusive with |data|.
+    data: File data as a string.
+    compress: Whether to enable compression. Default is taken from ZipFile
+        constructor.
+    timestamp: The last modification date and time for the archive member.
+  """
+  assert (src_path is None) != (data is None), (
+      '|src_path| and |data| are mutually exclusive.')
+  if isinstance(zip_path, zipfile.ZipInfo):
+    zipinfo = zip_path
+    zip_path = zipinfo.filename
+  else:
+    zipinfo = zipfile.ZipInfo(filename=zip_path)
+    zipinfo.external_attr = 0o644 << 16
+
+  zipinfo.date_time = _hermetic_date_time(timestamp)
+
+  # Filenames can contain backslashes, but it is more likely that we've
+  # forgotten to use forward slashes as a directory separator.
+  assert '\\' not in zip_path, 'zip_path should not contain \\: ' + zip_path
+  assert not posixpath.isabs(zip_path), 'Absolute zip path: ' + zip_path
+  assert not zip_path.startswith('..'), 'Should not start with ..: ' + zip_path
+  assert posixpath.normpath(zip_path) == zip_path, (
+      f'Non-canonical zip_path: {zip_path} vs: {posixpath.normpath(zip_path)}')
+  assert zip_path not in zip_file.namelist(), (
+      'Tried to add a duplicate zip entry: ' + zip_path)
+
+  if src_path:
+    with open(src_path, 'rb') as f:
+      data = f.read()
+
+  # zipfile will deflate even when it makes the file bigger. To avoid
+  # growing files, disable compression at an arbitrary cut off point.
+  if len(data) < 16:
+    compress = False
+
+  # None converts to ZIP_STORED, when passed explicitly rather than the
+  # default passed to the ZipFile constructor.
+  compress_type = zip_file.compression
+  if compress is not None:
+    compress_type = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED
+  zip_file.writestr(zipinfo, data, compress_type)
+
+
+def add_files_to_zip(inputs,
+                     output,
+                     *,
+                     base_dir=None,
+                     path_transform=None,
+                     compress=None,
+                     zip_prefix_path=None,
+                     timestamp=None):
+  """Creates a zip file from a list of files.
+
+  Args:
+    inputs: A list of paths to zip, or a list of (zip_path, fs_path) tuples.
+    output: Path, fileobj, or ZipFile instance to add files to.
+    base_dir: Prefix to strip from inputs.
+    path_transform: Called for each entry path. Returns a new zip path, or None
+        to skip the file.
+    compress: Whether to compress
+    zip_prefix_path: Path prepended to file path in zip file.
+    timestamp: Unix timestamp to use for files in the archive.
+  """
+  if base_dir is None:
+    base_dir = '.'
+  input_tuples = []
+  for tup in inputs:
+    if isinstance(tup, str):
+      src_path = tup
+      zip_path = os.path.relpath(src_path, base_dir)
+      # Zip files always use / as path separator.
+      if os.path.sep != posixpath.sep:
+        zip_path = str(pathlib.Path(zip_path).as_posix())
+      tup = (zip_path, src_path)
+    input_tuples.append(tup)
+
+  # Sort by zip path to ensure stable zip ordering.
+  input_tuples.sort(key=lambda tup: tup[0])
+
+  out_zip = output
+  if not isinstance(output, zipfile.ZipFile):
+    out_zip = zipfile.ZipFile(output, 'w')
+
+  try:
+    for zip_path, fs_path in input_tuples:
+      if zip_prefix_path:
+        zip_path = posixpath.join(zip_prefix_path, zip_path)
+      if path_transform:
+        zip_path = path_transform(zip_path)
+        if zip_path is None:
+          continue
+      add_to_zip_hermetic(out_zip,
+                          zip_path,
+                          src_path=fs_path,
+                          compress=compress,
+                          timestamp=timestamp)
+  finally:
+    if output is not out_zip:
+      out_zip.close()
diff --git a/tools/grit/grit_info.py b/tools/grit/grit_info.py
index 3e313ac..f2a60f26 100755
--- a/tools/grit/grit_info.py
+++ b/tools/grit/grit_info.py
@@ -23,7 +23,8 @@
             defines,
             ids_file,
             target_platform=None,
-            translate_genders=False):
+            translate_genders=False,
+            android_output_zip_path=None):
   grd = grd_reader.Parse(filename,
                          defines=defines,
                          tags_to_ignore={'messages'},
@@ -31,17 +32,13 @@
                          target_platform=target_platform,
                          translate_genders=translate_genders)
 
-  target = []
-  lang_folders = {}
-  # Add all explicitly-specified output files
-  for output in grd.GetOutputFiles():
-    path = output.GetFilename()
-    target.append(path)
+  target = [
+      i.GetFilename() for i in grd.GetOutputFiles()
+      if i.GetType() != 'android' or android_output_zip_path is None
+  ]
 
-    if path.endswith('.h'):
-      path, filename = os.path.split(path)
-    if output.attrs['lang']:
-      lang_folders[output.attrs['lang']] = os.path.dirname(path)
+  if android_output_zip_path is not None:
+    target.append(android_output_zip_path)
 
   return [t.replace('\\', '/') for t in target]
 
@@ -121,6 +118,9 @@
   parser.add_option("--translate-genders",
                     action="store_true",
                     dest="translate_genders")
+  parser.add_option("--android-output-zip-path",
+                    dest="android_output_zip_path",
+                    default=None)
 
   options, args = parser.parse_args(argv)
 
@@ -161,9 +161,9 @@
 
     prefix, filename = args
     outputs = [
-        posixpath.join(prefix, f)
-        for f in Outputs(filename, defines, options.ids_file,
-                         options.target_platform, options.translate_genders)
+        posixpath.join(prefix, f) for f in Outputs(
+            filename, defines, options.ids_file, options.target_platform,
+            options.translate_genders, options.android_output_zip_path)
     ]
     return '\n'.join(outputs)
   else:
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index e9d1729..d0b916b 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -1508,6 +1508,10 @@
   "<(SHARED_INTERMEDIATE_DIR)/third_party/blink/public/strings/permission_element_generated_strings.grd": {
     "META": {"sizes": {"messages": [2000],}},
     "messages": [10080],
+  },
+
+  "third_party/search_engines_data/resources/search_engines_scaled_resources.grd": {
+    "structures": [10100],
   }
 
   # END "everything else" section.
diff --git a/tools/gritsettings/translation_expectations.pyl b/tools/gritsettings/translation_expectations.pyl
index 28cc6a22..954dc85 100644
--- a/tools/gritsettings/translation_expectations.pyl
+++ b/tools/gritsettings/translation_expectations.pyl
@@ -134,6 +134,7 @@
     "tools/grit/grit/testdata/buildinfo.grd": "Test data",
     "tools/grit/grit/testdata/chrome/app/generated_resources.grd": "Test data",
     "tools/grit/grit/testdata/substitute.grd": "Test data",
+    "tools/grit/grit/testdata/substitute_android.grd": "Test data",
     "tools/grit/grit/testdata/substitute_no_ids.grd": "Test data",
     "tools/grit/grit/testdata/substitute_tmpl.grd": "Test data",
     "tools/translation/testdata/not_translated.grd": "Test data",
diff --git a/tools/json_schema_compiler/test/web_idl/defaults.idl b/tools/json_schema_compiler/test/web_idl/defaults.idl
new file mode 100644
index 0000000..ed06ab80
--- /dev/null
+++ b/tools/json_schema_compiler/test/web_idl/defaults.idl
@@ -0,0 +1,10 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+interface DefaultsOnlyWebIdl {
+};
+
+partial interface Browser {
+  static attribute DefaultsOnlyWebIdl defaultsOnlyWebIdl;
+};
diff --git a/tools/json_schema_compiler/web_idl_schema.py b/tools/json_schema_compiler/web_idl_schema.py
index 10bca0c..13fcad5b 100755
--- a/tools/json_schema_compiler/web_idl_schema.py
+++ b/tools/json_schema_compiler/web_idl_schema.py
@@ -642,9 +642,13 @@
     functions = []
     types = []
     events = []
+    properties = OrderedDict()
+    manifest_keys = None
     description = ProcessNodeDescription(self.namespace).description
     nodoc = False
     platforms = None
+    compiler_options = OrderedDict()
+    deprecated = None
 
     # Functions are defined as Operations on the API Interface definition.
     for node in self.namespace.GetListOf('Operation'):
@@ -676,9 +680,13 @@
         'functions': functions,
         'types': types,
         'events': events,
+        'properties': properties,
+        'manifest_keys': manifest_keys,
         'nodoc': nodoc,
         'description': description,
-        'platforms': platforms
+        'platforms': platforms,
+        'compiler_options': compiler_options,
+        'deprecated': deprecated,
     }
 
 
diff --git a/tools/json_schema_compiler/web_idl_schema_test.py b/tools/json_schema_compiler/web_idl_schema_test.py
index c1af87a..50de0a9 100755
--- a/tools/json_schema_compiler/web_idl_schema_test.py
+++ b/tools/json_schema_compiler/web_idl_schema_test.py
@@ -588,12 +588,24 @@
     expected = ['chromeos']
     self.assertEqual(expected, platforms_schema[0]['platforms'])
 
-  # Tests that the platforms attribute is None if not specified on in the
-  # extended attributes of a namespace.
-  def testNonSpecifiedPlatformsOnNamespace(self):
-    basic_schema = self.idl_basics
-    expected = None
-    self.assertEqual(expected, basic_schema['platforms'])
+  # Tests a variety of default values that are set on an API namespace when they
+  # are not specified in the source IDL file.
+  def testNonSpecifiedDefaultValues(self):
+    defaults_schema = web_idl_schema.Load('test/web_idl/defaults.idl')[0]
+    self.assertEqual(
+        {
+            'compiler_options': {},
+            'deprecated': None,
+            'description': '',
+            'events': [],
+            'functions': [],
+            'manifest_keys': None,
+            'namespace': 'defaultsOnlyWebIdl',
+            'nodoc': False,
+            'platforms': None,
+            'properties': {},
+            'types': [],
+        }, defaults_schema)
 
 
 if __name__ == '__main__':
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d6f80de2..f805f67 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2837,6 +2837,8 @@
   <int value="3" label="Both read and wrote cookies"/>
 </enum>
 
+<!-- LINT.IfChange(CookieControlsMode) -->
+
 <enum name="CookieControlsMode">
   <int value="0" label="Off"/>
   <int value="1" label="BlockThirdParty"/>
@@ -2844,6 +2846,8 @@
   <int value="3" label="Limited"/>
 </enum>
 
+<!-- LINT.ThenChange(/components/content_settings/core/browser/cookie_settings.h:CookieControlsMode, /chrome/browser/resources/settings/site_settings/constants.ts:CookieControlsMode) -->
+
 <enum name="CookieDeprecationFacilitatedTestingProfileEligibility">
   <int value="0" label="Eligible"/>
   <int value="1" label="Ineligible: 3P Cookies blocked"/>
@@ -9558,6 +9562,7 @@
   <int value="-1842511843" label="DiceWebSigninInterception:enabled"/>
   <int value="-1842145650" label="WaylandLinuxDrmSyncobj:enabled"/>
   <int value="-1841624903" label="FilesMaterializedViews:disabled"/>
+  <int value="-1841054968" label="HdrAgtm:disabled"/>
   <int value="-1840821581" label="WebViewPowerSchedulerThrottleIdle:disabled"/>
   <int value="-1840772138" label="WebKioskEnableLacros:disabled"/>
   <int value="-1840608422" label="AdvancedPpdAttributes:disabled"/>
@@ -13926,6 +13931,7 @@
       label="AutofillEnableUnmaskCardRequestSetInstrumentId:enabled"/>
   <int value="-172544594" label="LacrosNonSyncingProfiles:enabled"/>
   <int value="-172480221" label="UseDMSAAForTiles:enabled"/>
+  <int value="-171798137" label="HdrAgtm:enabled"/>
   <int value="-171232290" label="ListAllDisplayModes:disabled"/>
   <int value="-171173736" label="VrBrowsingExperimentalFeatures:disabled"/>
   <int value="-170986053" label="EnableManualFallbacksFilling:enabled"/>
@@ -17274,6 +17280,7 @@
   <int value="1115564918" label="LacrosWaylandLogging:enabled"/>
   <int value="1115635149" label="EnableUnifiedMultiDeviceSetup:enabled"/>
   <int value="1115732111" label="OmniboxCalcProvider:enabled"/>
+  <int value="1116018547" label="ThreeButtonPasswordSaveDialog:disabled"/>
   <int value="1116084116" label="BindingManagerConnectionLimit:enabled"/>
   <int value="1116593018" label="CaptureThumbnailOnLoadFinished:disabled"/>
   <int value="1116798400" label="NoncedPartitionedCookies:enabled"/>
@@ -18783,10 +18790,12 @@
   <int value="1675848452" label="BluetoothQualityReport:disabled"/>
   <int value="1675857410" label="PrivateNetworkAccessNullIpAddress:enabled"/>
   <int value="1676345689" label="IsolatedWebAppAllowlist:disabled"/>
+  <int value="1676457528" label="AndroidProgressBarVisualUpdate:enabled"/>
   <int value="1677167062" label="AutomaticPasswordGeneration:enabled"/>
   <int value="1677258310" label="DragAppsInTabletMode:disabled"/>
   <int value="1677610330" label="OmniboxExpandedStateHeight:enabled"/>
   <int value="1678259296" label="ChromeWhatsNewInMainMenuNewBadge:enabled"/>
+  <int value="1678849864" label="ThreeButtonPasswordSaveDialog:enabled"/>
   <int value="1678866761" label="SystemLatinPhysicalTyping:disabled"/>
   <int value="1679347136" label="ExperimentalWebAppProfileIsolation:enabled"/>
   <int value="1679558835" label="ArcAvailableForChildAccount:enabled"/>
@@ -19273,6 +19282,7 @@
   <int value="1852099433" label="AndroidHub:enabled"/>
   <int value="1852285132"
       label="AutofillEnableRankingFormulaAddressProfiles:disabled"/>
+  <int value="1852331669" label="AndroidProgressBarVisualUpdate:disabled"/>
   <int value="1852630189" label="NTPBookmarkSuggestions:disabled"/>
   <int value="1854017276" label="NavigationPredictorRendererWarmup:disabled"/>
   <int value="1854048611" label="OmniboxSuggestionsRecyclerView:disabled"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index ccdea12f..5bfc066 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -5936,6 +5936,22 @@
   </token>
 </histogram>
 
+<histogram name="Android.WebView.CachedFlagMigration" enum="Boolean"
+    expires_after="2026-04-28">
+  <owner>alexmitra@chromium.org</owner>
+  <owner>bewise@chromium.org</owner>
+  <owner>colibie@google.com</owner>
+  <owner>src/android_webview/OWNERS</owner>
+  <summary>
+    Records when any experiment is being migrated from manual shared preferences
+    to the generic WebViewCachedFlags implementation. This is recorded once per
+    startup and records true for startups where a migration takes place and
+    false otherwise. We expect to use this metric to determine when to remove
+    the migration code (when no more or a negligble amount of experiments are
+    being migrated).
+  </summary>
+</histogram>
+
 <histogram name="Android.WebView.Callback.Counts" enum="WebViewCallbackType"
     expires_after="2025-09-14">
   <owner>ntfschr@chromium.org</owner>
@@ -7460,7 +7476,7 @@
 </histogram>
 
 <histogram name="Android.WebView.SetAcceptThirdPartyCookies"
-    enum="BooleanAccepted" expires_after="2025-06-13">
+    enum="BooleanAccepted" expires_after="2026-05-01">
   <owner>jdeabreu@chromium.org</owner>
   <owner>pbirk@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 65c9335..a5cf1a2 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -6517,9 +6517,9 @@
 
 <histogram
     name="Autofill.TouchToFill.CreditCard.AutofillUsedAfterTouchToFillDismissal"
-    enum="Boolean" expires_after="2025-05-19">
+    enum="Boolean" expires_after="2026-05-19">
   <owner>smcgruer@google.com</owner>
-  <owner>chrome-payments-team@google.com</owner>
+  <owner>chrome-payments-eng@google.com</owner>
   <summary>
     Records whether a user has still used autofill after dismissing the payments
     bottom sheet. There is a fallback to still allow the user to autofill the
@@ -6533,9 +6533,9 @@
 </histogram>
 
 <histogram name="Autofill.TouchToFill.CreditCard.FillingCorrectness"
-    enum="BooleanAutofillFillingCorrectness" expires_after="2025-05-19">
+    enum="BooleanAutofillFillingCorrectness" expires_after="2026-05-19">
   <owner>smcgruer@google.com</owner>
-  <owner>chrome-payments-team@google.com</owner>
+  <owner>chrome-payments-eng@google.com</owner>
   <summary>
     For the Payments bottom sheet (Touch To Fill for credit cards), tracks
     whether or not the user has edited at least one of the autofilled fields
@@ -6544,9 +6544,9 @@
 </histogram>
 
 <histogram name="Autofill.TouchToFill.CreditCard.NumberOfCardsShown"
-    units="cards" expires_after="2025-05-19">
+    units="cards" expires_after="2026-05-19">
   <owner>smcgruer@google.com</owner>
-  <owner>chrome-payments-team@google.com</owner>
+  <owner>chrome-payments-eng@google.com</owner>
   <summary>
     The number of credit cards shown in the Touch To Fill bottom sheet. Recorded
     when showing the bottom sheet.
@@ -6554,9 +6554,9 @@
 </histogram>
 
 <histogram name="Autofill.TouchToFill.CreditCard.Outcome2"
-    enum="TouchToFill.CreditCard.Outcome" expires_after="2025-05-19">
+    enum="TouchToFill.CreditCard.Outcome" expires_after="2026-05-19">
   <owner>smcgruer@google.com</owner>
-  <owner>chrome-payments-team@google.com</owner>
+  <owner>chrome-payments-eng@google.com</owner>
   <summary>
     Records the outcome with which the bottom sheet was closed: credit card
     selected, virtual card selected, go to payment settings, scan new credit
@@ -6571,9 +6571,9 @@
 </histogram>
 
 <histogram name="Autofill.TouchToFill.CreditCard.PerfectFilling" enum="Boolean"
-    expires_after="2025-05-19">
+    expires_after="2026-05-19">
   <owner>smcgruer@google.com</owner>
-  <owner>chrome-payments-team@google.com</owner>
+  <owner>chrome-payments-eng@google.com</owner>
   <summary>
     For the Payments bottom sheet (Touch To Fill for credit cards), logs at
     submission time if the filling experience was perfect or not. In a perfect
@@ -6583,9 +6583,9 @@
 </histogram>
 
 <histogram name="Autofill.TouchToFill.CreditCard.SelectedIndex" units="index"
-    expires_after="2025-09-28">
+    expires_after="2026-05-19">
   <owner>smcgruer@google.com</owner>
-  <owner>chrome-payments-team@google.com</owner>
+  <owner>chrome-payments-eng@google.com</owner>
   <summary>
     The index of the selected credit card in the Touch To Fill bottom sheet.
     Recorded when user selects a credit card from the list.
@@ -6593,9 +6593,9 @@
 </histogram>
 
 <histogram name="Autofill.TouchToFill.CreditCard.TriggerOutcome"
-    enum="TouchToFill.PaymentMethod.TriggerOutcome" expires_after="2025-05-19">
+    enum="TouchToFill.PaymentMethod.TriggerOutcome" expires_after="2026-05-19">
   <owner>smcgruer@google.com</owner>
-  <owner>chrome-payments-team@google.com</owner>
+  <owner>chrome-payments-eng@google.com</owner>
   <summary>
     Records the outcome of the attempt to trigger Touch To Fill for credit
     cards. It is recorded only when the touch to fill feature is enabled and the
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml
index 468f44d..02d3134e 100644
--- a/tools/metrics/histograms/metadata/blink/enums.xml
+++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -8196,6 +8196,7 @@
   <int value="331" label="TextUnderlineOffset"/>
   <int value="332" label="WindowManagement"/>
   <int value="333" label="Requestclose"/>
+  <int value="334" label="DRAFT_Uint8ArrayToFromBase64AndHex"/>
 </enum>
 
 <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom:WebDXFeature) -->
diff --git a/tools/metrics/histograms/metadata/compositing/enums.xml b/tools/metrics/histograms/metadata/compositing/enums.xml
index 62955760..d5f72927 100644
--- a/tools/metrics/histograms/metadata/compositing/enums.xml
+++ b/tools/metrics/histograms/metadata/compositing/enums.xml
@@ -196,6 +196,13 @@
   <int value="3" label="No, mask candidate rejected by DRM"/>
 </enum>
 
+<enum name="PropertyMutation">
+  <int value="0" label="Transform"/>
+  <int value="1" label="Opacity"/>
+  <int value="2" label="Filter"/>
+  <int value="3" label="Backdrop Filter"/>
+</enum>
+
 <enum name="RenderPassDamage">
   <int value="0" label="Output rect">
     Clipping at the root does not make the damage smaller than the output rect.
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index 08c7ea0a..7d52884 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -87,6 +87,16 @@
   <variant name="DrawAndSwap"/>
 </variants>
 
+<histogram name="Compositing.Animation.MissingPropertyNodeForElementId"
+    enum="PropertyMutation" expires_after="2026-01-31">
+  <owner>kevers@chromium.org</owner>
+  <owner>animations-dev@chromium.org</owner>
+  <summary>
+    Tally failures resulting from missing a map entry from element id to
+    property node.
+  </summary>
+</histogram>
+
 <histogram name="Compositing.Browser.LayersUpdateTime" units="microseconds"
     expires_after="2025-09-14">
   <owner>pdr@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/content/enums.xml b/tools/metrics/histograms/metadata/content/enums.xml
index 40eaf16..a908c6c 100644
--- a/tools/metrics/histograms/metadata/content/enums.xml
+++ b/tools/metrics/histograms/metadata/content/enums.xml
@@ -199,6 +199,10 @@
              account"/>
   <int value="28" label="Failed - account token fetch timed out"/>
   <int value="29" label="Failed - network fetch timed out"/>
+  <int value="30" label="Failed - loading not allowed due to being disabled"/>
+  <int value="31"
+      label="Failed - loading not allowed due to being disabled by DSE"/>
+  <int value="32" label="Failed - no card received"/>
 </enum>
 
 <enum name="FeedRefreshTrigger">
diff --git a/tools/metrics/histograms/metadata/glic/enums.xml b/tools/metrics/histograms/metadata/glic/enums.xml
index 5ce8fc4..24dacce0 100644
--- a/tools/metrics/histograms/metadata/glic/enums.xml
+++ b/tools/metrics/histograms/metadata/glic/enums.xml
@@ -37,6 +37,25 @@
 
 <!-- LINT.ThenChange(//chrome/browser/glic/host/glic.mojom:ActInFocusedTabErrorReason) -->
 
+<!-- LINT.IfChange(DeepScanAccessPoint) -->
+
+<enum name="DeepScanAccessPoint">
+<!-- These values are persisted to logs. Entries should not be renumbered and
+     numeric values should never be reused. Keep this in sync with
+     safe_browsing::DeepScanAccessPoint in
+     chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
+    -->
+
+  <int value="0" label="File Downloaded"/>
+  <int value="1" label="File Uploaded"/>
+  <int value="2" label="Drag and Drop"/>
+  <int value="3" label="Paste"/>
+  <int value="4" label="Print"/>
+  <int value="5" label="File Transfer"/>
+</enum>
+
+<!-- LINT.ThenChange(//chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h:DeepScanAccessPoint) -->
+
 <!-- LINT.IfChange(GlicAttachChangeReason) -->
 
 <enum name="GlicAttachChangeReason">
diff --git a/tools/metrics/histograms/metadata/glic/histograms.xml b/tools/metrics/histograms/metadata/glic/histograms.xml
index da64835..c465520 100644
--- a/tools/metrics/histograms/metadata/glic/histograms.xml
+++ b/tools/metrics/histograms/metadata/glic/histograms.xml
@@ -200,6 +200,20 @@
   </summary>
 </histogram>
 
+<histogram name="Glic.Modal.DeepScanAccessPoint" enum="DeepScanAccessPoint"
+    expires_after="2026-03-01">
+  <owner>birnie@google.com</owner>
+  <owner>dewittj@google.com</owner>
+  <summary>
+    Recorded each time a Glic modal is created as a result of an Enterprise
+    Connector deep scan trigger originating from
+    ContentAnalysisDelegate::CreateForWebContents. The specific access point
+    that triggered the scan is recorded. See the DeepScanAccessPoint enum in
+    glic/enums.xml for possible values, corresponding to
+    safe_browsing::DeepScanAccessPoint.
+  </summary>
+</histogram>
+
 <histogram name="Glic.OsEntrypoint.Settings.Shortcut" enum="BooleanEnabled"
     expires_after="2026-01-15">
   <owner>agale@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index a102b214..8a2ad52 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -4605,7 +4605,7 @@
 </histogram>
 
 <histogram name="IOS.SafeBrowsing.RedirectedRequestResponseHostsMatch"
-    enum="BooleanMatched" expires_after="2025-06-19">
+    enum="BooleanMatched" expires_after="2026-06-19">
   <owner>danieltwhite@google.com</owner>
   <owner>gambard@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/kiosk/histograms.xml b/tools/metrics/histograms/metadata/kiosk/histograms.xml
index 0d710d1..d1a6949 100644
--- a/tools/metrics/histograms/metadata/kiosk/histograms.xml
+++ b/tools/metrics/histograms/metadata/kiosk/histograms.xml
@@ -173,7 +173,7 @@
 </histogram>
 
 <histogram name="Kiosk.Extensions.InstallTimedOut" enum="BooleanYesNo"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>yixie@chromium.org</owner>
   <owner>chromeos-kiosk-eng@google.com</owner>
   <summary>
@@ -223,7 +223,7 @@
 </histogram>
 
 <histogram name="Kiosk.NewBrowserWindow" enum="KioskBrowserWindowType"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>pbond@chromium.org</owner>
   <owner>chromeos-kiosk-eng@google.com</owner>
   <summary>
@@ -234,7 +234,7 @@
   </summary>
 </histogram>
 
-<histogram name="Kiosk.RamUsagePercentage" units="%" expires_after="2025-06-15">
+<histogram name="Kiosk.RamUsagePercentage" units="%" expires_after="2026-05-10">
   <owner>vkovalova@chromium.org</owner>
   <owner>chromeos-kiosk-eng@google.com</owner>
   <summary>
@@ -285,7 +285,7 @@
 </histogram>
 
 <histogram name="Kiosk.Session.NetworkDrops" units="network drops"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>pbond@chromium.org</owner>
   <owner>chromeos-kiosk-eng@chromium.org</owner>
   <summary>
@@ -295,7 +295,7 @@
 </histogram>
 
 <histogram name="Kiosk.SessionDuration.Crashed" units="ms"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>pbond@chromium.org</owner>
   <owner>chromeos-kiosk-eng@chromium.org</owner>
   <summary>
@@ -312,7 +312,7 @@
 </histogram>
 
 <histogram name="Kiosk.SessionDuration.Normal" units="ms"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>pbond@chromium.org</owner>
   <owner>chromeos-kiosk-eng@chromium.org</owner>
   <summary>
@@ -324,7 +324,7 @@
 </histogram>
 
 <histogram name="Kiosk.SessionDurationInDays.Crashed" units="days"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>pbond@chromium.org</owner>
   <owner>chromeos-kiosk-eng@chromium.org</owner>
   <summary>
@@ -339,7 +339,7 @@
 </histogram>
 
 <histogram name="Kiosk.SessionDurationInDays.Normal" units="days"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>pbond@chromium.org</owner>
   <owner>chromeos-kiosk-eng@chromium.org</owner>
   <summary>
@@ -395,7 +395,7 @@
 </histogram>
 
 <histogram name="Kiosk.SwapUsagePercentage" units="%"
-    expires_after="2025-06-15">
+    expires_after="2026-05-10">
   <owner>vkovalova@chromium.org</owner>
   <owner>chromeos-kiosk-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 93265f6f..14ca9d9 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -168,6 +168,24 @@
   <variant name="SubresourceRedirectThrottle"/>
 </variants>
 
+<histogram name="Crypto.SecureEnclaveOperation.Mac.{Operation}.Error"
+    enum="ErrSecOSStatus" expires_after="2025-10-05">
+  <owner>seblalancette@chromium.org</owner>
+  <owner>nsatragno@chromium.org</owner>
+  <owner>src/crypto/OWNERS</owner>
+  <summary>
+    Collected on Mac when a {Operation} operation failed for a
+    SecureEnclave-protected ECDSA key. Represents the OSStatus code returned by
+    the API corresponding with that operation.
+  </summary>
+  <token key="Operation">
+    <variant name="MessageSigning" summary="signing"/>
+    <variant name="NewKeyCreation" summary="new key creation"/>
+    <variant name="WrappedKeyCreation" summary="wrapped key creation"/>
+    <variant name="WrappedKeyExport" summary="wrapped key export"/>
+  </token>
+</histogram>
+
 <histogram name="Crypto.TPMDuration.Virtual.{Operation}{SignatureAlgorithm}"
     units="ms" expires_after="2025-08-01">
   <owner>kristianm@chromium.org</owner>
@@ -297,6 +315,7 @@
   <token key="Operation">
     <variant name="MessageSigning" summary="signing"/>
     <variant name="NewKeyCreation" summary="new key creation"/>
+    <variant name="WrappedKeyCreation" summary="wrapped key creation"/>
     <variant name="WrappedKeyExport" summary="wrapped key export"/>
   </token>
   <token key="SignatureAlgorithm">
diff --git a/tools/metrics/histograms/metadata/password/enums.xml b/tools/metrics/histograms/metadata/password/enums.xml
index 79517f2..b15e0fc 100644
--- a/tools/metrics/histograms/metadata/password/enums.xml
+++ b/tools/metrics/histograms/metadata/password/enums.xml
@@ -1338,6 +1338,8 @@
       label="Not Syncing/Sync pasword saved. This value should not happen."/>
 </enum>
 
+<!-- LINT.IfChange(PasswordManagerUIDismissalReason) -->
+
 <enum name="PasswordManagerUIDismissalReason">
   <int value="0" label="Bubble lost focus / No infobar interaction"/>
   <int value="1" label="Clicked 'Save'/'Update'/'Move'/etc"/>
@@ -1360,8 +1362,11 @@
   <int value="15"
       label="Clicked 'About password change' link in the password change
              bubble."/>
+  <int value="16" label="Clicked 'Not now' in the save password bubble."/>
 </enum>
 
+<!-- LINT.ThenChange(/components/password_manager/core/browser/password_manager_metrics_util.h:UIDismissalReason) -->
+
 <enum name="PasswordNoteAction">
   <int value="0"
       label="A new credential is added from settings, with the note field not
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 5779ca5..984a5ea 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -2339,7 +2339,7 @@
   </summary>
 </histogram>
 
-<histogram name="Signin.Promo.{Action}.ImpressionsUntil.{AccessPoint}"
+<histogram name="Signin.Promo.ImpressionsUntil.{Action}.{AccessPoint}"
     units="impressions" expires_after="2026-04-18">
   <owner>myuu@google.com</owner>
   <owner>chrome-signin-mobile-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index 048c192..a9d3b5eb 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -1867,14 +1867,14 @@
   </summary>
 </histogram>
 
-<histogram name="Sync.SearchEngine.HasLocalDataDuringStopSyncing"
+<histogram name="Sync.SearchEngine.HasLocalDataDuringStopSyncing2"
     enum="Boolean" expires_after="2026-03-07">
   <owner>ankushkush@google.com</owner>
   <owner>mahmadi@chromium.org</owner>
   <summary>
     Recorded whenever search engines sync is being stopped, for example, upon
     signout. For each search engine with account data, records whether there
-    exists local data.
+    exists local data. Note that this is not recorded upon browser shutdown.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/toasts/enums.xml b/tools/metrics/histograms/metadata/toasts/enums.xml
index defa8bf..49c907b 100644
--- a/tools/metrics/histograms/metadata/toasts/enums.xml
+++ b/tools/metrics/histograms/metadata/toasts/enums.xml
@@ -71,6 +71,7 @@
   <int value="12" label="Tab removed from collaboration"/>
   <int value="13" label="User joined collaboration"/>
   <int value="14" label="Collaboration removed"/>
+  <int value="15" label="Video Frame Copied"/>
 </enum>
 
 <!-- LINT.ThenChange(/chrome/browser/ui/toasts/api/toast_id.h:ToastId) -->
diff --git a/tools/metrics/histograms/metadata/webauthn/enums.xml b/tools/metrics/histograms/metadata/webauthn/enums.xml
index 811a5a30..9acfa0e 100644
--- a/tools/metrics/histograms/metadata/webauthn/enums.xml
+++ b/tools/metrics/histograms/metadata/webauthn/enums.xml
@@ -289,6 +289,21 @@
   <int value="14" label="Other Failure"/>
 </enum>
 
+<!-- LINT.IfChange(WebAuthenticationIOSContentAreaEvent) -->
+
+<enum name="WebAuthenticationIOSContentAreaEvent">
+  <int value="0" label="GetRequested">
+    Page requested a WebAuthn credential using the navigator.credentials.get
+    API.
+  </int>
+  <int value="1" label="CreateRequested">
+    Page requested a new WebAuthn credential using the
+    navigator.credentials.create API.
+  </int>
+</enum>
+
+<!-- LINT.ThenChange(//components/webauthn/ios/passkey_java_script_feature.mm) -->
+
 <enum name="WebAuthenticationMacOSPasskeysPermission">
   <int value="0" label="Requested permission during a create() call"/>
   <int value="1" label="Permission approved during a create() call"/>
diff --git a/tools/metrics/histograms/metadata/webauthn/histograms.xml b/tools/metrics/histograms/metadata/webauthn/histograms.xml
index 1fe8d26..a220f982 100644
--- a/tools/metrics/histograms/metadata/webauthn/histograms.xml
+++ b/tools/metrics/histograms/metadata/webauthn/histograms.xml
@@ -402,6 +402,20 @@
   </summary>
 </histogram>
 
+<histogram name="WebAuthentication.IOS.ContentAreaEvent"
+    enum="WebAuthenticationIOSContentAreaEvent" expires_after="2025-11-01">
+  <owner>rgod@google.com</owner>
+  <owner>tmartino@chromium.org</owner>
+  <owner>bling-transactions@google.com</owner>
+  <summary>
+    Logs WebAuthn API interactions in the content area in Chrome on iOS, such as
+    a site requesting passkeys, or an assertion being returned by a CPE. Note
+    that this is *not* limited to passkeys stored in Chrome. Requests handled by
+    any (or no) credential provider are counted here, as well as requests for
+    other types of WebAuthn credentials (e.g. security key credentials).
+  </summary>
+</histogram>
+
 <histogram name="WebAuthentication.IsUVPlatformAuthenticatorAvailable2"
     enum="Boolean" expires_after="2025-10-12">
   <owner>kenrb@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 6c10f2b1..adcb37df 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v50.1/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "20d24483040173ee3f8de2b42f95ee1b1fe26466",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/fc9aac573945f2da6d05bf1904d500e6d5cdf18d/trace_processor_shell.exe"
+            "hash": "6cdfc3b341633fb60786e2a45516e59bb0f2ca8e",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/f4cde1b052fd591a5c50fe11dbcda61c51c4cccf/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v50.1/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "446daf64b1490672ebd7ca2f437b7c4b78fae3d4",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/fc9aac573945f2da6d05bf1904d500e6d5cdf18d/trace_processor_shell"
+            "hash": "f5ba58688594ec06f0c5bb6a99ad6758fff3e8b1",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/f4cde1b052fd591a5c50fe11dbcda61c51c4cccf/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/process_perf_results.pydeps b/tools/perf/process_perf_results.pydeps
index 21ce947..f38f8f5 100644
--- a/tools/perf/process_perf_results.pydeps
+++ b/tools/perf/process_perf_results.pydeps
@@ -112,7 +112,6 @@
 ../../third_party/catapult/devil/devil/utils/__init__.py
 ../../third_party/catapult/devil/devil/utils/cmd_helper.py
 ../../third_party/catapult/devil/devil/utils/geometry.py
-../../third_party/catapult/devil/devil/utils/host_utils.py
 ../../third_party/catapult/devil/devil/utils/lazy/__init__.py
 ../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py
 ../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java b/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java
index bbe6e0ee..0ff0b58 100644
--- a/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java
+++ b/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java
@@ -11,6 +11,7 @@
 import android.util.AttributeSet;
 
 import androidx.appcompat.widget.AppCompatTextView;
+import androidx.core.view.ViewCompat;
 
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
@@ -124,7 +125,8 @@
     }
 
     private void announceForAccessibilityOnToggleTruncation(boolean isUrlTruncated) {
-        announceForAccessibility(
+        ViewCompat.setAccessibilityPaneTitle(
+                this,
                 getResources()
                         .getString(
                                 isUrlTruncated
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java
index 2c128f2..61dfa11 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java
@@ -54,15 +54,13 @@
     @IntDef({
         ModalDialogProperties.ButtonType.POSITIVE,
         ModalDialogProperties.ButtonType.NEGATIVE,
-        ModalDialogProperties.ButtonType.TITLE_ICON,
         ButtonType.POSITIVE_EPHEMERAL
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ButtonType {
         int POSITIVE = 0;
         int NEGATIVE = 1;
-        int TITLE_ICON = 2;
-        int POSITIVE_EPHEMERAL = 3;
+        int POSITIVE_EPHEMERAL = 2;
     }
 
     /**
diff --git a/ui/base/cocoa/touch_bar_util_unittest.mm b/ui/base/cocoa/touch_bar_util_unittest.mm
index 5a1e928..39f2eba1 100644
--- a/ui/base/cocoa/touch_bar_util_unittest.mm
+++ b/ui/base/cocoa/touch_bar_util_unittest.mm
@@ -11,7 +11,7 @@
 
 namespace {
 
-const char kTestChromeBundleId[] = "test.bundleid";
+constexpr char kTestChromeBundleId[] = "test.bundleid";
 
 NSString* const kTestTouchBarId = @"test-touch-bar";
 
@@ -21,11 +21,11 @@
 
 class TouchBarUtilTest : public ui::CocoaTest {
  public:
-  TouchBarUtilTest() {}
+  TouchBarUtilTest() = default;
 };
 
 TEST_F(TouchBarUtilTest, TouchBarIdentifiers) {
-  base::apple::SetBaseBundleID(kTestChromeBundleId);
+  base::apple::SetBaseBundleIDOverride(kTestChromeBundleId);
   EXPECT_TRUE([ui::GetTouchBarId(kTestTouchBarId)
       isEqualToString:@"test.bundleid.test-touch-bar"]);
   EXPECT_TRUE([ui::GetTouchBarItemId(kTestTouchBarId, kTestTouchBarItemId)
diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn
index e598004..491b8006 100644
--- a/ui/display/BUILD.gn
+++ b/ui/display/BUILD.gn
@@ -69,6 +69,8 @@
       "mac/display_link_mac.h",
       "mac/display_link_mac.mm",
       "mac/screen_mac.mm",
+      "mac/screen_mac_headless.h",
+      "mac/screen_mac_headless.mm",
     ]
   }
 
@@ -147,6 +149,7 @@
   }
 
   if (is_mac) {
+    deps += [ "//components/headless/screen_info" ]
     frameworks = [
       "AppKit.framework",
       "CoreGraphics.framework",
diff --git a/ui/display/mac/DEPS b/ui/display/mac/DEPS
new file mode 100644
index 0000000..4a3d7376
--- /dev/null
+++ b/ui/display/mac/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "screen_mac_headless\.mm": [
+    "+components/headless/screen_info",
+  ],
+}
diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm
index 874ac9d..033ebc00 100644
--- a/ui/display/mac/screen_mac.mm
+++ b/ui/display/mac/screen_mac.mm
@@ -21,6 +21,8 @@
 #include "base/apple/bridging.h"
 #include "base/apple/foundation_util.h"
 #include "base/apple/scoped_cftyperef.h"
+#include "base/check_deref.h"
+#include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
@@ -32,11 +34,13 @@
 #include "components/device_event_log/device_event_log.h"
 #include "ui/display/display.h"
 #include "ui/display/display_change_notifier.h"
+#include "ui/display/mac/screen_mac_headless.h"
 #include "ui/display/util/display_util.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/icc_profile.h"
 #include "ui/gfx/mac/coordinate_conversion.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/switches.h"
 
 extern "C" {
 Boolean CGDisplayUsesForceToGray(void);
@@ -611,6 +615,13 @@
 }
 
 Screen* CreateNativeScreen() {
+  const base::CommandLine& command_line =
+      CHECK_DEREF(base::CommandLine::ForCurrentProcess());
+
+  if (command_line.HasSwitch(switches::kHeadless)) {
+    return new ScreenMacHeadless;
+  }
+
   return new ScreenMac;
 }
 
diff --git a/ui/display/mac/screen_mac_headless.h b/ui/display/mac/screen_mac_headless.h
new file mode 100644
index 0000000..708cd0b8
--- /dev/null
+++ b/ui/display/mac/screen_mac_headless.h
@@ -0,0 +1,40 @@
+// Copyright 2025 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_DISPLAY_MAC_SCREEN_MAC_HEADLESS_H_
+#define UI_DISPLAY_MAC_SCREEN_MAC_HEADLESS_H_
+
+#include "ui/display/display.h"
+#include "ui/display/screen_base.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace display {
+
+class ScreenMacHeadless : public ScreenBase {
+ public:
+  ScreenMacHeadless();
+
+  ScreenMacHeadless(const ScreenMacHeadless&) = delete;
+  ScreenMacHeadless& operator=(const ScreenMacHeadless&) = delete;
+
+  ~ScreenMacHeadless() override;
+
+  // display::Screen overrides:
+  gfx::Point GetCursorScreenPoint() override;
+  bool IsWindowUnderCursor(gfx::NativeWindow window) override;
+  gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override;
+  gfx::NativeWindow GetLocalProcessWindowAtPoint(
+      const gfx::Point& point,
+      const std::set<gfx::NativeWindow>& ignore) override;
+  Display GetDisplayNearestWindow(gfx::NativeWindow window) const override;
+  bool IsHeadless() const override;
+
+ private:
+  void CreateDisplayList();
+};
+
+}  // namespace display
+
+#endif  // UI_DISPLAY_MAC_SCREEN_MAC_HEADLESS_H_
diff --git a/ui/display/mac/screen_mac_headless.mm b/ui/display/mac/screen_mac_headless.mm
new file mode 100644
index 0000000..2ae6774
--- /dev/null
+++ b/ui/display/mac/screen_mac_headless.mm
@@ -0,0 +1,125 @@
+// Copyright 2025 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/display/mac/screen_mac_headless.h"
+
+#import <AppKit/AppKit.h>
+
+#include <vector>
+
+#include "base/check_deref.h"
+#include "base/command_line.h"
+#include "base/containers/flat_set.h"
+#include "base/types/expected.h"
+#include "components/headless/screen_info/headless_screen_info.h"
+#include "ui/display/util/display_util.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/mac/coordinate_conversion.h"
+#include "ui/gfx/switches.h"
+
+namespace display {
+
+namespace {
+
+// Headless display ids are synthesized sequential numbers.
+constexpr int64_t kHeadlessDisplayIdBase = 1;
+
+std::vector<headless::HeadlessScreenInfo> GetHeadlessScreenInfos() {
+  std::vector<headless::HeadlessScreenInfo> screen_infos;
+
+  const base::CommandLine& command_line =
+      CHECK_DEREF(base::CommandLine::ForCurrentProcess());
+
+  if (command_line.HasSwitch(switches::kScreenInfo)) {
+    const std::string switch_value =
+        command_line.GetSwitchValueASCII(switches::kScreenInfo);
+    base::expected<std::vector<headless::HeadlessScreenInfo>, std::string>
+        screen_infos_or_error =
+            headless::HeadlessScreenInfo::FromString(switch_value);
+    CHECK(screen_infos_or_error.has_value()) << screen_infos_or_error.error();
+    screen_infos = screen_infos_or_error.value();
+  } else {
+    screen_infos.push_back(headless::HeadlessScreenInfo());
+  }
+
+  return screen_infos;
+}
+
+}  // namespace
+
+ScreenMacHeadless::ScreenMacHeadless() {
+  CreateDisplayList();
+}
+
+ScreenMacHeadless::~ScreenMacHeadless() = default;
+
+void ScreenMacHeadless::CreateDisplayList() {
+  std::vector<headless::HeadlessScreenInfo> screen_infos =
+      GetHeadlessScreenInfos();
+  CHECK(!screen_infos.empty());
+
+  bool is_primary = true;
+  base::flat_set<int64_t> internal_display_ids;
+  for (const headless::HeadlessScreenInfo& it : screen_infos) {
+    static int64_t synthesized_display_id = kHeadlessDisplayIdBase;
+    Display display(synthesized_display_id++);
+    display.set_label(it.label);
+    display.set_color_depth(it.color_depth);
+    display.SetScaleAndBounds(it.device_pixel_ratio, it.bounds);
+
+    if (!it.work_area_insets.IsEmpty()) {
+      display.UpdateWorkAreaFromInsets(it.work_area_insets);
+    }
+
+    if (it.rotation) {
+      CHECK(Display::IsValidRotation(it.rotation));
+      display.SetRotationAsDegree(it.rotation);
+    }
+
+    if (it.is_internal) {
+      internal_display_ids.insert(display.id());
+    }
+
+    ProcessDisplayChanged(display, is_primary);
+    is_primary = false;
+  }
+
+  SetInternalDisplayIds(internal_display_ids);
+}
+
+gfx::Point ScreenMacHeadless::GetCursorScreenPoint() {
+  return gfx::Point();
+}
+
+bool ScreenMacHeadless::IsWindowUnderCursor(gfx::NativeWindow window) {
+  return GetWindowAtScreenPoint(GetCursorScreenPoint()) == window;
+}
+
+gfx::NativeWindow ScreenMacHeadless::GetWindowAtScreenPoint(
+    const gfx::Point& point) {
+  return gfx::NativeWindow();
+}
+
+gfx::NativeWindow ScreenMacHeadless::GetLocalProcessWindowAtPoint(
+    const gfx::Point& point,
+    const std::set<gfx::NativeWindow>& ignore) {
+  return gfx::NativeWindow();
+}
+
+Display ScreenMacHeadless::GetDisplayNearestWindow(
+    gfx::NativeWindow window) const {
+  if (window && GetNumDisplays() > 1) {
+    if (NSWindow* ns_window = window.GetNativeNSWindow()) {
+      const gfx::Rect bounds = gfx::ScreenRectFromNSRect([ns_window frame]);
+      return GetDisplayMatching(bounds);
+    }
+  }
+  return GetPrimaryDisplay();
+}
+
+bool ScreenMacHeadless::IsHeadless() const {
+  return true;
+}
+
+}  // namespace display
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index c8f01a8..af66f53 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -462,6 +462,8 @@
     "display_color_spaces.h",
     "hdr_metadata.cc",
     "hdr_metadata.h",
+    "hdr_metadata_agtm.cc",
+    "hdr_metadata_agtm.h",
     "hdr_static_metadata.cc",
     "hdr_static_metadata.h",
     "icc_profile.cc",
@@ -478,6 +480,7 @@
   deps = [
     "//skia:skcms",
     "//ui/gfx:buffer_types",
+    "//ui/gfx:gfx_switches",
     "//ui/gfx/geometry:geometry_skia",
   ]
   public_deps = [
diff --git a/ui/gfx/hdr_metadata.cc b/ui/gfx/hdr_metadata.cc
index ea1da825..6733403e 100644
--- a/ui/gfx/hdr_metadata.cc
+++ b/ui/gfx/hdr_metadata.cc
@@ -7,21 +7,13 @@
 #include <iomanip>
 #include <sstream>
 
-#include "base/feature_list.h"
 #include "skia/ext/skcolorspace_primaries.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
 #include "third_party/skia/include/core/SkData.h"
+#include "ui/gfx/switches.h"
 
 namespace gfx {
 
-namespace {
-
-BASE_FEATURE(kAgtmToneMapping,
-             "AgtmToneMapping",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-}
-
 std::string HdrMetadataCta861_3::ToString() const {
   std::stringstream ss;
   ss << std::fixed << std::setprecision(4)
@@ -76,7 +68,7 @@
 
 // static
 bool HdrMetadataAgtm::IsEnabled() {
-  static bool result = base::FeatureList::IsEnabled(kAgtmToneMapping);
+  static bool result = base::FeatureList::IsEnabled(features::kHdrAgtm);
   return result;
 }
 
diff --git a/ui/gfx/hdr_metadata_agtm.cc b/ui/gfx/hdr_metadata_agtm.cc
new file mode 100644
index 0000000..978a4af
--- /dev/null
+++ b/ui/gfx/hdr_metadata_agtm.cc
@@ -0,0 +1,336 @@
+// Copyright 2025 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/hdr_metadata_agtm.h"
+
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkData.h"
+#include "ui/gfx/hdr_metadata.h"
+
+namespace gfx {
+
+namespace {
+
+bool ReadFloat(const base::DictValue* dict, const char* key, float& value) {
+  if (!dict) {
+    return false;
+  }
+  if (auto v = dict->FindDouble(key)) {
+    value = v.value();
+    return true;
+  }
+  return false;
+}
+
+// Read a piecewise cubic into a sampled SkImage
+bool ReadPiecewiseCubic(const base::DictValue* dict, sk_sp<SkImage>& curve) {
+  if (!dict) {
+    DVLOG(1) << "Piecewise cubic is missing";
+    return false;
+  }
+  // The parameters for the piecewise cubic segment.
+  float m_min = 0.f, m_span = 0.f;
+  float x0 = -1.f, y0 = 0.f, m0 = 0.f;
+  float x1 = -1.f, y1 = 0.f, m1 = 0.f;
+
+  // The output SkBitmap.
+  const size_t kSamples = 1024;
+  SkBitmap bm;
+  if (!bm.tryAllocPixels(SkImageInfo::Make(kSamples, 1, kA16_unorm_SkColorType,
+                                           kUnpremul_SkAlphaType))) {
+    DVLOG(1) << "Failed to allocate pixels for gain curve";
+    return false;
+  }
+
+  // The sample x value that is being written into `bm`.
+  size_t xi = 0;
+
+  // Function to evalue the current piecewise cubic segment.
+  auto eval_piecewise_cubic = [&](float x) {
+    // If x0 >= x1, then hold the y0 value. This can happen for repeated control
+    // points, or initializing values beyond the control points.
+    if (x0 >= x1) {
+      return y0;
+    }
+    const float m0p = (m_min + m_span * m0) * (x1 - x0);
+    const float m1p = (m_min + m_span * m1) * (x1 - x0);
+    const float c3 = (2.0 * y0 + m0p - 2.0 * y1 + m1p);
+    const float c2 = (-3.0 * y0 + 3.0 * y1 - 2.0 * m0p - m1p);
+    const float c1 = m0p;
+    const float c0 = y0;
+    const float t = (x - x0) / (x1 - x0);
+    return c0 + t * (c1 + t * (c2 + t * c3));
+  };
+
+  // Function to increment `xi` until it is past `x1`, writing values into `bm`
+  // along the way.
+  auto write_samples_through_x1 = [&]() {
+    while (xi < kSamples && xi / (kSamples - 1.f) < x1) {
+      const float y = eval_piecewise_cubic(xi / (kSamples - 1.f));
+      *bm.pixmap().writable_addr16(xi, 0) =
+          std::round(65535.f * std::clamp(y, 0.f, 1.f));
+      xi += 1;
+    }
+  };
+
+  // Read the parameters and control points, writing to `bm` along the way.
+  if (!ReadFloat(dict, "m_min", m_min) && !ReadFloat(dict, "m_span", m_span)) {
+    DVLOG(1) << "Missing slope minimum or span";
+    return false;
+  }
+  const auto* cp_list = dict->FindList("control_points");
+  if (!cp_list || cp_list->size() < 1 || cp_list->size() > 64) {
+    DVLOG(1) << "Control point list missing or incorrect size";
+    return false;
+  }
+  bool is_first_control_point = true;
+  for (const auto& control_point : *cp_list) {
+    x0 = x1;
+    y0 = y1;
+    m0 = m1;
+    const auto* control_point_dict = control_point.GetIfDict();
+    if (!ReadFloat(control_point_dict, "x", x1) ||
+        !ReadFloat(control_point_dict, "y", y1) ||
+        !ReadFloat(control_point_dict, "m", m1)) {
+      DVLOG(1) << "Control point missing x, y, or m value";
+      return false;
+    }
+    // Repeat the first control point, so that the piecewise cubic segment
+    // function will evaluate to a constant.
+    if (is_first_control_point) {
+      is_first_control_point = false;
+      x0 = x1;
+      y0 = y1;
+      m0 = m1;
+    }
+    // Samples must be sorted in increasing order.
+    if (x0 > x1) {
+      DVLOG(1) << "Sample x values not sorted";
+      return false;
+    }
+    // The function must have C0 continuity.
+    if (x0 == x1 && y0 != y1) {
+      DVLOG(1) << "Function not continuous";
+      return false;
+    }
+    // Write and increment xi until we need to read past x1.
+    write_samples_through_x1();
+  }
+
+  // Write all samples past the last control point. Repeat the last control
+  // point, so that the piecewise cubic segment function will evaluate to a
+  // constant.
+  x0 = x1;
+  y0 = y1;
+  m0 = m1;
+  write_samples_through_x1();
+
+  curve = SkImages::RasterFromPixmapCopy(bm.pixmap());
+  return true;
+}
+
+bool ReadAgtmAlternate(const base::DictValue* dict,
+                       HdrMetadataAgtmParsed::Alternate& altr) {
+  if (!ReadFloat(dict, "hdr_headroom", altr.hdr_headroom)) {
+    DVLOG(1) << "Alternate representation missing HDR headroom";
+    return false;
+  }
+  if (const auto* v = dict->FindDict("component_mix_params")) {
+    if (!ReadFloat(v, "red", altr.mix_rgbx[0]) &&
+        !ReadFloat(v, "green", altr.mix_rgbx[1]) &&
+        !ReadFloat(v, "blue", altr.mix_rgbx[2]) &&
+        !ReadFloat(v, "max", altr.mix_Mmcx[0]) &&
+        !ReadFloat(v, "min", altr.mix_Mmcx[1]) &&
+        !ReadFloat(v, "component", altr.mix_Mmcx[2])) {
+      DVLOG(1) << "Alternate missing component mix params";
+      return false;
+    }
+  } else {
+    DVLOG(1) << "Alternate missing component mix dictionary";
+    return false;
+  }
+  if (!ReadPiecewiseCubic(dict->FindDict("piecewise_cubic"), altr.curve)) {
+    DVLOG(1) << "Failed to piecewise cubic";
+    return false;
+  }
+  return true;
+}
+
+bool ReadAgtmRoot(const base::Value& value, HdrMetadataAgtmParsed& params) {
+  const auto* dict = value.GetIfDict();
+  if (!dict) {
+    DVLOG(1) << "Agtm root is not dictionary";
+    return false;
+  }
+  if (!ReadFloat(dict, "hdr_reference_white", params.hdr_reference_white) ||
+      !ReadFloat(dict, "baseline_hdr_headroom", params.baseline_hdr_headroom) ||
+      !ReadFloat(dict, "baseline_max_component",
+                 params.baseline_max_component) ||
+      !ReadFloat(dict, "gain_min", params.gain_min) ||
+      !ReadFloat(dict, "gain_span", params.gain_span) ||
+      !ReadFloat(dict, "gain_application_offset",
+                 params.gain_application_offset)) {
+    DVLOG(1) << "Required values are absent";
+    return false;
+  }
+  if (auto v = dict->FindInt("gain_application_space_primaries")) {
+    params.gain_application_color_space =
+        SkColorSpace::MakeCICP(static_cast<SkNamedPrimaries::CicpId>(v.value()),
+                               SkNamedTransferFn::CicpId::kLinear);
+  }
+  if (!params.gain_application_color_space) {
+    DVLOG(1) << "Invalid or absent gain application space primaries";
+    return false;
+  }
+  const auto* altr_list = dict->FindList("alternates");
+  if (altr_list) {
+    if (altr_list->size() > 4) {
+      DVLOG(1) << "Too many alternates";
+      return false;
+    }
+    for (const auto& altr_value : *altr_list) {
+      HdrMetadataAgtmParsed::Alternate altr;
+      if (!ReadAgtmAlternate(altr_value.GetIfDict(), altr)) {
+        DVLOG(1) << "Failed to read alternate parameters";
+        return false;
+      }
+      params.alternates.push_back(altr);
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+HdrMetadataAgtmParsed::HdrMetadataAgtmParsed() = default;
+HdrMetadataAgtmParsed::~HdrMetadataAgtmParsed() = default;
+
+bool HdrMetadataAgtmParsed::Parse(const HdrMetadataAgtm& agtm) {
+  if (!HdrMetadataAgtm::IsEnabled()) {
+    return false;
+  }
+  if (!agtm.payload) {
+    DVLOG(1) << "Empty AGTM payload";
+    return false;
+  }
+  auto value = base::JSONReader::Read(
+      std::string_view(reinterpret_cast<const char*>(agtm.payload->data()),
+                       agtm.payload->size()));
+  if (!value) {
+    DVLOG(1) << "Failed to parse AGTM metadata JSON";
+    return false;
+  }
+  if (!ReadAgtmRoot(value.value(), *this)) {
+    return false;
+  }
+  return true;
+}
+
+void HdrMetadataAgtmParsed::ComputeAlternateWeights(float H_target,
+                                                    size_t& i,
+                                                    float& w_i,
+                                                    size_t& j,
+                                                    float& w_j) const {
+  const float H_base = baseline_hdr_headroom;
+
+  // Let H_i and H_j be the HDR headrooms of the ith and jth representation.
+  // Set them to the same value to indicate that the ith representation should
+  // be used in full.
+  i = j = kBaselineIndex;
+  float H_i = H_base;
+  float H_j = H_base;
+
+  // Special-case the absence of any alternate representations.
+  if (alternates.empty()) {
+    w_i = w_j = 0.f;
+    return;
+  }
+
+  for (i = 0; i < alternates.size(); ++i) {
+    j = kBaselineIndex;
+    H_i = alternates[i].hdr_headroom;
+    H_j = H_base;
+
+    // Mix of i = 0 and potentially baseline
+    if (H_target <= H_i) {
+      DCHECK_EQ(i, 0u);
+      j = kBaselineIndex;
+      if (H_base <= H_i) {
+        H_j = H_base;
+      } else {
+        H_j = H_i;
+      }
+      break;
+    }
+
+    // Mix of i = N-1 and potentially baseline.
+    if (i == alternates.size() - 1) {
+      DCHECK_GT(H_target, H_i);
+      j = kBaselineIndex;
+      if (H_base >= H_i) {
+        H_j = H_base;
+      } else {
+        H_j = H_i;
+      }
+      break;
+    }
+
+    // Consider the interval between alternate representations i and i+1 only if
+    // H_target is in that interval.
+    j = i + 1;
+    H_j = alternates[j].hdr_headroom;
+    if (H_i <= H_target && H_target <= H_j) {
+      // If it's the case that i < target < base < i+1, then we will only mix
+      // i and base.
+      if (H_i <= H_target && H_target <= H_base && H_base <= H_j) {
+        j = kBaselineIndex;
+        H_j = H_base;
+      }
+
+      // If it's the case that i < base < target < i+1, then we will only mix
+      // i+1 and base.
+      if (H_i <= H_base && H_base <= H_target && H_target <= H_j) {
+        i = j;
+        H_i = H_j;
+        j = kBaselineIndex;
+        H_j = H_base;
+        break;
+      }
+
+      // Otherwise, it's the case that i < target < i+1 and base isn't in that
+      // interval.
+      DCHECK(H_i <= H_target && H_target <= H_j);
+      break;
+    }
+  }
+
+  // Compute the weights for the two representations.
+  if (H_j == H_i) {
+    w_i = 1.f;
+  } else {
+    w_i = std::min(std::max((H_target - H_j) / (H_i - H_j), 0.f), 1.f);
+  }
+  w_j = 1.f - w_i;
+
+  // Zero out baseline weights.
+  if (i == kBaselineIndex) {
+    w_i = 0.f;
+  }
+  if (j == kBaselineIndex) {
+    w_j = 0.f;
+  }
+}
+
+HdrMetadataAgtmParsed::Alternate::Alternate() = default;
+HdrMetadataAgtmParsed::Alternate::Alternate(const Alternate&) = default;
+HdrMetadataAgtmParsed::Alternate::Alternate(Alternate&&) = default;
+HdrMetadataAgtmParsed::Alternate& HdrMetadataAgtmParsed::Alternate::operator=(
+    const Alternate&) = default;
+HdrMetadataAgtmParsed::Alternate& HdrMetadataAgtmParsed::Alternate::operator=(
+    Alternate&&) = default;
+HdrMetadataAgtmParsed::Alternate::~Alternate() = default;
+
+}  // namespace gfx
diff --git a/ui/gfx/hdr_metadata_agtm.h b/ui/gfx/hdr_metadata_agtm.h
new file mode 100644
index 0000000..b6f217a
--- /dev/null
+++ b/ui/gfx/hdr_metadata_agtm.h
@@ -0,0 +1,78 @@
+// Copyright 2025 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_HDR_METADATA_AGTM_H_
+#define UI_GFX_HDR_METADATA_AGTM_H_
+
+#include <vector>
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "ui/gfx/color_space_export.h"
+
+namespace gfx {
+
+struct HdrMetadataAgtm;
+
+struct COLOR_SPACE_EXPORT HdrMetadataAgtmParsed {
+  HdrMetadataAgtmParsed();
+  HdrMetadataAgtmParsed(const HdrMetadataAgtmParsed&) = delete;
+  HdrMetadataAgtmParsed& operator=(const HdrMetadataAgtmParsed&) = delete;
+  ~HdrMetadataAgtmParsed();
+
+  bool Parse(const HdrMetadataAgtm& agtm);
+
+  // Compute the alternate indices and their weights for tone mapping targeting
+  // H_target. If w_i==0, then i may be kBaselineIndex, indicating that it does
+  // not refer to a valid alternate representation. Likewise for w_j. If i is
+  // kBaselineIndex then j is also kBaselineIndex.
+  static constexpr size_t kBaselineIndex = -1;
+  void ComputeAlternateWeights(float H_target,
+                               size_t& i,
+                               float& w_i,
+                               size_t& j,
+                               float& w_j) const;
+
+  // Luminance of HDR reference white in nits.
+  float hdr_reference_white = 0.f;
+
+  // Baseline representation HDR headroom.
+  float baseline_hdr_headroom = 0.f;
+
+  // The maximum component of the baseline image in the gain application space,
+  // used to convert from gain application space to [0,1] for evaluation.
+  float baseline_max_component = 0.f;
+
+  // Gain parameters to convert from [0,1] to real values.
+  float gain_min = 0.f;
+  float gain_span = 0.f;
+
+  // Gain application parameters.
+  float gain_application_offset = 0.f;
+  sk_sp<SkColorSpace> gain_application_color_space;
+
+  // Alternate representations' headrooms and gain curves.
+  struct Alternate {
+    Alternate();
+    Alternate(const Alternate&);
+    Alternate(Alternate&&);
+    Alternate& operator=(const Alternate&);
+    Alternate& operator=(Alternate&&);
+    ~Alternate();
+
+    // HDR headroom for the alternate representation.
+    float hdr_headroom;
+
+    // Component mixing function and gain curve parameters.
+    SkColor4f mix_rgbx{0.f, 0.f, 0.f, 0.f};
+    SkColor4f mix_Mmcx{1.f, 0.f, 0.f, 0.f};
+    sk_sp<SkImage> curve;
+  };
+  std::vector<Alternate> alternates;
+};
+
+}  // namespace gfx
+
+#endif  // UI_GFX_HDR_METADATA_AGTM_H_
diff --git a/ui/gfx/switches.cc b/ui/gfx/switches.cc
index bf292a3..d3ca7f6b 100644
--- a/ui/gfx/switches.cc
+++ b/ui/gfx/switches.cc
@@ -68,4 +68,7 @@
 BASE_FEATURE(kUseSmartRefForGPUFenceHandle,
              "UseSmartRefForGPUFenceHandle",
              base::FEATURE_ENABLED_BY_DEFAULT);
+
+BASE_FEATURE(kHdrAgtm, "HdrAgtm", base::FEATURE_DISABLED_BY_DEFAULT);
+
 }  // namespace features
diff --git a/ui/gfx/switches.h b/ui/gfx/switches.h
index 0c61de2..1e30496 100644
--- a/ui/gfx/switches.h
+++ b/ui/gfx/switches.h
@@ -32,6 +32,8 @@
 GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kOddWidthMultiPlanarBuffers);
 GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kUseSmartRefForGPUFenceHandle);
 
+GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kHdrAgtm);
+
 }  // namespace features
 
 #endif  // UI_GFX_SWITCHES_H_
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
index 9d1b31c6..39faa30 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -397,6 +397,21 @@
       this};
 };
 
+class BubbleDialogDelegate::ThemeObserver : public ViewObserver {
+ public:
+  explicit ThemeObserver(BubbleDialogDelegate* delegate) : delegate_(delegate) {
+    observation_.Observe(delegate->GetContentsView());
+  }
+
+  void OnViewThemeChanged(views::View* view) override {
+    delegate_->UpdateColorsFromTheme();
+  }
+
+ private:
+  const raw_ptr<BubbleDialogDelegate> delegate_;
+  base::ScopedObservation<View, ViewObserver> observation_{this};
+};
+
 class BubbleDialogDelegateView::CloseOnDeactivatePin::Pins {
  public:
   Pins() = default;
@@ -460,8 +475,11 @@
 
   RegisterWidgetInitializedCallback(base::BindOnce(
       [](BubbleDialogDelegate* bubble_delegate) {
-        // Update the frame colors, once the frame is initialized.
-        bubble_delegate->UpdateFrameColors();
+        bubble_delegate->theme_observer_ =
+            std::make_unique<ThemeObserver>(bubble_delegate);
+        // Call the theme callback to make sure the initial theme is picked up
+        // by the BubbleDialogDelegate.
+        bubble_delegate->UpdateColorsFromTheme();
       },
       this));
 
@@ -1115,15 +1133,15 @@
   }
 }
 
-void BubbleDialogDelegate::UpdateFrameColors() {
+void BubbleDialogDelegate::UpdateColorsFromTheme() {
+  View* const contents_view = GetContentsView();
+  DCHECK(contents_view);
+
   BubbleFrameView* frame_view = GetBubbleFrameView();
   if (frame_view) {
     frame_view->SetBackgroundColor(background_color());
   }
 
-  View* const contents_view = GetContentsView();
-  CHECK(contents_view);
-
   // When there's an opaque layer, the bubble border background won't show
   // through, so explicitly paint a background color.
   const bool contents_layer_opaque =
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h
index bcb5ea6..19ac071 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -578,6 +578,7 @@
   class AnchorViewObserver;
   class AnchorWidgetObserver;
   class BubbleWidgetObserver;
+  class ThemeObserver;
 
   FRIEND_TEST_ALL_PREFIXES(BubbleDialogDelegateViewTest,
                            VisibleWidgetShowsInkDropOnAttaching);
@@ -592,6 +593,7 @@
   friend class AnchorWidgetObserver;
   friend class BubbleWidgetObserver;
   friend class TestBubbleUmaLogger;
+  friend class ThemeObserver;
 
   friend class BubbleBorderDelegate;
   friend class BubbleWindowTargeter;
@@ -609,7 +611,9 @@
   void OnBubbleWidgetPaintAsActiveChanged();
 
   void OnDeactivate();
-  void UpdateFrameColors();
+
+  // Update the bubble color from the NativeTheme unless it was explicitly set.
+  void UpdateColorsFromTheme();
 
   // Notify this bubble that it is now the primary anchored bubble. When a new
   // bubble becomes the primary anchor, the previous primary silently loses its
@@ -632,6 +636,7 @@
   std::unique_ptr<AnchorViewObserver> anchor_view_observer_;
   std::unique_ptr<AnchorWidgetObserver> anchor_widget_observer_;
   std::unique_ptr<BubbleWidgetObserver> bubble_widget_observer_;
+  std::unique_ptr<ThemeObserver> theme_observer_;
   bool adjust_if_offscreen_ = true;
   bool focus_traversable_from_anchor_view_ = true;
   ViewTracker highlighted_button_tracker_;
@@ -674,7 +679,7 @@
   bool paint_client_to_layer_ = false;
 
   // If true, contents view will be forced to create a solid color background in
-  // `UpdateFrameColors()`.
+  // UpdateColorsFromTheme().
   bool force_create_contents_background_ = false;
 
 #if BUILDFLAG(IS_MAC)
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc
index 250e7f5..42e0654 100644
--- a/ui/views/controls/webview/web_dialog_view.cc
+++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -486,6 +486,7 @@
 }
 
 bool WebDialogView::IsWebContentsCreationOverridden(
+    content::RenderFrameHost* opener,
     content::SiteInstance* source_site_instance,
     content::mojom::WindowContainerType window_container_type,
     const GURL& opener_url,
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h
index c96aeb2..0fa7e80 100644
--- a/ui/views/controls/webview/web_dialog_view.h
+++ b/ui/views/controls/webview/web_dialog_view.h
@@ -164,6 +164,7 @@
                          bool proceed,
                          bool* proceed_to_fire_unload) override;
   bool IsWebContentsCreationOverridden(
+      content::RenderFrameHost* opener,
       content::SiteInstance* source_site_instance,
       content::mojom::WindowContainerType window_container_type,
       const GURL& opener_url,
diff --git a/v8 b/v8
index b7e5533..8b2e5e5 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit b7e55339f42eb610415fae3fb16b5a56b3304ffb
+Subproject commit 8b2e5e57af618aadee7b3b9f967348c87da61591